Signals, Clocks, and Primitive Channels
How sc_signal stores values, delays updates, notifies readers, and models hardware-like behavior.
sc_signal<T> is the everyday channel for value communication. It implements signal interfaces, stores a current value, accepts writes, and notifies readers when the value changes.
Read and Write
#include <systemc>
using namespace sc_core;
SC_MODULE(Writer) {
sc_out<int> out{"out"};
SC_CTOR(Writer) { SC_THREAD(run); }
void run() {
out.write(42);
wait(10, SC_NS);
}
};
int sc_main(int, char*[]) {
sc_signal<int> data{"data"};
Writer w("writer");
w.out(data);
data.write(42);
int old_or_new = data.read();
sc_start(20, SC_NS);
return 0;
}The tricky part is timing. A write does not necessarily become visible immediately to all other processes. The signal requests an update from the kernel. During the update phase, the current value changes and value-change events are notified.
Why Delayed Update Exists
Hardware does not usually behave like a sequence of software assignments. If two processes evaluate during the same simulated moment, the final state should not depend on an arbitrary function-call order.
Delayed update gives SystemC a hardware-like discipline:
- Processes evaluate and request channel updates.
- Primitive channels update.
- Events from those updates wake dependent processes.
- More delta cycles run if necessary.
This is the evaluate-update rhythm behind many SystemC semantics.
Clocks
sc_clock is a predefined channel that toggles over time:
#include <systemc>
using namespace sc_core;
SC_MODULE(ClockedModule) {
sc_in<bool> clk{"clk"};
SC_CTOR(ClockedModule) {
SC_METHOD(tick);
sensitive << clk.pos();
dont_initialize();
}
void tick() {
std::cout << "Tick at " << sc_time_stamp() << std::endl;
}
};
int sc_main(int, char*[]) {
sc_clock clk{"clk", 10, SC_NS};
ClockedModule mod("mod");
mod.clk(clk);
sc_start(30, SC_NS);
return 0;
}dont_initialize() prevents the method from running once at time zero before the first triggering edge.
Writer Policies
Signals can enforce writer rules. A common bug is accidentally driving the same signal from multiple processes. SystemC has writer-policy machinery to detect or allow different cases, depending on the signal type and configuration.
Resolved signals exist for cases such as tri-state or multi-driver logic, but you should not use them to hide accidental architecture problems. If a signal has multiple writers, make that a conscious design choice.
Primitive Channels
Signals are primitive channels. They participate directly in the kernel update phase through request_update() and an update() callback. That source-code shape explains why writing a signal from a process is not the same as assigning a C++ variable.
The public API is small. The behavior comes from how the channel cooperates with the scheduler.
Comments and Corrections