abstraction
SystemC vs Bare C++
2026 · 8 min read
We build models in both. And the most common wrong decision we see isn't a bad model — it's a model in the wrong vehicle: a single block that didn't need a simulation kernel, or a platform that absolutely did. Here's the decision, stated plainly.
What SystemC actually is
SystemC is not a modeling language. It's a discrete-event simulation kernel wearing a C++ class library. What you buy with it: a scheduler that decides when things happen, a time model that everyone in the platform agrees on, and a set of interoperability standards — TLM 2.0 sockets, phases, and payload conventions — that let models written by different people, in different years, talk to each other.
What you pay for it: the kernel's scheduling overhead on every event, a build and debug experience that's C++ with extra ceremony, and a framework whose idioms every engineer on the project now has to know. None of that is free. All of it is worth paying — sometimes.
The case for bare C++
A single block model — a peripheral, a controller, a datapath — that exists to answer questions about itself doesn't need any of that. What does the block do given this stimulus? What are its corner cases? Does it match the spec? A plain C++ program with a test harness answers those questions faster to build, faster to run, and easier to debug than the same logic inside an SC_MODULE. No scheduler, no sockets, no phases — just the behavior and a main().
This is also the honest vehicle for cycle-approximate work. If the model's job is to be correlated against RTL — same stimulus, same trace, diff the outputs — then what matters is the trace, not the framework. A bare C++ model with a clean cycle log is every bit as correlatable as a SystemC one, and it's usually faster, because nothing is paying kernel tax on the way to the observation point.
The case for SystemC
The moment the question stops being about one block, the calculus flips. SystemC earns its keep when:
- Multiple initiators contend. Timing interactions between blocks — who stalls whom, what overlaps — need a shared time model. Two bare C++ models don't have one; a platform does.
- Software runs on it. A virtual platform that boots an OS needs the ecosystem: processor models, TLM 2.0 interoperability, the standard payload conventions. You don't hand-roll that, and you shouldn't.
- The model outlives the project. A block model that will be reused, handed off, or integrated into someone else's platform needs to speak the standard — that's what the standard is for.
- Timing semantics are the deliverable. Approximately-timed work — the four-phase protocol, annotated transitions, backpressure — is what TLM 2.0 standardizes. Doing it ad hoc in bare C++ means inventing a private protocol that no one else can integrate against.
The failure modes, both directions
We see both mistakes, roughly equally:
SystemC where it doesn't belong. A single block wrapped in SC_MODULEs and sockets because that's what the last project used. The model takes longer to build, runs slower, and — the quiet cost — the framework's idioms start dictating the design. The behavior contorts to fit the vehicle. When a reviewer asks "why is this a socket?" the honest answer is "it didn't need to be."
Bare C++ where it doesn't belong. A platform built as a constellation of ad hoc models, each with its own private timing convention, stitched together by whoever needed the integration that week. It works — until it doesn't, and then the debugging question "whose time model is wrong" has no answer, because there were four. The platform that should have been SystemC from week one gets rebuilt as SystemC in a panic later.
The decision, compressed
Strip the ceremony and it's one question: does the model need to interoperate?
- One block, answering questions about itself, correlated against a trace → bare C++.
- Multiple blocks, shared time, software running on top, or reuse beyond the project → SystemC / TLM 2.0.
- Not sure yet → start bare, and let the second block decide. The conversion cost is real but bounded; the framework cost of guessing wrong in the other direction compounds.
And one meta-rule, because it's the one that gets skipped: whichever vehicle you pick, the correlation contract — same stimulus, same observation points, same tolerance — is identical. The framework is a delivery mechanism for behavior. The behavior is the deliverable. Teams that keep that ordering straight pick the vehicle correctly almost by accident; teams that don't end up with a beautiful platform whose models nobody trusts.