Esperan - the EDA Training Company
       
Course Menu
   
   
 
 
 
 
 
 
 

Introduction to SystemC

Tutorials > SystemC > Introduction to SystemC

Rational

This tutorial is aimed at Hardware and Software engineers wishing to acquire an understanding of the SystemC language and its various uses.

No prior knowledge of C++ or HDL is required for the completion of this tutorial; however, throughout this tutorial we will be drawing parallels between SystemC and other languages.

Note this is a deliberately simplified description of SystemC. Full details on the language, coding styles; design guidelines can be found on the Esperan SystemC Fundamentals class.

Introduction

SystemC is a C++ library used for supporting system level modeling. It supports various abstraction levels and can be used for fast, efficient designs and verification. The SystemC library is provided by the Open SystemC Initiative, a non-profit independent organisation. The OSCI is composed of numerous companies, universities and individuals. The ultimate aim of the organisation is to achieve IEEE standardisation for SystemC. The SystemC reference simulator is freely available at www.systemc.org . Numerous EDA vendors provide commercial implementations of the SystemC language and support for mixed languages simulations. Along with the SystemC language, a number of additional application specific libraries are freely available either at www.systemc.org or www.testbuilder.net

Why SystemC instead of C++

The C++ language is based on sequential programming. Consequently it is not suited for the modeling of concurrent activities. Furthermore most system and hardware models require a notion of delays, clocks or time. features which are not present in C++ as a software programming language. As a result, complex and detailed systems cannot be easily described in C++ alone. Additionally communication mechanisms used in hardware models, such as signals and ports, are very different from those used in software programming. Lastly, the data types found in C++ are too remote from the actual hardware implementation. Ultimately, new dedicated data types and communication mechanisms have to be provided.

SystemC Implementation

The SystemC core language is based on C++. As a C++ library, layered on top of C++, SystemC defines data types dedicated to hardware modeling such as bit and vector types as well as fixed point types. Core language elements such as modules, processes, events, channels, event driven simulation kernel are also present. Finally, elementary channels such as signals or FIFOs are provided to implement communication mechanisms between concurrent objects.

Modules

A module is a C++ class - it encapsulates a hardware or software description. SystemC defines that any module has to be derived from the existing class sc_module. SystemC modules are analogous to Verilog modules or VHDL entity/architecture pairs, as they represent the basic building block of a hierarchical system. By definition, modules communicate with other modules through channels and via ports. Typically a module will contain numerous concurrent processes used to implement their required behaviour. An example of a module is as follows:
class counter: public sc_module { int value; public: sc_in clk; sc_in count; sc_in reset; sc_out q; SC_HAS_PROCESS(counter); counter(sc_module_name nm): sc_module(nm), value(0) { SC_METHOD(do_count); sensitive<< clk.pos() << reset ; } protected: void do_count() { if (reset) { value = 0; } else if (count) { value++; q.write(value); } } };
This example illustrates the creation of a counter module. The first part consists in the declaration of input and output ports. Ports are created form existing SystemC template classes: sc_in<> and sc_out<>. A type passed as a template argument defines the type of the data exchanged on the ports. The macro SC_HAS_PROCESS is used to indicate to the simulator’s kernel that this specific counter class will contain concurrent processes.

The constructor function is used to register any of the access functions as concurrent processes. In this case, the do_count function is registered an SC_METHOD which is similar to a Verilog always or a VHDL process. It is worth observing that the constructor function defines a parameter of type sc_module_name. This parameter is required by the sc_module parent class. For the sake of simplicity, this parameter can be seen as a string type.

The last part of this module defines the do_count function. At this point, it can be observed that the do_count function is being made sensitive to the reset port and the positive edge of the clk port. Consequently, it will only be activated on a change of either the reset or the clk ports.

Ports and Interfaces

As can be observed in the previous example, ports are defined as objects inside a module. For obvious reasons they will have to be made publicly available to the outside world through the use of the public keyword.

Although SystemC provides numerous predefined ports such as: sc_in<>, sc_out<>, sc_inout<>, sc_fifo_in<>, sc_fifo_out<>, and more, the language also allows the definition of user defined ports and how should they be accessed. This is done through the use of the sc_port<> class. An example of the use of the sc_port is as follows:

sc_port< sc_signal_in_if, 1 > clk;
This declaration is, in effect, identical to:
sc_in clk ;
As it can be observed, ports are defined by a name clk, a type bool and an interface sc_signal_in_if<>.

The interface sc_signal_in_if<> defines the restricted set of available messages that can be send to the port clk. For instance the functions: read() or default_event() are defined by the sc_signal_in_if<> class. At this stage it worth pointing out that the implementation of the functions defined inside an interface is provided by a third party element: the channel. Channels will be discussed in greater detail at the end of this section.

Processes

Two kinds of process exist in SystemC: SC_METHOD and SC_THREAD. To some extent, the two processes are similar since they will both will contain sequential statements and have their own thread of execution; hence, they will operate concurrently. Additionally, both SystemC processes allow for both static sensitivity and dynamic sensitivity.

By definition, SC_METHOD cannot be suspended during its execution. Once the execution of the SC_METHOD as been performed, it halts and waits for new activities on its static or dynamic sensitivity list before executing again. This is similar to a VHDL process or Verilog procedure with a sensitivity list.

In contrast with SC_METHOD, SC_THREAD can be suspended during execution and resumed at a later stage. Furthermore, by definition, SC_THREAD only executes once during simulation and then suspends. This mechanism is akin to a Verilog initial block. For this reason, designers will commonly use an infinite loop inside an SC_THREAD to prevent it from ever exiting before the end of the simulation. An example of an SC_THREAD is as follows:

void do_count() { while(true) { if (reset) { value = 0; } else if (count) { value++; q.write(value); } wait(); } }
Because of performance overheads, SC_METHOD implementations are usually preferred to SC_THREAD.

Channels

Channels are SystemC’s communication medium. They can be seen as a more generalized form of signals. SystemC provides a exhaustive range of predefined channels for generic uses such as: sc_signal, sc_fifo, sc_semaphore etc. Additionally SystemC permits the creation of user defined channels. This feature of the language significantly differentiates it form other Hardware Description Languages such as Verilog or VHDL. Providing abstraction at the interface level of components achieves greater design and modeling flexibilities. By definition modules are interconnected via channels and ports. In turn, ports and channels communicate via a common interface.

Note: For the purpose of this tutorial we will only consider predefined SystemC channels.

Composition

The principle of composition is analogous to hierarchical design. SystemC encourages composition for the creation of complex systems. To illustrate composition, an additional component (testbench) is created. A simple example of a test bench is as follows:
class testbench: public sc_module { public: sc_out clk; sc_out reset; sc_out count; SC_HAS_PROCESS(testbench); testbench(sc_module_name nm): sc_module(nm) { SC_THREAD(clk_gen); SC_THREAD(stimuli); } void clk_gen() { while(true) { clk.write(true); wait(10, SC_NS); clk.write(false); wait(10, SC_NS); } } void stimuli() { while(true) { reset.write(true); count.write(false); wait(10, SC_NS); reset.write(false); wait(50, SC_NS); count.write(true); wait(200, SC_NS); } } };
This module defines two processes clk_gen and stimuli. The clk_gen process is used to generate the clock signal used by the counter. The stimuli process is used to generate the enable signal used by the counter. Both processes are registered as SC_THREAD since they contain wait() statements.

The next step consists of instantiating a counter and a testbench object inside a top level module as follows:-

class top: public sc_module { public: sc_signal clk_sig, count_sig, reset_sig; sc_signal q_sig; counter uut ; // Counter instance testbench tb ; // Testbench instance top(sc_module_name nm): sc_module(nm), uut("uut"), tb("tb") { // Testbench’s ports connection tb.clk(clk_sig); tb.reset(reset_sig); tb.count(count_sig); // Counter’s ports connection uut.clk(clk_sig); uut.reset(reset_sig); uut.count(count_sig); uut.q(q_sig); } };
This example illustrates composition as two objects are declared inside the class top. SystemC defines that port/channel connections are performed inside the constructor function. The semantics used for port/channel connection is:
instance_name.port_name(channel_name);

Simulation

Simulation instructions are usually located inside a function called: sc_main. The sc_main functions are equivalent to the more conventional main function in C++.

This function will execute simulation specific commands such as setting the simulator’s resolution, channels to be traced, top level instance, simulation running time and more. An example of a sc_main function is as follows:-

int sc_main(int argc, char* argv[]) { sc_set_time_resolution(1, SC_NS); top verif_env("verif_env"); // Top level instance // Creating a trace file sc_trace_file *tf; tf = sc_create_vcd_trace_file("trace"); sc_trace(tf, verif_env.clk_sig, "clk_sig"); sc_trace(tf, verif_env.reset_sig, "reset_sig"); sc_trace(tf, verif_env.count_sig, "count_sig"); sc_trace(tf, verif_env.q_sig, "q_sig"); // Running the simulation sc_start(1000, SC_NS); sc_close_vcd_trace_file(tf); return (0); }
In this example the top level component of class top is called: verify_env. This declaration along with the sc_start() function call are sufficient to run a SystemC simulation. However a number of trace commands have been added to allow visualization of the results of the simulation. These traces files are stored using the VCD format inside a file called: trace.vcd.

Conclusions

This section presented the creation of SystemC modules and their associated concurrent processes. We examined the differences between SC_METHOD and SC_THREAD and illustrated the composition mechanism in SystemC. Lastly we saw how the sc_main function is used to provide a simulation “layer”. The next tutorial considers the simulation of a simple worked example.

Back to top


News
 
 
Technical Assets
 
 
 
 
   
Course Schedule
 
 
curve For over 10 years..
  Esperan has been providing VHDL training and Verilog training in UK, US, Canada, Western Europe, South Africa and throughout the world.
 
Esperan contact information US contact information
Phone +44 1344 865436 Fax +44 1344 865347
Email info@esperan.com
Tollfree Tel. 1800 220 8148 Fax. 1888 641 6431
Email US-sales@esperan.com