Everything in one bench
You will learn
What an integration bench checks when every bus of the design is driven at once.
An integration bench drives every bus at once and asks the design to hold together: test_reset_all_modules, test_module_count, test_mac_uart_pipeline, test_spi_memory_pipeline, test_full_pipeline, seven tests. The recording lowers the integration testbench spec to Verilog: every bus of the design in one bench.
Try it
In the recording, find the five pipeline tests; then in the spec frame say which two buses the integration bench joins.

The integration testbench spec lowered to Verilog: every bus of the design in one bench.
specs/fpga/testbench/integration_tb.t27
// SPDX-License-Identifier: Apache-2.0
// t27/specs/fpga/testbench/integration_tb.t27
// Full FPGA Integration Testbench
// Tests top-level connectivity: MAC + UART + SPI + Memory + Bridge
// phi^2 + 1/phi^2 = 3 | TRINITY
module Integration_Testbench {
const CLK_PERIOD : u32 = 20;
const SIM_TIMEOUT : u32 = 20_000_000;
const NUM_MODULES : u32 = 5;
var clk : bool = false;
var rst_n : bool = false;
var mac_busy : bool = false;
var uart_tx_ready : bool = false;
var spi_done : bool = false;
var mem_ready : bool = false;
var bridge_busy : bool = false;
var all_modules_idle : bool = false;
var integration_passed : bool = false;
var test_passed : u32 = 0;
var test_failed : u32 = 0;
fn tick() {
clk = false;
clk = true;
}
fn reset() {
rst_n = false;
tick();
tick();
rst_n = true;
tick();
}
fn check_all_idle() -> bool {
return !mac_busy && uart_tx_ready && spi_done && mem_ready && !bridge_busy;
}
test test_reset_all_modules {
reset();
all_modules_idle = check_all_idle();
invariant all_modules_idle == true;
}
test test_module_count {
invariant NUM_MODULES == 5;
}
test test_mac_uart_pipeline {
reset();
mac_busy = true;
tick();
tick();
mac_busy = false;
uart_tx_ready = true;
tick();
invariant uart_tx_ready == true;
}
test test_spi_memory_pipeline {
reset();
spi_done = false;
tick();
tick();
spi_done = true;
mem_ready = true;
tick();
invariant mem_ready == true;
}
test test_full_pipeline {
reset();
mac_busy = true;
tick();
mac_busy = false;
uart_tx_ready = true;
tick();
spi_done = true;
mem_ready = true;
bridge_busy = true;
tick();
bridge_busy = false;
all_modules_idle = check_all_idle();
invariant all_modules_idle == true;
integration_passed = true;
}
test test_stress_pipeline {
reset();
var i : u32 = 0;
while i < 10 {
mac_busy = true;
tick();
mac_busy = false;
uart_tx_ready = true;
tick();
spi_done = true;
mem_ready = true;
bridge_busy = true;
tick();
bridge_busy = false;
i = i + 1;
}
all_modules_idle = check_all_idle();
invariant all_modules_idle == true;
}
invariant num_modules_positive : NUM_MODULES > 0;
test test_tick_function {
reset();
var initial_clk : bool = clk;
tick();
invariant clk == !initial_clk;
}
bench bench_integration_throughput {
reset();
var i : u32 = 0;
while i < 50 {
mac_busy = true;
tick();
mac_busy = false;
uart_tx_ready = true;
tick();
i = i + 1;
}
}
}
All lessons
Module 1 · What a bus is
Why a bus exists at all: a conversation on wires, framed and addressed, and who is allowed to talk.
Module 2 · UART
The two-wire bus with no clock: the frame, the divisor that sets the rate, and the status a driver polls.
Module 3 · SPI
The clocked conversation: four modes, a prescaler ladder, and a chip select per servant.
Module 4 · APB
The register bus: PSEL and PENABLE, strobes and wait states, and how many address bits a peripheral count costs.
Module 5 · AXI4
The five channels: address, data and response in both directions, lite or full, bursts and IDs.
Module 6 · Memory
What sits on the far side of every bus: memory maps, port kinds, and latency that a wait state must cover.
Module 7 · Bridges
Why designs grow more than one bus, and the packet bridge that moves work between them.
Module 8 · Ethernet
Frames, the frame check sequence, RGMII timing, and the pre-registered steps of a real bring-up.
Module 9 · The bench
The discipline that guards real hardware: who holds the IO, taking and giving the lock, and what runs next.