Tải bản đầy đủ (.pdf) (10 trang)

High Level Synthesis: from Algorithm to Digital Circuit- P10 pptx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (360.94 KB, 10 trang )

76 M. Meredith
5.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.
5 High-Level SystemC Synthesis with Forte’s Cynthesizer 77
Supported C++ Constructs
Arithmetic operators Integer data types
serutcurtS srotarepo lacigoL
References Classes
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.
78 M. Meredith
• 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
5 High-Level SystemC Synthesis with Forte’s Cynthesizer 79
level. 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 complex 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
80 M. Meredith
SC 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.
5 High-Level SystemC Synthesis with Forte’s Cynthesizer 81
Cynthesizer 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 corporate CAD department, and
project-specific interfaces can be written by any engineer.
82 M. Meredith
The 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-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()
5 High-Level SystemC Synthesis with Forte’s Cynthesizer 83
{
vld = 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;
}
84 M. Meredith
T 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 );
}
}

};
5 High-Level SystemC Synthesis with Forte’s Cynthesizer 85
5.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 )

×