LG2 Notes: SystemC

Slides for LG2.

It's history, overview, and how to use SystemC on the PWF.

SystemC is a library for C++ to support hardware modelling.

It can be used for detailed net-level modelling, but today its main uses are :

SystemC was developed over the last ten years. There have been two major releases, 1.0 and 2.0. Also of importance is the recent release of the add-on TLM library, TLM 2.0.

Everything can be downloaded from www.systemc.org.

Practical classes

In the practical classes we do not use the TLM 2.0 library. Instead, the main principles behind TLM 2.0 are implemented from scratch using tiny examples.


SystemC Components

SystemC includes (at least):

Problem: hardware engineers are not C++ experts but they can be faced with complex or advanced C++ error messages when they misuse the library.

Benefit: General-purpose behavioural C code, including application code and device drivers, can all be modelled in a common language.

Example (Counter)

   sc_in clk, reset;
   sc_out out;
   sc_int<10> sum;

   void m() 
      sum =  (reset) ? 0: (sum.read()+1); // Use .read() since channel contains a signal.

     { SC_METHOD(m);
       sensitive << clk.pos();


SystemC enables a user class to be defined using the the SC_MODULE macro.

Modules inherit various attributes appropriate for an hierarchic hardware design including an instance name, a type name and channel binding capability..

The sensitive construct registers a callback with the EDS kernel that says when the code inside the module should be run.

A nasty feature of SystemC is the need to use the .read() method when reading a signal.

SystemC Structural Netlist

A SystemC channel provides general purpose interface between components.

The sc_signal channel should be used to obtain the compute/commit paradigm. This avoids non-determinacy from races in zero-delay models.

Other provided channels include FIFOs and semaphores.

Users can overload the channel class to implement channels with their own semantics if needed. A user-defined channel type can even contain other SystemC components but the importance of this is reduced when using the TLM libraries.

SystemC Signals

Signals have a current value and a next value. Assigns are to the next value whereas reads use the current value. The next value is copied to the current value in a commit cycle when there are no futher events of the current tnow on the event queue.

For faster system modelling, we do not want to enter EDS kernel for every change of every net: so is it possible to pass larger objects around, or even send threads between components, like S/W does ?

It is possible to put any datatype inside a signal and route that signal between components (provided the datatype can be checked for equality to see if current and nex are different and so on). So yes, using this approach, a higher-level model is possible, because a complete Ethernet frame or other large item can be delivered as a single event, rather than having to step though the cycle-by-cycle operation of a serial hardware implementation.

SystemC 2.0 enabled threads to be passed along the channels, breaking away from just using signals. This enables the transactional calls introduced in LG4 to be passed along structures that were previously EDS nets carrying logic values.

Threads and Methods

SystemC enables a user module to keep a thread and a stack but prefers, for efficiency reasons if user code runs on its own upcalls in a trampoline style.

Comparing SC_THREADS with trampoline-style methods we can see the basis for two main programming TLM styles to be introduced later: blocking and non blocking.

Blocking and Eventing

SystemC original provided a type called lambda for building predicate functions that could be registered with the EDS kernel so that the kernel could determine when a process was unblocked.

However, they were cumbersome to use. They illustrate some of the issues with using a language like C++ for a purpose it was not designed for.

The recommended approach now is just to use spinlocks.

     waituntil(mycount.delayed() > 5 && !reset.delayed());
is replaced with the simple
     do { wait(SC_TIME(0)); }  while(!((mycount > 5 && !reset)));

Pre-TLM S/W Style Channels

We can implement the object-oriented (OO) S/W concept of adding an interface to a component by inheritance.

Although there was a limited capability in SystemC 1.0 to pass threads along channels, and hence do subroutine calls along what look like wire, this was made much easier SystemC 2.0.

See the slide for full details, but the important thing to note is that the entry points in the interface class are implemented inside the fifo device and are bound, at a higher level, to the calls made by the writer device. This kind of plumbing of upcalls to entrypoints formed an essential basis for future transactional modelling styles.

However we soon run in to the well-known OO problem with multiple instances of an interface: not often needed for S/W but common enough in H/W designs.

SystemC Synthesis

We cannot compile general C/C++ programs to hardware.

Must be finite state:

As well as the C/C++ input code we require additional directives over speed, area and perhaps power. A given function can generally be done in half as many clock cycles using twice as much silicon, although name aliases and control hazards (dependence on run time input data) can limit this.

Trading time for space is basically a matter of unwinding loops or introducing new loops.

Other important sources of hazard that can limit the amount of unrolling possible are limited numbers of ports on RAMs and user-set budgets on the number of certain components instantiated, such as adders or multipliers.

Products available : Catapult, SimVision, CoCentric, ... others.