-
Notifications
You must be signed in to change notification settings - Fork 40
Common SystemC Library
Common SystemC Library consists of types, modules and functions which could be used in designs and testbench code. All the components are synthesizable with Intel Compiler for SystemC.
Common SystemC Library has three parts:
- Inter-process and inter-module communication channels
- Integer types and common functions
- Immediate and temporal assertions synthesizable into SVA
Common SystemC Library contains nine main channels in the library.
Target and Initiator are intended to connect two SC modules with 1:1 connection. Multi-target and Multi-initiator modules provides 1:N connection to connect multiple SC modules. FIFO is intended to connect two processes in the same module or to serve as a buffer for one process. On-die port represents any external port to connect SC design to other IPs or fabric. Memory represents any kinds of on-chip SRAM, RF or ROM memory. Register is used to add state for METHOD process. The common use cases of the modules are given in the picture below.
The Single Source modules work in two modes: RTL and TLM. RTL mode intended for hardware synthesis. In RTL mode the modules provide cycle accurate simulation. TLM (Transaction Level Modelling) mode provide fast simulation, intended for virtual prototyping. In TLM mode the modules provide approximate time simulation, there is no clock. Simulation is request-driven, executed in ordered delta-cycles (DC).
Currently only FIFO channel in RTL mode is available under open source license.
There are multiple options for clock/reset levels:
-
SCT_DEFAULT_TRAITS
-- clock edge and reset level, one of six following options: -
SCT_POSEDGE_NEGRESET
-- positive clock edge, negative reset level -
SCT_POSEDGE_POSRESET
-- positive clock edge, positive reset level -
SCT_NEGEDGE_NEGRESET
-- negative clock edge, negative reset level -
SCT_NEGEDGE_POSRESET
-- negative clock edge, positive reset level -
SCT_BOTHEDGE_NEGRESET
-- both clock edges, negative reset level -
SCT_BOTHEDGE_POSRESET
-- both clock edges, positive reset level
Usually, positive clock edge and negative reset level are used. That is provided by define SCT_DEFAULT_TRAITS
:
#ifndef SCT_DEFAULT_TRAITS
#define SCT_DEFAULT_TRAITS SCT_POSEDGE_NEGRESET
#endif
If other clock edge/reset levels required, SCT_DEFAULT_TRAITS
value should be provided as compile definition.
There is an CMakeLists.txt
example where sct_def_traits
target has definitions for negative clock edge and positive reset level:
add_executable(sct_def_traits sc_main.cpp)
target_compile_definitions(sct_def_traits PUBLIC -DSCT_DEFAULT_TRAITS=SCT_NEGEDGE_POSRESET)
The interfaces contain non-blocking functions except b_put
and b_get
which are may-blocking.
Interface | Functions | Comment |
---|---|---|
sct_put_if | bool ready() |
Return true if it is ready to put request |
void reset_put() |
Reset this initiator/FIFO | |
void clear_put() |
Clear (remove) request put in this cycle | |
bool put(const T& data) |
Put request into initiator/FIFO if it is ready, return ready to request | |
bool put(const T& data, sc_uint<N> mask) |
Put request into initiator/FIFO if it is ready, mask used to enable/disable put or choose targets in multi-cast put, return ready to request |
|
void b_put(const T& data) |
May-block put request, could be used in THREAD process only | |
void addTo(sc_sensitive& s) |
Add put related signals to process sensitivity | |
void addTo(sc_sensitive* s, sc_process_handle* p) |
Add put related signals to process sensitivity | |
sct_get_if | bool request() |
Return true if it has request to get |
void reset_get() |
Reset this target/FIFO | |
void clear_get() |
Clear (return back) request got in this cycle | |
T peek() |
Peek request, return current request data, if no request last data returned | |
T get() |
Get request and remove it from FIFO/target, return current request data, if no request last data returned | |
bool get(T& data, bool enable) |
Get request and remove it from FIFO/target if enable is true, return true if there is a request |
|
T b_get() |
May-block get request, could be used in THREAD process only | |
void addTo(sc_sensitive& s) |
Add get related signals to process sensitivity | |
void addTo(sc_sensitive* s, sc_process_handle* p) |
Add get related signals to process sensitivity | |
void addPeekTo(sc_sensitive& s) |
Add peek related signal to process sensitivity | |
sct_fifo_if | inherits sct_put_if<T> and sct_get_if<T>
|
|
unsigned size() |
FIFO size | |
unsigned elem_num() |
Number of elements in FIFO, value updated last clock edge for METHOD, last DC for THREAD | |
bool almost_full(const unsigned& N) |
Return true if FIFO has (LENGTH-N) elements or more, value updated last clock edge for METHOD, last DC for THREAD | |
void clk_nrst(sc_in<bool>& clk_in, sc_in<bool>& nrst_in) |
Bind clock and reset to FIFO | |
void addTo(sc_sensitive& s) |
Add put and get related signal to process sensitivity | |
void addToPut(sc_sensitive& s) |
Add put related signals to process sensitivity | |
void addToGet(sc_sensitive& s) |
Add get related signals to process sensitivity | |
sct_in_if | const T& read() |
Read from signal/register |
void addTo(sc_sensitive* s, sc_process_handle* p) |
Add signals to process sensitivity | |
sct_inout_if | const T& read() |
Read from signal/register |
void write(const T& val) |
Write to signal/register | |
void addTo(sc_sensitive* s, sc_process_handle* p) |
Add signals to process sensitivity |
Functions addTo
, addToPut
, addToGet
and addPeekTo
are used to add the channel to process sensitivity list. For target and initiator instead addTo
operator <<
can be used. For FIFO instead addToPut
and addToGet
operator << fifo.PUT
and << fifo.GET
can be used.
The FIFO can be used for inter-process communication between processes in the same module and for storing requests inside one process.
The FIFO implements sct_fifo_if
. FIFO has size template parameter which could be 0 or positive. Zero-size FIFO is a special case intended to communication with always ready target process (process which gets from the FIFO).
template<
class T,
unsigned LENGTH, // Size (maximal number of elements)
class TRAITS = SCT_DEFAULT_TRAITS, // Clock edge and reset level traits
bool TLM_MODE = SCT_DEFAULT_MODE> // RTL (0)
>
class sct_fifo {};
The FIFO can have combinational or registered request (core_req
and core_data
) and response (core_ready
) kind which specified in constructor parameters.
sct_fifo(const sc_module_name& name,
bool sync_valid = 0, // Request path has synchronous register
bool sync_ready = 0, // Response path has synchronous register
bool use_elem_num = 0, // Element number/Almost full or empty used
bool init_buffer = 0) // Initialize all buffer elements with zeros in reset
// First element to get is always initialized to zero
Minimal FIFO size to provide full throughput depends on process types and request/response kind. In the table below minimal required FIFO sizes to provide full throughput are given.
Initiator process | Target process | sync_valid | sync_ready | Minimal FIFO size |
---|---|---|---|---|
method | method | 0 | 0 | 1 |
method | method | 0 | 1 | 1 |
method | method | 1 | 0 | 1 |
method | method | 1 | 1 | 2 |
method | thread | 0 | 0 | 1 |
method | thread | 0 | 1 | 2 |
method | thread | 1 | 0 | 2 |
method | thread | 1 | 1 | 3 |
thread | method | 0 | 0 | 1 |
thread | method | 0 | 1 | 2 |
thread | method | 1 | 0 | 2 |
thread | method | 1 | 1 | 3 |
thread | thread | 0 | 0 | 2 |
thread | thread | 0 | 1 | 3 |
thread | thread | 1 | 0 | 3 |
thread | thread | 1 | 1 | 4 |
FIFO should be used for processes communication instead of set of signals. FIFO has only one writer and one reader process, in comparison with sct_signal
which could be read in multiple processes. For 1:N communication array or sc_vector
of FIFOs should be used.
struct Top : public sc_module {
sct_fifo<T, 2> fifo{"fifo", 1}; // Pipelining register for request
explicit Top(const sc_module_name& name) : sc_module(name) {
fifo.clk_nrst(clk, nrst);
SC_THREAD(producerProc); sensitive << fifo.PUT; // Process puts to FIFO
async_reset_signal_is(nrst, 0);
SC_METHOD(consumerProc); sensitive << fifo.GET; // Process gets from FIFO
}
}
void producerProc() {
fifo.reset_put();
wait();
while (true) {
if (fifo.ready()) { // If FIFO is ready put next value
fifo.put(getSomeVal());
}
wait();
}
}
void consumerProc() {
fifo.reset_get();
T val;
if (fifo.get(val)) {
doSomething(val);
}
}
struct Top : public sc_module {
sc_in<bool> clk{"clk"};
sc_in<bool> nrst{"nrst"};
sct_fifo<T, 5> fifo{"fifo"};
explicit Top(const sc_module_name& name) : sc_module(name) {
fifo.clk_nrst(clk, nrst);
SC_THREAD(storeProc); sensitive << fifo; // Process puts and gets to FIFO
async_reset_signal_is(nrst, 0);
}
}
void storeProc() {
fifo.reset();
wait();
while (true) {
if (fifo.ready()) {
fifo.put(getSomeValue());
}
wait();
if (fifo.request()) {
doSomething(fifo.get());
}
}
}
The bit-accurate integer types which support any number of bits:
-
sct_int<N>
is signed integer with N bits -
sct_uint<N>
is unsigned integer with N bits
SystemC contains sc_int
/sc_uint
integer types which are limited to 64 bit. Also SystemC contains sc_bigint
/sc_biguint
which can be more than 64bits , but are slow in simulation. Also all these integer types do not support 0 width.
sct_int
and sct_uint
automatically substitute sc_int
/sc_bigint
(sc_uint
/sc_biguint
) depends on bit width. These types are implemented in sct_sel_types.h
.
To initialize a variable of sct_uint
type with all bits 0 or 1 there are special templates:
-
sct_zeros<N>
is N-bit zeros literal of sct_uint type, -
sct_ones<N>
is N-bit ones literal of sct_uint type.
// Variable declaration with 0/1 initialization
sct_uint<12> a = sct_zeros<12>;
sct_uint<66> b = sct_ones<66>;
auto c = sct_zeros<90>;