P4. SystemC Tutorial - OR Gate with Testbench

Part 3 introduced one input, one output, one process. This part adds two new ideas: multiple inputs in the sensitivity list, and a directed testbench that walks the truth table. Both translate directly to how UVM monitors and directed tests work later — the OR gate is just the smallest possible vehicle for the pattern.

Implementation

#include "systemc.h"

// OR Gate Module
SC_MODULE(or_gate) {
  sc_in<bool>  a, b;  // Two input ports
  sc_out<bool> c;     // Output port

  void or_gate_p() {
    c.write(a.read() | b.read());
  }

  SC_CTOR(or_gate) {
    SC_METHOD(or_gate_p);
    sensitive << a << b;   // Trigger on either input
  }
};

int sc_main(int argc, char* argv[]) {
  sc_signal<bool> a, b, c;

  or_gate or1("or_gate_or1");
  or1.a(a);
  or1.b(b);
  or1.c(c);

  sc_trace_file* tf = sc_create_vcd_trace_file("or_gate");
  tf->set_time_unit(1, SC_NS);
  sc_trace(tf, a, "a");
  sc_trace(tf, b, "b");
  sc_trace(tf, c, "c");

  // Walk the truth table — each combination held for 1 ns
  a = 0; b = 0; sc_start(1.0, SC_NS);
  a = 0; b = 1; sc_start(1.0, SC_NS);
  a = 1; b = 0; sc_start(1.0, SC_NS);
  a = 1; b = 1; sc_start(1.0, SC_NS);

  sc_stop();
  sc_close_vcd_trace_file(tf);
  cout << "Finished at time " << sc_time_stamp() << endl;
  return 0;
}

Truth Table

ABC (A|B)
000
011
101
111

Expected Waveform

Open or_gate.vcd in GTKWave to confirm. c is high whenever either a or b is high.

Why exhaustive testing here?

For a 2-input combinational gate the input space is 4 values — checkable in microseconds. As soon as the design has state or wider buses, exhaustive enumeration explodes. That's where the next layer of techniques comes in:

  • Constrained random stimulus (UVM sequences) — let the simulator pick legal inputs
  • Functional coverage — measure which combinations you actually hit
  • Self-checking testbenches — assert the output instead of eyeballing waveforms

A self-checking version of this OR gate is a one-line addition. Inside sc_main after each sc_start:

sc_assert(c.read() == (a.read() | b.read()));

If the gate is ever wrong, the simulation aborts with a file/line. That's the same idea SystemVerilog assertions and UVM scoreboards generalize to bus protocols.

Viewing the VCD

sudo apt install gtkwave           # one-time
gtkwave or_gate.vcd &              # opens the GUI

In GTKWave, drag a, b, and c from the SST panel into the Signals pane. You should see four 1ns segments matching the truth table.

Common Pitfalls

  • Sensitivity list missing one input. Writing sensitive << a; alone makes the process oblivious to b changes — output looks stale half the time. Always list every input the process reads.
  • Forgetting sc_stop(). Without it, the simulation runs until the kernel decides nothing more will happen, which can leave the trace file truncated on some platforms.
  • Using = on sc_signal. Inside processes, write with .write() and read with .read(). The shorthand a = 0; in sc_main works only because sc_signal overloads operator= for the testbench context.
  • Two zero-width sc_start calls back-to-back. Both happen in the same delta cycle — only the last assignment shows up in the trace.

Next: Part 5 — AND Gate (and what we've learned)

Author
Mayur Kubavat
VLSI Design and Verification Engineer sharing knowledge about SystemVerilog, UVM, and hardware verification methodologies.

Comments (0)

Leave a Comment