Chapter 2: Core Modeling

Datatypes and Bit-Accurate Modeling

When to use C++ integers, sc_int, sc_uint, sc_bigint, sc_bv, sc_lv, fixed-point types, and enums.

How to Read This Lesson

Keep one question in mind: when does this code run as ordinary C++, and when is the simulation kernel in charge? That split explains most beginner bugs.

SystemC is C++, so the first datatype question is always: can a normal C++ type answer this modeling question? If yes, use it. If the model needs hardware-shaped behavior, use SystemC datatypes. In accordance with the LRM Section 7, SystemC provides a robust set of numeric and vector types.

Here is a complete, fully compilable example demonstrating how all these types are instantiated and used within a SystemC module:

#include <systemc>
// Include the specific headers for SystemC datatypes
#include <sysc/datatypes/int/sc_int.h>
#include <sysc/datatypes/int/sc_uint.h>
#include <sysc/datatypes/bit/sc_bv.h>
#include <sysc/datatypes/bit/sc_lv.h>
#include <sysc/datatypes/fx/sc_fixed.h>
 
using namespace sc_core;
 
enum class BusState {
  Idle,
  Address,
  Data,
  Response,
};
 
SC_MODULE(DatatypeDemo) {
  SC_CTOR(DatatypeDemo) {
    SC_THREAD(run);
  }
 
  void run() {
    // Native C++ Types: fast and familiar
    uint32_t address = 0x40001000;
    uint8_t byte = 0xff;
    bool irq_pending = false;
 
    // sc_int and sc_uint: EXACT small bit-widths (up to 64 bits)
    sc_dt::sc_uint<12> page_offset = address & 0x0FFF;
    sc_dt::sc_int<9> signed_delta = -7;
    std::cout << "Page offset: " << page_offset << ", signed delta: " << signed_delta << "\n";
 
    // sc_bigint and sc_biguint: Arbitrary precision (> 64 bits)
    sc_dt::sc_biguint<257> wide_accumulator = 0;
    wide_accumulator = wide_accumulator + 1;
    
    // sc_bv and sc_lv: Bit vectors and Logic vectors
    sc_dt::sc_bv<8> mask = "10101100";
    sc_dt::sc_lv<4> bus = "10ZX"; // Z = High impedance, X = Unknown
    std::cout << "Bit vector mask: " << mask << ", Logic vector bus: " << bus << "\n";
 
    // Fixed-Point Types: DSP and quantization
    // <Total word length, Integer word length>
    sc_dt::sc_fixed<16, 2> gain = 1.25;
    std::cout << "Fixed point gain: " << gain << "\n";
 
    // Enums
    BusState state = BusState::Idle;
    if (state == BusState::Idle) {
       std::cout << "Bus is idle.\n";
    }
  }
};
 
int sc_main(int argc, char* argv[]) {
  DatatypeDemo demo("demo");
  sc_start();
  return 0;
}

Source and LRM Trail

Read this topic against Docs/LRMs/SystemC_LRM_1666-2023.pdf for process, event, time, reset, and report semantics. In source, follow .codex-src/systemc/src/sysc/kernel/sc_simcontext.cpp, sc_process.*, sc_event.*, sc_wait.*, sc_reset.*, and .codex-src/systemc/src/sysc/utils/sc_report_handler.cpp.

Choosing a Type

Use this practical rule:

  • Use native C++ types for fast functional state.
  • Use sc_uint and sc_int for exact small widths.
  • Use bit vectors (sc_bv) for bit slicing and packed fields when arithmetic isn't the primary goal.
  • Use logic vectors (sc_lv) when X or Z is meaningful for bus resolution (LRM Section 7.9).
  • Use fixed-point types (sc_fixed) for quantization and DSP modeling.
  • Use enums for readable control state.

The best type is the one that preserves the behavior you need without pretending the model is more detailed than it is.

Under the Hood: sc_logic and 4-Value Logic

SystemC's sc_logic provides 4-value logic: '0', '1', 'Z' (high impedance), and 'X' (unknown). In sysc/datatypes/bit/sc_logic.h, these states are represented by the enum sc_logic_value_t. When you perform operations on sc_logic, the library uses lookup tables (arrays) for logic gates. For example, the AND operation a & b uses a 4x4 matrix where X AND 0 yields 0, but X AND 1 yields X. This precise modeling is vital for RTL co-simulation, but it comes at a significant simulation performance cost compared to native boolean math.

Comments and Corrections