Official Resources Hub
Links to the IEEE Language Reference Manual, Accellera Forums, and official GitHub repositories.
How to Read This Lesson
Start here slowly. The goal is not to memorize APIs yet; it is to build the mental model you will reuse in every later SystemC design review.
Official SystemC Resources
While LearnSystemC aims to be your definitive guide and single source of truth, it is crucial to know where the official standards and community discussions reside.
SystemC is an open standard maintained by the Accellera Systems Initiative and standardized by the IEEE.
Source and LRM Trail
For this foundation lesson, keep three references close: Docs/LRMs/SystemC_LRM_1666-2023.pdf for portable semantics, .codex-src/systemc/src/sysc/kernel for kernel behavior, and .codex-src/systemc/src/sysc/datatypes for bit-accurate C++ types. When this lesson mentions a macro or type, the useful habit is to ask which C++ class the macro eventually creates.
1. The Language Reference Manual (LRM)
The final authority on how SystemC behaves is the IEEE 1666 Standard. If you ever want to know the exact mathematical or logical rules governing the simulator, read the LRM.
2. The Accellera Community Forums
The Accellera forums are the primary gathering place for SystemC engineers, tool vendors, and language architects. If you have a highly specific bug or compiler issue, search the forums first.
3. Official Source Code Repositories
The Accellera Proof-of-Concept (PoC) simulator and associated libraries are open source and hosted on GitHub. Browsing these repositories is highly recommended once you reach the advanced chapters of LearnSystemC.
- SystemC Core: github.com/accellera-official/systemc
- Configuration, Control & Inspection (CCI): github.com/accellera-official/cci
- SystemC Verification Library (SCV): github.com/accellera-official/scv
- UVM-SystemC: github.com/accellera-official/uvm-systemc
Bookmark these links! They will be invaluable as you transition from a SystemC learner to a professional ESL architect.
Let's Connect This to the Standard and the Source
To effectively read and interpret the IEEE 1666-2023 Language Reference Manual and map it to the Accellera source code, you must understand how the standard is structured and where its rules are physically implemented.
Reading the IEEE 1666 LRM
The IEEE 1666 LRM is not a tutorial; it is a normative specification document. It is divided into several key sections. When you encounter a bug or need to verify a specific behavior, you should consult these chapters:
- Section 4 - Elaboration and Simulation Semantics: This chapter defines the simulation lifecycle. It dictates exactly what is allowed during elaboration (before simulation starts) and what the scheduling algorithm does during execution (the Delta Cycle, time progression, process awakening). The Accellera implementation for this resides heavily in
sysc/kernel/sc_simcontext.cpp. - Section 5 - Core Language (Modules, Processes, Events): This defines
sc_module,sc_method_process,sc_thread_process, andsc_event. This is the structural backbone of SystemC. - Section 6 - Communication (Ports, Interfaces, Channels): Defines how
sc_portbinds tosc_interfaceand how channels facilitate safe communication. - Section 7 - Data Types: Defines the fixed-precision integer and logic types (
sc_int,sc_logic). - Section 8 - Predefined Channels: Specifies the exact behavior of
sc_signal,sc_fifo, andsc_mutex, including their writer policies (SC_ONE_WRITERvsSC_MANY_WRITERS). - Sections 10 through 16 - Transaction Level Modeling (TLM-2.0): Defines interoperability standards for memory-mapped buses, including the generic payload (
tlm_generic_payload), blocking/non-blocking transport interfaces, and quantum keeping.
Navigating the Accellera SystemC Repository
The GitHub repository accellera-official/systemc mirrors the LRM architecture but uses deep C++ idioms to achieve the mandated behavior.
src/sysc/kernel/
This is the heart of the SystemC simulation engine.
sc_simcontext.cpp: Manages the global state. It contains the core simulation loop, handling the transition from evaluate phase to update phase (Delta Cycle).sc_cor.handsc_cor_qt.cpp/sc_cor_fiber.cpp: The underlying coroutine implementations. SystemC uses lightweight cooperative threads (coroutines) to implementSC_THREADs without the heavy OS overhead ofstd::thread. Depending on your OS, it uses QuickThreads, POSIX contexts, or Windows Fibers.sc_runnable.cpp: The run queue. It holds the lists of runnable threads and methods for the current delta cycle.sc_event.cpp: Implements thesc_eventnotification mechanisms, interacting directly withsc_simcontext's time wheel for delayed notifications.
src/sysc/communication/
This directory implements LRM Sections 6 and 8.
sc_port.cppandsc_export.cpp: Implement the hierarchical binding mechanism. During elaboration, ports traverse their bindings to find the ultimate target interface implementation.sc_signal.cpp: Implements thesc_signal<T>template. You can observe theupdate()phase logic here, which strictly enforces the read-only evaluate / deferred update semantics mandated by the LRM to prevent race conditions.sc_fifo.cpp: Implements bounded, process-safe queues.
src/sysc/datatypes/
This directory implements LRM Section 7.
int/: Implementssc_intandsc_uintup to 64 bits.bit/: Implementssc_logicandsc_lv(logic vectors).fx/: Implements fixed-point data types (sc_fixed,sc_ufixed). These are crucial for DSP algorithm modeling and HW synthesis but are incredibly heavy on compile times due to massive template usage.
src/tlm_core/
This directory implements the TLM-2.0 standard (LRM Sections 10-16).
tlm_1/: Legacy TLM-1.0 interfaces (rarely used in modern code).tlm_2/tlm_generic_payload/: Definestlm_generic_payload, the universal bus transaction object.tlm_2/tlm_sockets/: Defines the initiator and target sockets (tlm_initiator_socket,tlm_target_socket) which combine ansc_portandsc_exportto enable bidirectional function calls.tlm_2/tlm_quantum/: Implements thetlm_global_quantumclass, which allows processes to decouple from the SystemC scheduler to maximize simulation speed (Temporal Decoupling).
Translating LRM Constraints to Source Code Limits
When the LRM states "An sc_signal shall only be updated by a single process unless the SC_MANY_WRITERS policy is specified," the Accellera source code enforces this by storing the ID of the process that first writes to the signal. If a different process ID attempts a write in the same delta cycle (or across the simulation if strictly enforced), the sc_signal throws a fatal sc_report exception, abruptly terminating the simulation. Understanding where these checks live (e.g., sc_writer_policy.h) allows you to debug complex architectural violations efficiently.
Standard and Source Deep Dive: Port Binding
Port binding is the topological glue of a SystemC model. The IEEE 1666-2023 LRM Sections 4.2.1 (Elaboration) and Section 6.11-6.13 (Ports, Exports, Interfaces) rigidly define how structural connections are made and verified.
Inside the Accellera Source: sc_port_b and sc_port_registry
In src/sysc/communication/sc_port.h/cpp, all specialized sc_port<IF> classes derive from a non-template base class sc_port_b.
When you declare sc_port<BusIf> bus{"bus"};, the constructor ultimately calls sc_simcontext::get_port_registry()->insert(this).
The sc_port_registry (located in src/sysc/kernel/sc_simcontext.cpp) is the global list of every port in the simulation.
When you write cpu.bus.bind(subsystem.target); in your C++ code, you are invoking the bind() method on sc_port. However, this does not immediately resolve the C++ pointer! Instead, the port simply stores a generic pointer to the bound object in an internal array (because a port can be bound to multiple channels if the port's N parameter is > 1).
The Elaboration Phase: complete_binding()
The real magic happens when sc_start() is called.
Before simulation begins, sc_start() invokes sc_simcontext::elaborate(), which ultimately calls sc_port_registry::complete_binding().
If you trace sysc/kernel/sc_simcontext.cpp, you will see complete_binding() iterate over every single port in the design. For each port:
- It traverses the binding tree. If Port A is bound to Port B, and Port B is bound to Channel C, it recursively walks from A -> B -> C to find the actual
sc_interfaceimplementation. - Type Checking: It uses C++ RTTI (
dynamic_cast) to verify that the target object actually implements the interface required by the port.// Abstract representation of the kernel's check: sc_interface* target_if = dynamic_cast<sc_interface*>(bound_object); if (!target_if) { SC_REPORT_ERROR("Port binding failed: interface mismatch"); } - It resolves the final interface pointer and stores it directly inside the port's
m_interfacepointer array.
Zero-Overhead Simulation Dispatch
Why delay pointer resolution until complete_binding()? Because once elaboration finishes, the port has an absolute, direct C++ pointer to the implementing channel.
In src/sysc/communication/sc_port.h, the overloaded operator-> is extraordinarily simple:
template <class IF>
inline IF* sc_port<IF>::operator -> () {
return m_interface;
}During simulation, when a thread executes bus->write(0x10, data);, there are no map lookups, no string comparisons, and no routing tables. It is exactly equivalent to a direct C++ virtual function call on the channel object.
Comments and Corrections