C BASED
VERIFICATION
for Functional Verification
of Hardware Designs
Master with detailed concepts and 50
advanced practice questions
Prasanthi Chanda
INTRODUCTION
1.1 What is C-Based Verification?
C-Based Verification refers to the use of the C or C++
programming languages to verify hardware designs,
particularly at the functional level. In this methodology,
testbenches, models, stimulus generators, and checkers
are written in C/C++ instead of traditional hardware
verification languages (HVLs) like SystemVerilog.
It is commonly used to:
Validate algorithms before RTL implementation
Create golden reference models
Enable high-speed simulation
Interface with RTL using DPI-C, co-simulation, or
transactors
C-based verification is often used in early stages of
design or when performance and portability are critical.
1.2 Why C/C++ for Verification?
C and C++ offer several benefits when used for
hardware verification:
High simulation speed: Compiled C programs are
generally faster than RTL simulation.
Platform independence: Easy to run tests on any
OS with a compiler.
Rich libraries: Access to standard C/C++ libraries
and third-party tools (e.g., file I/O, math, STL).
Golden reference models: Useful for bit-accurate
algorithm comparison.
Reuse of existing code: Algorithms or drivers from
software teams can be reused in verification.
Good for algorithm-heavy blocks: Particularly for
signal processing, compression, encryption units,
etc.
1.3 Advantages of C-Based Verification
Faster simulation of algorithm-level and software-
oriented logic
Reusable in both hardware and embedded software
development
Better debugging with standard software tools like
GDB
Ideal for bit-accurate reference models
Easier transition for software engineers entering
hardware design
1.4 Limitations of C-Based Verification
Not timing-aware: Cannot model cycle-accurate or
timing-specific behavior
Manual RTL interface setup: Need DPI-C, PLI, or
other integration
Less integration with coverage and assertions tools
Limited adoption in structured verification
environments like UVM
Verification Flow Using C
C-based verification fits into the functional verification
phase of digital design, particularly during pre-silicon
validation, algorithm testing, and high-level simulation.
This chapter covers how C integrates into the overall
design verification flow and elaborates on its critical use
cases.
2.1 High-Level Architecture
Below is a simplified architecture diagram of C-based
verification
C Testbench RTL Simulator RTL Design
Reference DPI-C
Model Interface
Main Elements:
C/C++ Testbench generates stimulus and checks
output.
RTL Design written in Verilog or VHDL.
DPI-C (Direct Programming Interface - C) links the
RTL simulator and C code.
Reference Model in C/C++ acts as a golden output
generator.
2.2 Where C Fits in the Design & Verification Cycle
Here’s how C-based verification fits into the broader
ASIC/FPGA development cycle:
Design Stage Role of C-Based Verification
Specification Model functionality in C/C++
Architecture Algorithm prototyping
RTL Design Compare RTL outputs with C-model
RTL Verification Co-simulation, testbench development
Validation Software-hardware integration testing
At early stages, designers often implement functionality
in C to validate data flow, algorithm correctness, and
edge cases. Once the RTL is ready, the C model
becomes the reference for comparing the actual design
behavior.
2.3 Common Use-Cases of C-Based Verification
2.3.1 Algorithm Validation
Many hardware blocks implement complex algorithms,
especially in domains like:
Digital Signal Processing (DSP)
Cryptography (AES, SHA, RSA)
Image processing
Compression (JPEG, H.264)
Why C?
C/C++ is great for rapid prototyping.
Enables algorithm tuning and optimization.
Example:
You can implement an AES encryption block in C and
validate its functionality before writing the RTL. This
ensures the core logic is functionally correct.
2.3.2 Reference Model (Golden Model) Creation
A golden reference model is a bit-accurate C/C++
implementation of the hardware design.
Role of the Golden Model:
Acts as the standard for verifying RTL outputs.
Accepts same inputs as RTL, produces expected
outputs.
Helps detect RTL bugs during simulation.
Implementation Notes:
Needs to be cycle-accurate (if possible) or at least
bit-accurate.
Often written in pure C or C++.
Integrated with the testbench to compare outputs
dynamically.
Example Use:
If the RTL output differs from the C model's output,
the testbench raises a flag.
2.3.3 Testbench Development
In C-based verification, the testbench is written in
C/C++ to:
Apply stimulus to the DUT.
Monitor outputs.
Perform checks against expected values (from
golden model).
Log errors or results.
Features of a C Testbench:
Procedural code (functions, loops, etc.)
Supports constrained random inputs, file-based
inputs, directed tests
Works with file I/O for vectors, stimulus patterns
Advantages:
Faster execution than HDL testbenches
Easy to write and extend for software engineers
Example:
for (int i = 0; i < 1000; i++) {
input = rand() % 256;
expected = golden_model(input);
output = call_rtl_dut(input); // via DPI
if (output != expected) {
printf("Mismatch at %d: expected %d, got %d\n", i,
expected, output);
}
}
2.3.4 Driver/Monitor Implementation for Simulation
To interface C testbenches with RTL simulators like
ModelSim, VCS, or Questa, DPI-C is commonly used.
Driver Role:
Converts C data into HDL signals.
Drives the input ports of the DUT (Design Under
Test).
Monitor Role:
Reads output signals from the DUT.
Sends them back to C for checking.
Using DPI-C Interface:
import and export DPI-C functions in
SystemVerilog.
C functions compiled with gcc or g++ and linked to
the simulator.
Handles data exchange, memory allocation
Example SystemVerilog-DPI Call:
import "DPI-C" function int add_in_c(int a, int b);
module dut_test;
initial begin
$display("Result: %0d", add_in_c(5, 7));
end
endmodule
// C implementation
#include <stdio.h>
int add_in_c(int a, int b) {
return a + b;
}
Conclusion
C-based verification enables early and fast validation of
algorithms, supports golden model creation, and
interfaces well with RTL using DPI-C. Its lightweight and
efficient approach makes it ideal for the functional
verification of algorithmic blocks, long before RTL is
complete.
Components of C-Based
Verification
C-based verification involves multiple modular
components that work together to verify a hardware
design. Each component serves a distinct purpose and
communicates through well-defined interfaces. Let’s
explore each component in detail:
3.1 DUT (Design Under Test) Interface
Definition: The DUT is the RTL hardware module
(written in Verilog/VHDL) being verified.
Interface Role: In C-based verification, the DUT is
exposed to the C environment using SystemVerilog
DPI-C or other cosimulation mechanisms.
Interaction: The testbench written in C/C++
interacts with the DUT via simulation or API layers,
sending inputs and receiving outputs.
3.2 Testbench in C
Purpose: Acts as the stimulus generator and output
checker.
Functionality:
Initializes test data.
Drives inputs to the DUT through driver functions.
Collects DUT outputs for validation.
Flexibility: You can reuse algorithm code, automate
corner-case testing, and integrate pre-existing
libraries.
3.3 Drivers and Monitors
Drivers:
Convert high-level testbench commands into
DUT-compatible transactions.
Feed inputs into the DUT via DPI functions or
simulator APIs.
Monitors:
Observe DUT outputs and capture them for
analysis.
Translate low-level DUT responses back into C-
readable structures.
Analogy: Similar to UVM drivers/monitors but
implemented in C with function calls and buffers.
3.4 Scoreboards and Checkers
Scoreboard:
Collects expected vs. actual outputs.
Keeps a record of transaction-level
comparisons.
Checkers:
Evaluate if DUT output matches reference
model results.
Often implemented as assertions or custom
comparison logic in C.
3.5 Reference Models
Definition: A high-level C/C++ model of the DUT’s
expected functionality.
Purpose: Provides a "golden" output for each input,
serving as a correctness oracle.
Use-cases:
Early algorithm development.
Comparison baseline during verification.
Shared reference across simulation and
emulation.
Typical Tools and Environments
C-based verification is supported by a rich ecosystem of
compilers, simulators, and debug tools. Here’s a
breakdown of the commonly used ones:
1. GCC, G++, Clang
GCC/G++: Standard GNU C/C++ compilers.
Clang: LLVM-based C/C++ compiler with advanced
static analysis.
Purpose: Compile the C/C++ testbench, reference
model, and other components.
Benefits: Fast, widely supported, good integration
with IDEs and CI pipelines.
2. Simulators
ModelSim:
Popular RTL simulator.
Supports DPI-C interface for integration with
C/C++.
Synopsys VCS:
Industry-grade simulator.
Strong support for C-based verification via DPI.
Cadence Xcelium: Also supports cosimulation with C
via DPI and other interfaces.
3. Integration with SystemVerilog via DPI-C
DPI-C (Direct Programming Interface - C):
Enables communication between C/C++ and
SystemVerilog modules.
C functions can be called from Verilog and vice
versa.
Use Cases:
Calling reference models from Verilog
testbenches.
Driving Verilog DUTs using C testbenches.
4. Cosimulation Tools
SystemC + Verilog: Using simulators with
cosimulation kernels.
Mentor’s Questa Cosimulation: Supports
synchronized simulation of C/SystemC and Verilog.
Synopsys’ CVer + VCS: Common in commercial SoC
verification flows.
5. Debugging Tools
GDB (GNU Debugger): For line-by-line debugging of
C/C++ code.
Valgrind: Useful for memory checking and profiling.
Simulators’ Debug Consoles: For watching signals
and tracing RTL-level activity.
Waveform Viewers (e.g., GTKWave, SimVision): To
visualize signal changes and cross-reference with C
testbench logs.
Case Study – Advanced Example
Project
C-BASED VERIFICATION OF HIGH-PERFORMANCE
AXI4-BASED IMAGE PROCESSING IP
Project Overview
Goal: Verify a complex image processing IP that
implements a Sobel filter, integrated over an AXI4-
based interface, using a C-based testbench and
golden model.
RTL Design:
Written in SystemVerilog.
Uses AXI4-Lite for control and AXI4-Stream for
pixel data.
Includes line buffers, convolution kernel, edge
detection, and DMA controller.
Verification Strategy
Language & Tools:
C++ for testbench and golden model.
SystemVerilog RTL.
VCS simulator + DPI-C for integration.
Debug: GDB, DVE waveform viewer.
Testbench Setup in C++:
Stimulus Generator: Reads input .bmp image and
feeds pixel stream.
AXI Driver: Writes to control registers via AXI-Lite.
AXI Monitor: Captures processed pixel stream
output.
Reference Model: Pure C++ Sobel filter algorithm.
Scoreboard: Compares RTL output to reference
model output pixel by pixel.
Component Description
DUT RTL-based Image Processing IP
Protocol AXI4-Stream for data input/output
High-level C/C++ model using
Reference Model OpenCV or hand-written pixel-
based logic
C program to read images, send
Testbench data to RTL via DPI, receive output,
compare
VCS / ModelSim / XSIM with DPI-C
Simulator
Integration
GDB, GTKWave (for waveform),
Debug Tools OpenCV visual diff (for image
comparison)
1. Image Input & Preprocessing in C:
Read grayscale or RGB image using OpenCV or plain C.
Resize if necessary and convert to pixel stream format
(e.g., row-major 8-bit per pixel).
uint8_t image[IMG_HEIGHT][IMG_WIDTH];
fread(image, sizeof(uint8_t), IMG_HEIGHT * IMG_WIDTH, fp);
2. Reference Model (Golden Model):
Apply a 3x3 Gaussian filter using floating-point or
integer convolution.
Written in C/C++, optionally accelerated with OpenCV.
uint8_t reference[IMG_HEIGHT][IMG_WIDTH];
apply_gaussian_filter(image, reference);
3. Driving the RTL via DPI-C:
Use DPI-C to send pixel data from the C testbench
to RTL AXI-Stream input port.
Collect processed pixel data from AXI output port
into a C array.
// Example DPI calls (pseudocode)
dpi_send_pixel(uint8_t pixel); // drives AXIS input
uint8_t dpi_receive_pixel(); // collects output from AXIS output
for (int i = 0; i < IMG_HEIGHT * IMG_WIDTH; i++) {
dpi_send_pixel(image[i / IMG_WIDTH][i % IMG_WIDTH]);
out[i / IMG_WIDTH][i % IMG_WIDTH] = dpi_receive_pixel();
}
4. Comparison and Image Validation:
Compare the output image from RTL with the
golden model pixel-by-pixel.
Allow for a tolerance margin if fixed-point errors are
expected.
int error_count = 0;
for (int y = 0; y < IMG_HEIGHT; y++) {
for (int x = 0; x < IMG_WIDTH; x++) {
if (abs(out[y][x] - reference[y][x]) > 2) {
printf("Mismatch at (%d, %d): DUT=%d Ref=%d\n", x, y,
out[y][x], reference[y][x]);
error_count++;
}
}
}
This case study demonstrates how C-based verification
can be extended to real-world, protocol-based, high-
performance RTL designs, offering:
Fast prototyping via DPI.
High-level stimulus generation using OpenCV.
Fast regression for different image types.
Seamless RTL + algorithm co-verification.
Advanced Practice Questions
Explain how you would implement a coverage-driven
verification environment using C in conjunction with
hardware simulators. What are the challenges and
benefits?
Design a strategy for verifying a complex pipelined
processor using C-based verification techniques. How
would you handle pipeline hazards and out-of-order
execution in your testbench?
Describe how you can leverage Transaction-Level
Modeling (TLM) in C++ for early functional verification
of hardware blocks before RTL is available.
Discuss the role of C-based verification in
hardware/software co-design and co-verification.
Provide examples where this integration improves
verification efficiency.
Explain how functional coverage and assertion
coverage can be collected and analyzed in a C-based
verification framework. What tools or methodologies
would you integrate?
Design a testbench framework in C that supports
constrained random stimulus generation for an AXI
bus interface. How would you implement constraints
and checkers?
Advanced Practice Questions
How can you integrate machine learning techniques
into a C-based verification environment to optimize
test stimulus generation? Discuss the potential
benefits and challenges.
Compare and contrast SystemVerilog UVM with a C-
based verification environment for verifying a
complex SoC. Discuss trade-offs in terms of
scalability, maintainability, and speed.
Describe an approach to verify asynchronous FIFO
designs using C-based verification methods, including
how you would model and detect metastability
issues.
Propose a hybrid verification methodology combining
formal verification and C-based simulation. How
would you architect the verification environment to
leverage the strengths of both approaches?
How would you use C/C++ with SystemC to model
hardware behavior at a high level? What are the
advantages of using SystemC in functional
verification?
Develop a C-based methodology for stimulus
generation, result checking, and regression testing
for a parameterized ALU module.
Advanced Practice Questions
In a mixed-language simulation environment, how
can synchronization be handled between a C-based
testbench and a Verilog/VHDL DUT?
Explain how dynamic memory allocation and pointer
manipulation in C can help in building reusable and
modular testbenches. Provide a use-case.
How would you handle clock and reset generation in
a C-based verification environment when the DUT is a
synthesizable Verilog block?
Discuss the interfacing of C-based testbenches with
commercial HDL simulators like ModelSim, VCS, or
NC-Sim. What are the typical APIs or protocols used?
Propose a strategy to validate a complex interrupt
controller using C. How would you verify edge/level
triggering and priority resolution mechanisms?
How can you use C++ polymorphism and inheritance
to develop a scalable verification environment for a
family of IP cores with similar functionality?
Illustrate how multithreading in C/C++ can be utilized
to mimic concurrent test scenarios in hardware
verification. What synchronization mechanisms must
be used?
Advanced Practice Questions
You are verifying a custom memory controller using
C. How would you model memory timing, latency,
burst operations, and error conditions in your
testbench?
How would you verify a DMA controller using C-based
verification techniques? Outline how you'd test
memory-to-memory, memory-to-peripheral, and
peripheral-to-memory transfers.
Design a scoreboard mechanism in C to compare
expected and actual outputs from a DUT. How would
you handle timing mismatches and out-of-order
data?
Explain the use of callback mechanisms in C for
inserting checkers, monitors, or functional coverage
in your verification framework.
How would you implement a layered verification
architecture in C (similar to UVM) for modularity and
reusability? Illustrate with components like drivers,
monitors, and agents.
Describe how you can build a protocol checker in C
for a custom communication protocol. What steps
would you follow to ensure compliance and
robustness?
Advanced Practice Questions
What mechanisms would you use to inject faults or
perturbations into a C-based verification testbench to
perform fault injection testing of a hardware module?
You are verifying a hardware encryption accelerator.
How would you integrate reference models (e.g., in
OpenSSL) into your C-based verification strategy?
How can C/C++ STL containers (like vectors, queues,
maps) be effectively used in modeling stimulus
generation and output comparison in a testbench?
Explain how to create a reusable C/C++ testbench
infrastructure that supports command-line
configuration, test selection, and result logging.
Discuss how you would integrate third-party C
libraries (e.g., JSON, CSV parsers) into your testbench
for dynamic test configuration and automated results
analysis.
How would you verify a hardware multiplier using
both directed and random stimulus in C? Discuss the
methods you’d use to handle corner cases.
Describe how you can simulate back-pressure and
flow control mechanisms in C when verifying a data
streaming interface (like AXI-Stream).
Propose a structure for building a C-based golden
reference model for an instruction decoder. How
would you validate correctness and performance?
Advanced Practice Questions
How would you verify a priority arbiter in C when the
number of request lines is dynamically configurable
at runtime?
Discuss the challenges in verifying asynchronous clock
domain crossings (CDC) using C. How would you
model synchronization and metastability?
How can you simulate power-aware verification
scenarios (like power gating or dynamic frequency
scaling) using C testbenches and behavioral models?
Design a debug-friendly C-based verification
environment where errors can be traced using logs,
assertions, and runtime diagnostics.
How would you implement a coverage collector in C
that logs functional coverage across test runs and
generates a simple report in JSON or CSV?
You are testing a packet router module. How would
you simulate network congestion, packet loss, and
reordering in C to stress the design?
Compare the scalability of C-based verification
frameworks with UVM when dealing with verification
of a multi-core processor. What are the design trade-
offs?
How would you structure a layered packet generator
in C to verify a network protocol stack (e.g., Ethernet
+ IP + UDP)?
Advanced Practice Questions
Design a regression test infrastructure in C that can
execute multiple test cases, capture pass/fail status,
and generate a summary report.
Explain how you would perform latency and
throughput analysis in C for a hardware
communication channel. Include measurement
techniques.
How can you simulate bursty traffic patterns in a C
testbench to validate a FIFO-based design under
stress conditions?
Propose a technique to implement error injection and
detection (e.g., bit flips, parity errors) in a C-based
memory testbench.
How would you apply Design for Testability (DFT)
concepts like scan chains or BIST in your C-based test
framework?
Describe the steps to integrate a cycle-accurate
hardware emulator with a high-level C testbench for
real-time verification.
You are building a testbench for an image processing
pipeline (e.g., edge detection). How would you
integrate image input/output handling in C?
Advanced Practice Questions
What synchronization models and APIs (e.g., POSIX
threads, semaphores) would you use in a C-based
multi-threaded testbench to mimic bus arbitration
scenarios?
How would you develop a reference model in C for a
hardware floating-point unit (FPU)? What special
cases must you account for in validation?
Excellence in World class
VLSI Training & Placements
Do follow for updates & enquires
+91- 9182280927