Chapter 1: Foundations

Build SystemC and Write a First Model

How a SystemC program is compiled, linked, elaborated, and started.

A SystemC model is a normal C++ program linked with the SystemC library. That makes the workflow familiar: include headers, compile sources, link against the library, and run the executable.

The official downloads and release material live under Accellera's SystemC resources, while active source development is public in the Accellera GitHub repository. In a production environment, pin a SystemC version the same way you would pin a compiler or simulator.

Minimal Build Shape

The exact commands vary by installation, but the structure is consistent:

c++ -std=c++17 main.cpp \
  -I/path/to/systemc/include \
  -L/path/to/systemc/lib \
  -lsystemc \
  -o sim
./sim

Many teams wrap this with CMake:

cmake_minimum_required(VERSION 3.20)
project(counter_systemc CXX)
 
set(CMAKE_CXX_STANDARD 17)
find_package(SystemCLanguage CONFIG REQUIRED)
 
add_executable(sim main.cpp)
target_link_libraries(sim SystemC::systemc)

A Clocked Counter

This example introduces a module with input and output ports:

#include <systemc>
using namespace sc_core;
 
SC_MODULE(Counter) {
  sc_in<bool> clk{"clk"};
  sc_out<unsigned> value{"value"};
  unsigned internal = 0;
 
  void tick() {
    value.write(++internal);
  }
 
  SC_CTOR(Counter) {
    SC_METHOD(tick);
    sensitive << clk.pos();
    dont_initialize();
  }
};
 
int sc_main(int, char*[]) {
  sc_clock clk{"clk", 10, SC_NS};
  sc_signal<unsigned> count{"count"};
 
  Counter counter{"counter"};
  counter.clk(clk);
  counter.value(count);
 
  sc_start(50, SC_NS);
  return 0;
}

sc_clock is a channel that provides a clock signal. sc_signal<unsigned> is a channel that stores a value and notifies readers when it changes. The Counter module exposes ports, and the top level binds those ports to channels.

The Three Phases You Should Name

SystemC execution is easier to understand if you separate it into three phases:

  1. Construction: C++ constructors allocate modules, channels, and local state.
  2. Elaboration: SystemC finalizes hierarchy, port bindings, process registration, and object names.
  3. Simulation: sc_start() lets the kernel run processes according to events and time.

Many confusing errors come from doing phase-specific work in the wrong place. Binding belongs before simulation. wait() belongs in a thread process during simulation. Creating a process dynamically is possible, but you should first learn the static model.

Practical Advice

Keep the first model small. Build one clock, one signal, one module, and one print statement. Once that is working, add hierarchy. Then add events. Then add TLM. A SystemC environment is just C++, but debugging gets much easier when each layer has been proven independently.

Comments and Corrections