-
Notifications
You must be signed in to change notification settings - Fork 0
Simulation
Advanced simulation techniques and analysis tools.
GHDL is an open-source VHDL compiler and simulator. It provides:
- Analysis: Syntax checking and compilation
- Elaboration: Design linking and instantiation
- Simulation: Event-driven waveform simulation
- Waveform Export: VCD, GHW formats for analysis
# Analyze (compile) source files
ghdl -a [options] file1.vhd file2.vhd
# Elaborate (link design)
ghdl -e [options] entity_name
# Simulate (run)
ghdl -r [options] entity_name [runtime options]--std=08 Use VHDL-2008 standard
--ieee=synopsys Enable Synopsys extensions
-fsynopsys (deprecated, use --ieee=synopsys)
--wave=file.ghw Export waveforms in GHW format
--stop-time=10ms Stop simulation after 10ms
--vcd=file.vcd Export waveforms in VCD format
GHW Format (native GHDL):
ghdl -r tb_sbc_bus_write --wave=tb_sbc_bus_write.ghwVCD Format (standard, portable):
ghdl -r tb_sbc_bus_write --vcd=tb_sbc_bus_write.vcdBoth Formats:
ghdl -r tb_sbc_bus_write --wave=wave.ghw --vcd=wave.vcdView waveforms with GTKWave (separate tool):
gtkwave tb_sbc_bus_write.ghw >KWave Features:
- Pan/zoom along time axis
- Add/remove signals to display
- Search for signal transitions
- Measure timing between events
- Save/load views as .gtkw files
Bus Signals:
-
addr: CPU address bus (when it changes, which device is selected) -
data_out: CPU output data (during writes) -
data_in/cpu_din: Read data from peripherals
Control Signals:
-
clk: System clock (verify edges align with data stability) -
reset_n: Reset sequence (should be low then high) -
we: Write enable (strobes for writes)
Peripheral Signals:
- VIA:
via_cs,via_dout,via_irq,porta_out,portb_out - UART:
uart_cs,uart_dout,uart_tx_valid,uart_tx_data
Insert report statements in testbenches:
process
begin
report "Test starting" severity note;
addr <= x"0000";
wait for 1 ns;
report "addr = " & to_hstring(addr) severity note;
if sel /= DEV_SRAM then
report "ERROR: Expected DEV_SRAM, got " & device_sel_t'image(sel)
severity error;
end if;
wait;
end process;Test one component at a time:
-- Instead of full sbc_top, test just bus_decode
test_only_bus_decode: if true generate
dut: entity work.bus_decode ...
end generate;Measure propagation delays:
-- Measure delay from address change to output change
addr <= x"0000";
wait for 0 ns; -- Combinational logic settles
assert sel = DEV_SRAM report "Delay too long?" severity warning;Print signal values at key times:
wait for 100 ns;
report "t=100ns: addr=" & to_hstring(addr) &
" sel=" & device_sel_t'image(sel) severity note;Full test suite on typical machine:
- Analysis (compilation): ~1-2 seconds
- Elaboration (linking): <1 second per testbench
- Simulation: <1 second per test (300-1000 ns virtual time)
GHDL simulation typically uses:
- Simple testbenches: 50-100 MB
- Full system simulation: 100-200 MB
- Increase available memory if simulations crash
Reduce verbosity:
-- Remove report statements in loops
-- Keep only essential assertionsShorter test sequences:
-- Test only the failing condition, not entire flow
-- Use targeted stimulus instead of comprehensive testsDisable unused components:
-- Comment out instantiation of unused peripherals
-- Reduces elaboration and simulation timeTest synchronous vs asynchronous behavior:
-- Synchronous: data valid at clock edge
wait until rising_edge(clk);
assert data_out = expected_value
report "Data not ready at clock edge" severity error;
-- Asynchronous: data valid combinationally
wait for 0 ns; -- Allow combinational logic to settle
assert data_out = expected_value
report "Combinational path failed" severity error;Test proper reset behavior:
-- Reset assertion
reset_n <= '0';
wait for 100 ns;
-- Verify all outputs are reset
assert counter = 0 report "Counter not cleared" severity error;
assert output = (others => '0') report "Output not cleared" severity error;
-- Reset release
reset_n <= '1';
wait for 100 ns;
-- Verify system is ready
assert ready = '1' report "System not ready after reset" severity error;Test operations spanning multiple clock cycles:
-- Cycle 1: Issue command
cmd_valid <= '1';
cmd_data <= x"42";
wait until rising_edge(clk);
-- Cycle 2: Command accepted
cmd_valid <= '0';
assert busy = '1' report "Device not busy" severity error;
wait until rising_edge(clk);
-- Cycle 3: Result ready
assert busy = '0' report "Device still busy" severity error;
assert result = x"84" report "Incorrect result" severity error;Test interrupt assertion and servicing:
-- Wait for interrupt assertion
wait until irq = '1' report "IRQ never asserted" severity error;
-- Service interrupt
acknowledge <= '1';
wait until rising_edge(clk);
acknowledge <= '0';
-- Verify IRQ deasserts
wait for 10 ns;
assert irq = '0' report "IRQ not cleared" severity error;-
Time Scale: Set appropriate resolution
- For nanosecond timing, use ns unit
- For microsecond processes, use us unit
-
Zoom Levels:
- Zoom out (ns/div) to see overall flow
- Zoom in (ps/div) for detailed timing
-
Cursor Markers:
- Set markers at key events
- Measure timing between markers
- Hierarchy: Expand to see all signals
- Filter: Search for signals by name
- Grouping: Organize related signals
- Bus Display: Show bus values in decimal/hex
Add text notes to waveform to document:
- Expected vs actual behavior
- Timing violations
- Anomalies or interesting events
Before committing:
cd fpga/
make clean
make testAll tests must PASS.
Example workflow:
name: GHDL Simulation Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install GHDL
run: sudo apt-get install ghdl
- name: Run simulation tests
run: cd fpga && make testCause: Unbounded loop or missing wait
Solution:
- Check testbench for
while truewithoutwait - Use
--stop-timeto force termination - Add timeout conditions
ghdl -r tb_test --stop-time=1msIssue: Process triggers spuriously
Solution: Ensure sensitivity list matches variable dependencies
-- Wrong: only a in sensitivity list
process(a)
begin
c <= a and b; -- Misses b changes
end process;
-- Correct: all inputs in sensitivity list
process(a, b)
begin
c <= a and b; -- Triggers on a or b change
end process;Problem: Waveform file too large
Solution:
- Reduce simulation time:
--stop-time=1ms - Use binary format:
--wave=wave.ghw(smaller than VCD) - Filter signals: Export only needed signals
Debug multi-condition failures:
-- Instead of:
assert (a = 1) and (b = 2) and (c = 3)
report "Complex assertion failed" severity error;
-- Use:
assert a = 1 report "a is not 1" severity error;
assert b = 2 report "b is not 2" severity error;
assert c = 3 report "c is not 3" severity error;See Also:
- Testing Guide - Test structure
- Building & Synthesis - Compilation
- Development Guide - Contributing
Generated from 6502-sbc-fpga Markdown documentation. Part of the 6502 SBC emulator project (emulator Wiki).