5.2 C ++ SupportBecause SystemC is a class library implemented in C++, the advantages of high-level C++ constructs are available to hardware designers working in SystemC.. 5.2.1 Synthesi
Trang 15.2 C ++ Support
Because SystemC is a class library implemented in C++, the advantages of high-level C++ constructs are available to hardware designers working in SystemC Cynthesizer supports a large number of these constructs but, just as there are SystemVerilog constructs that are only intended for verification, there are C++ constructs that are only appropriate for modeling and testbench construction, not for synthesis
5.2.1 Synthesizable High-Level C ++ Constructs
The C++ constructs that are within the synthesizable subset can be used in ways that give SystemC synthesis advantages unattainable in any other hardware design language
• Encapsulation: C++ classes can be used in SystemC synthesis to manage the
complexity inherent in hardware design
Algorithmic functionality can be captured in a class for reuse Functions providing a public API for use of the algorithm can be made externally avail-able using the C++ “public” access control Internal computation functions and storage of internal state needed by the algorithm can be made private
Interface functionality can be encapsulated as discussed earlier creating a modular, reusable interface Modular interfaces expose a transaction-level func-tion call interface to the designer which allows them to be used without requiring the designer to be expert in the details of the interface protocol
• Construction of custom data types: Operator overloading is a C++ technique
whereby a class can provide a custom implementation for such built-in opera-tors as “*” (multiply) and “+” (add) This allows the construction of user defined datatypes such as for complex arithmetic, and matrix arithmetic Arithmetic oper-ations can be performed on these datatypes using conventional C++ syntax, e.g., a= b + c; which promotes ease-of-use and improves a reader’s ability to understand the code
• Development of configurable IP: C++ provides template specialization as a way
to write a single body of code which can represent a wide range of behaviors depending on the specific template parameters selected As a simple example, template specialization can be used to build a filter class that can operate on any given datatype, including user-defined custom datatypes
A more sophisticated example is the cynw float parameterized floating-point class that Forte has developed It allows the user to specify template parameters
to choose the exponent and mantissa widths as well and configure options such
as normalization and rounding behaviors
Trang 2Supported C++ Constructs
Arithmetic operators Integer data types
s e r u t c u r t S s
r o t a r e o l a c i
g
L
Statically-determinable pointers Inheritance
if-else statements Operator overloading
switch-case statements Inferring memories from arrays
do, while, and for loops Inferring registers from arrays
break and continue statements Template classes and functions
Template specialization
5.2.2 Non-Synthesizable C ++ Constructs
One characteristic of the synthesis process is that it uses the source code of the high-level design without access to information that can only be determined at simulation time In other words, the synthesis process can only take advantage of language features that can be resolved statically and information that can be determined by inspection of the source code This is the source of most of the restrictions on C++ constructs that can be used:
• Pointer arithmetic: In the processor-based execution environment in which the C
and C++ languages were originally envisioned, all variables, structures, arrays and other storage elements are defined to exist within a single uniform address space
A hardware implementation may include multiple separate memories of dif-ferent kinds as well as storage elements implemented directly with flip-flops Clearly, in this environment making decisions based on the value of the address
of a variable is meaningless Consequently, pointer arithmetic is not supported for SystemC synthesis
• Pointer dereferencing: Similarly, accessing a specific storage element by its
address assumes a processor-based execution environment Therefore, in general, passing pointers and dereferencing them is not supported for SystemC synthesis Nevertheless, under some circumstances the target of the pointer can be unam-biguously determined by a static analysis of the source code For instance, if the address of an array is passed directly to a subroutine it is usually possible to statically determine the identity of the array in question In such cases the use of the pointer will be supported by synthesis
Trang 3• Dynamic memory allocation: For reasons similar to those limiting the use of
pointers, allocation of storage elements using malloc(), free(), new, and delete is not supported for SystemC synthesis One notable exception is that allocation of sub-modules using new is supported
• Virtual functions: Virtual functions select the behavior of a particular object
based upon run-time determination of its class identity Since this cannot, in general, be determined statically, use of virtual functions is not supported for SystemC synthesis
5.3 Synthesizable Module Structure
Synthesizable SC MODULES can include multiple SC CTHREAD processes, and multiple SC METHOD processes In addition they can include submodules along with signals and channels to provide internal interconnect Because SC MODULES are C++ classes, they can also include data members of any synthesizable data type
to provided internal state, and member functions that can be used by the processes
to implement the required behavior
5.4 Concurrent Processes
Among the required hardware semantics provided by SystemC are process con-structs that allow a designer to directly express concurrent behaviors Two of these process constructs, SC CTHREAD, and SC METHOD, are appropriate for syn-thesis to hardware and are supported by Cynthesizer A module may contain any combination of these Use of multiple SC CTHREADs and/or SC METHODs in a single module is fully supported
This allows SystemC synthesis using Cynthesizer to encompass the areas tra-ditionally considered separately as the behavioral level and the register-transfer
Trang 4level Using Cynthesizer, an engineer can combine high-level behavioral design with low-level register-transfer level design
Ordinarily, an engineer who wants to do a pure RTL design will choose a con-ventional HDL such as SystemVerilog or VHDL SystemC is more often used when high-level synthesis is needed for a substantial part of the design Typically a com-plex algorithm or a comcom-plex control structure is defined using an SC CTHREAD,
or multiple concurrently executing SC CTHREADs These are combined with
SC METHODS for implementation of small parts of the design that can be bet-ter specified at a low level Examples of these low-level parts of the design might include the clock boundary crossing logic or an asynchronous bypass path
5.4.1 SC CTHREAD Processes
The SC CTHREAD construct implements a clocked process The declaration of the process includes specification of a signal that will be used as the clock for the process The semantics of SC CTHREAD guarantee that the behavior of the process will be synchronized to this clock
In addition the reset signal is() function specifies a signal that will be used to reset the process Whenever the reset signal is asserted, the process is restarted in its initial state This allows explicit initialization behaviors to be written that determine the state of the flip-flops of the design when it comes out of reset During simulation, within the body of the subroutine that is the behavior of the SC CTHREAD process, execution proceeds sequentially until the process hits a wait() statement upon which the process is suspended until the next clock cycle
These characteristics make SC CTHREAD ideal for high-level synthesis of abs-tract, untimed behaviors combined with detailed cycle-accurate, pin-level interfaces Synthesizer interprets all behavior in an SC CTHREAD process that occurs before the first wait() statement as reset conditions Synthesis requires that this reset code be schedulable in a single clock cycle
void thread_func() {
// reset behavior must be // executable in a single cycle
reset_behavior();
wait();
// initialization may contain // any number of wait()s
// This part is only executed // once after a reset.
initialization();
// infinite loop – concurrent hardware
while (true) { rest_of_behavior();
} }
SC_CTHREAD
reset behavior
while (1) {
main loop
}
post-reset
initialization
module_name.cc
Trang 5SC MODULE(sub)
{
// ports
sc in clk clk;
sc in<bool> rst;
SC CTOR(sub)
{
SC CTHREAD( thread func, clk.pos() );
reset signal is( rst, 1 );
}
void thread func()
{
// reset behavior
wait();
while(1)
{
}
}
};
The “SC CTHREAD” statement associates the thread func() function with the positive edge of the signal clk Cynthesizer implements such a thread as a circuit synchronous to that clock edge
The “reset signal is” statement makes the “1” level of the rst signal reset the thread
5.4.2 SC METHOD Processes
The SC METHOD process construct implements a triggered process associated with a sensitivity list The SC METHOD declaration includes a set of signals and rising-edge/falling-edge information that define the sensitivity list of the
SC METHOD The subroutine associated with the SC METHOD process is exe-cuted whenever any of the signal transitions in its sensitivity list occurs
These characteristics make SC METHOD ideal for synthesis of register-transfer level behaviors
The SC METHOD construct is used to express design functionality at a low level equivalent to RTL for synthesis SC METHOD provides a way to specify a sensitivity list that a specific clock signal with a thread, and has precise semantics for reset behavior
Trang 6Cynthesizer can be used to synthesize synchronous SC METHODS using static sensitivity to a clock as follows
SC CTOR(sync)
{
CYN DEFAULT INPUT DELAY(.1,"delay");
SC METHOD( sync method );
sensitive pos( clk );
dont initialize();
}
Asynchronous SC METHODS using static sensitivity to a number of inputs can also be synthesized as follows
SC CTOR(async)
{
CYN DEFAULT INPUT DELAY(.1,"delay");
SC METHOD( async method );
sensitive << input 1 << input 2;
dont initialize();
}
SystemC semantics for SC METHOD also provide for dynamic sensitivity using the next trigger() function Dynamic sensitivity is not supported for synthesis SystemC semantics for SC METHOD also provide that each SC METHOD will
be executed once at the beginning of simulation This is meaningless in the con-text of synthesis, so disabling this behavior using the dont initialize() function is recommended
5.5 Modular Interfaces
In addition to simple signals carrying single-bit or scalar values, designers using Cynthesizer can implement high-level channels for communication By encapsulat-ing the low-level signals, ports, and protocol functions in modular interface socket classes, the designer is relieved of the tedious connection of individual signals, and can connect an entire interface, such as a connection to a memory, with a sin-gle binding function In addition, the modular interface code can be thoroughly tested once, and then reused many times without modification, avoiding numerous common errors and reducing debug time
These modular interfaces consist of C++ classes containing synthesizable Sys-temC code using constructs such as signals, ports, and synthesizable protocol code Common interfaces are provided by Forte Interfaces conforming to specific cor-porate standards can be written in SystemC by a corcor-porate CAD department, and project-specific interfaces can be written by any engineer
Trang 7The abstraction and modularity capabilities of C++ and SystemC offer a unique advantage for high-level hardware design when they are used in this way to encap-sulate interfaces for ease-of-use and for reuse
The key technique is to use the C++ class mechanism to encapsulate the signal-level connections (i.e., ports) along with the code that implements the signal-signal-level protocol
In general, there are two complementary interfaces (e.g., input and output) that are implemented as two modular interface “socket” classes These are connected by binding calls to a modular interface “channel” class The processes in the modules containing the sockets call transaction-level interface functions defined in the socket classes to execute their interface behaviors
sc_in/out
sc_signal
Module 2
CTHREAD
Module 1
CTHREAD
Modular interface Channel
Modular interface
Output socket
f1()
Modular interface Input socket f2()
g1() g2()
5.5.1 Modular Output Socket
In its simplest form, an output socket for a ready/valid handshake interface might look like the following
// Output socket
template <class T>
class RV out
{
public:
sc in<bool> rdy;
sc out<bool> vld;
sc out<T> data;
RV out( const char* name=0 )
{}
// reset function called from SC CTHREAD
// establishes initial conditions
void reset()
Trang 8vld = 0;
data = 0;
}
// put function called from SC CTHREAD
// executes output protocol
void put( const T& val )
{
do { wait(); } while ( !rdy.read() );
data.write( val );
vld = 1;
wait();
vld = 0;
}
};
Note that the sc in/sc out ports are incorporated into the modular interface socket
as data members The two transactions that the port implements, reset() and put(), are also implemented as member functions
5.5.2 Modular Input Socket
The corresponding input socket implements the reciprocal protocol Note that the direction of the ports is reversed from that of the output socket
// Output socket
template <class T>
class RV in
{
public:
RV in( const char* name=0 )
{}
sc out<bool> rdy;
sc in<bool> vld;
sc in<T> data;
//
// Protocol transaction functions
//
void reset()
{
rdy = 0;
}
Trang 9T get()
{
wait();
rdy = 1;
do { wait(); } while ( !vld.read() );
rdy = 0;
return data.read();
}
};
5.5.3 Use of Modular Interfaces
The modular interface socket can be used in a design in a way that is similar to how a simple sc in or sc out port would be used The instantiation and binding
of the socket look just like an sc in or sc out port To execute the protocol, the
SC CTHREAD calls the transaction functions of the modular interface socket as follows
SC MODULE(sub)
{
sc in clk clk;
sc in<bool> rst;
RV in< sc uint<8> > din;
RV out< sc uint<8> > dout;
SC CTOR(sub)
{
SC CTHREAD( thread func, clk.pos() );
reset signal is( rst, 1 );
}
void thread func()
{
// reset behavior
din.reset();
dout.reset();
wait();
while (1)
{
sc uint<8> d = din.get();
dout.put( d + 1 );
}
}
};
Trang 105.5.4 Channel
The signals that are needed to provide connectivity for this interface can also be encapsulated in a channel class as follows
// Channel class
template <class T>
class RV
{
public:
sc signal<bool> rdy;
sc signal<bool> vld;
sc signal<T> data;
};
5.5.5 Binding
The addition of a couple of binding functions to the modular interface socket allows the entire interface to be bound using a single function call This reduces the number
of lines of code needed to use an interface, allows interchange of different inter-faces with minimal code modification, and prevents trivial errors due to misspelling and misconnecting individual signals For our example the binding functions in the output port are as follows
// Output socket
template <class T>
class RV out
{
//
// Binding functions
//
template <class C>
void bind( C& c )
{
rdy(c.rdy);
vld(c.vld);
data(c.data);
}
template <class C>
void operator() ( C& c )