In System‑on‑Chip development, most late‑stage issues are not caused by broken IPs or incorrect RTL logic. They are caused by integration assumptions that silently fail when software starts running on real hardware.
This is not a marginal observation; it is a recurring reality across SoC projects. As designs grow in complexity, verifying hardware in isolation is no longer sufficient. A System‑on‑Chip only becomes functional once software takes control, and the interaction between hardware and software must therefore be verified explicitly and early.
This is precisely the purpose of hardware–software co‑verification.
ASIC‑Level thinking does not scale to System‑on‑Chip verification
ASIC verification and System‑on‑Chip verification address fundamentally different problems.
An ASIC is usually designed to perform a single, clearly defined function. Software, when present, plays a minimal role. Verification can therefore focus primarily on RTL correctness, protocol compliance and block‑level corner cases. The verification scope is well contained.
A System‑on‑Chip completely changes this model. It integrates CPUs, memories, interconnects and peripherals into a system that does nothing without software. Verification is no longer about ensuring that individual blocks behave correctly in isolation. It is about ensuring that the full system behaves correctly when controlled by embedded software.
Treating an SoC as a large ASIC is one of the most common verification mistakes, and it almost always leads to surprises during bring‑up.
Two verification approaches and their practical limits
System‑level verification generally starts with testbench‑driven stimulus. Transactions are generated externally, and verification IPs inject traffic into the SoC interconnect while the CPU is bypassed. This approach is attractive because it is simpler to implement and faster in simulation, and it allows reuse of existing IP‑level test scenarios.
In early integration phases, this approach is useful. However, its limitations are well known. As soon as system behavior depends on CPU execution, boot sequences, interrupt handling or driver logic, testbench‑driven stimulus stops being representative. Verification coverage may look good, while key system‑level behaviors remain completely untested.
This is where software‑driven stimulus becomes essential. By running real embedded software on the CPU, the SoC is exercised in a way that closely reflects its final use case. Boot flows can be verified, interrupts can be triggered, and complex interactions between software and peripherals can be validated.
Simulation becomes slower and debugging more complex, but this complexity reflects the reality of the system. Avoiding it does not eliminate integration problems; it only postpones them.
What hardware–software co‑verification really means
Hardware–software co‑verification is not about verifying hardware and software separately. It is about verifying their interaction as a unified system, early in the development flow.
By validating how embedded software runs on RTL hardware during simulation, teams can detect integration issues before the design is fixed in silicon or constrained by FPGA prototypes. This early feedback loop is the main value of co‑verification.
In practice, hardware–software co‑verification also enables parallel development. While hardware engineers finalize RTL, software engineers can already write and validate firmware and drivers against a realistic system model. Integration risks are addressed continuously instead of being discovered at the end.
Core foundations that cannot be treated as details
Effective hardware–software co‑verification relies on solid embedded fundamentals.
The compilation flow, from C source code through preprocessing, compilation, assembly and linking, directly determines how the CPU executes instructions. Memory segmentation decisions affect boot behavior, interrupt handling and debugging. These aspects are not software implementation details; they are part of the system architecture.
Startup code is a critical element of this architecture. Executed immediately after reset, it initializes the stack pointer, registers, memory and interrupt vectors before transferring control to the main software. If startup code is incorrect, the CPU may never reach the application, and failures are often misinterpreted as hardware issues.
Linker scripts play an equally important role. They define the memory layout of the system and establish the contract between hardware address maps and software placement. Experience shows that many early bring‑up issues originate from incorrect linker configurations rather than RTL bugs.
Loading software and making tests observable
Once the software is compiled, the generated binary must be loaded into memory. In co‑verification environments, this can be done using a bootloader, JTAG, verification IPs or direct memory backdoor access. In early simulation phases, backdoor loading is often preferred because it is deterministic and independent of unverified infrastructure.
After software execution begins, test results must be observable from the testbench. Relying on interfaces such as UART or GPIO too early is risky, since these IPs may not yet be verified.
This is why many teams rely on a memory‑based backdoor mechanism. Software writes status information such as pass, fail or error codes to specific memory locations. The testbench accesses these locations directly through a backdoor and evaluates the result. This approach enables fully automated, self‑checking tests without dependency on external interfaces.
Debugging software in RTL simulation
Debugging software running on RTL simulation requires a different mindset than debugging on physical hardware. Traditional debuggers are often unavailable, but simulation provides full visibility into CPU signals.
By monitoring the program counter, general‑purpose registers and control/status registers in the waveform, and correlating program counter values with disassembly generated from the ELF file, engineers can determine exactly which instructions are executed and why. This method requires experience, but it provides insights that are often impossible to obtain on real silicon.
Teams that develop these debugging skills typically handle integration issues faster, not slower.
Simulation and FPGA are complementary
Simulation remains the reference platform for hardware–software co‑verification because it offers full observability and precise control over system execution. FPGA‑based platforms complement simulation when execution speed or interaction with real hardware becomes necessary.
Effective verification strategies use both platforms at the right time rather than viewing them as alternatives.
Conclusion
Hardware–software co‑verification combines RTL verification and embedded software verification to validate System‑on‑Chip behavior at the system level. It enables early detection of integration issues, supports realistic use‑case validation and accelerates development by allowing hardware and software teams to work in parallel.
As SoCs continue to grow in complexity, verifying hardware alone is no longer enough. Verifying the interaction between hardware and software is the real objective and hardware–software co‑verification is the most effective way to achieve it.