Chapter 2: Core Modeling

Processes, Events, and Time

SC_METHOD, SC_THREAD, sensitivity, wait(), sc_event, and the meaning of delta cycles.

Processes are the executable behavior inside a SystemC model. Modules provide structure. Channels provide communication. Processes provide activity.

SystemC has two process styles you will use constantly:

  • SC_METHOD: runs to completion and cannot call wait().
  • SC_THREAD: can suspend with wait() and resume later.

SC_METHOD

Use SC_METHOD for combinational behavior or small reactions to events:

#include <systemc>
using namespace sc_core;
 
SC_MODULE(AndGate) {
  sc_in<bool> a{"a"};
  sc_in<bool> b{"b"};
  sc_out<bool> y{"y"};
 
  void comb() {
    y.write(a.read() && b.read());
  }
 
  SC_CTOR(AndGate) {
    SC_METHOD(comb);
    sensitive << a << b;
  }
};
 
int sc_main(int, char*[]) {
  sc_signal<bool> sig_a, sig_b, sig_y;
  AndGate and_gate("and_gate");
  and_gate.a(sig_a);
  and_gate.b(sig_b);
  and_gate.y(sig_y);
 
  sc_start(1, SC_NS);
  return 0;
}

The method runs when an event in its sensitivity list occurs. It should finish quickly because it cannot yield.

SC_THREAD

Use SC_THREAD when behavior has an internal timeline:

#include <systemc>
using namespace sc_core;
 
SC_MODULE(Timer) {
  sc_event done;
 
  SC_CTOR(Timer) {
    SC_THREAD(run);
  }
 
  void run() {
    wait(100, SC_NS);
    done.notify();
    std::cout << "Timer done at " << sc_time_stamp() << std::endl;
  }
};
 
int sc_main(int, char*[]) {
  Timer timer("timer");
  sc_start(200, SC_NS);
  return 0;
}

The call to wait() suspends the thread process. The simulation kernel saves enough process state to resume it when the wait condition is satisfied.

Events Do Not Store History

An sc_event is not a queue of messages. It is a notification mechanism. If nobody is waiting when an immediate event is notified, the event is missed.

That makes this pattern important:

#include <systemc>
using namespace sc_core;
 
SC_MODULE(Consumer) {
  sc_event producer_done;
 
  SC_CTOR(Consumer) {
    SC_THREAD(consumer_thread);
  }
 
  void consumer_thread() {
    while (true) {
      wait(producer_done);
      consume_result();
    }
  }
 
  void consume_result() {
    std::cout << "Result consumed at " << sc_time_stamp() << std::endl;
  }
};
 
int sc_main(int, char*[]) {
  Consumer cons("cons");
  cons.producer_done.notify(10, SC_NS);
  sc_start(20, SC_NS);
  return 0;
}

The process arms the wait first, then reacts.

Delta Cycles

A delta cycle is a zero-time scheduling step. It lets the kernel settle chains of events without advancing simulation time. Signal writes use this idea: a process writes a new value, the channel schedules an update, and dependent processes wake in a later delta cycle.

Delta cycles are why SystemC can avoid many order-dependent bugs. Processes can run in a deterministic simulation order while still modeling hardware-like simultaneous updates.

Practical Debug Rule

When behavior looks one step late, ask which phase you are observing:

  • Did a method write a signal but the update has not happened yet?
  • Did an event notify in the same delta or the next delta?
  • Is a thread waiting on a value change or on a timed delay?

Most SystemC timing surprises become ordinary once you separate time advancement from delta-cycle settling.

Comments and Corrections