Capstone: what runs next
You will learn
How the pieces of this course meet in one design, and what runs next on the bench.
Close the course where it started, at the whole design: top_level.t27 carries CLK_FREQ_HZ 100,000,000, SYSTICK_HZ 1000, NUM_MAC_UNITS 8, DATA_WIDTH 32, and the opcodes CMD_NOP, CMD_MAC_MULT, CMD_MAC_DOT and CMD_UART_SEND -- nineteen tests of the design that holds every bus this course took apart. The recording reads what the bench runs next; the also-chips lower the whole design to Verilog, and its top bench with it.
Try it
In the recording, read what runs next; then in the spec frame find the four opcodes and count the design's tests.

The next queued step on the bench, read live from the run state.
specs/fpga/top_level.t27
// SPDX-License-Identifier: Apache-2.0
// t27/specs/fpga/top_level.t27
// ZeroDSP FPGA Top Level Module
// Integrates MAC and UART for FPGA deployment
// φ² + 1/φ² = 3 | TRINITY
module ZeroDSP_TopLevel {
use base::types;
use base::ops;
use isa::registers;
const CLK_FREQ_HZ : u32 = 100_000_000;
const SYSTICK_HZ : u32 = 1000;
const NUM_MAC_UNITS : usize = 8;
const DATA_WIDTH : usize = 32;
const CMD_NOP : u8 = 0;
const CMD_MAC_MULT : u8 = 1;
const CMD_MAC_DOT : u8 = 2;
const CMD_UART_SEND : u8 = 3;
const CMD_RESET : u8 = 0xFF;
struct SystemState {
mac_ready : bool,
uart_ready : bool,
processing : bool,
error : bool,
}
var system_state : SystemState = SystemState{
.mac_ready = true,
.uart_ready = true,
.processing = false,
.error = false,
};
var mac_result : i32 = 0;
var uart_tx_data : u8 = 0;
fn system_init() -> void {
system_state.mac_ready = true;
system_state.uart_ready = true;
system_state.processing = false;
system_state.error = false;
}
fn system_ready() -> bool {
return system_state.mac_ready and system_state.uart_ready;
}
fn system_busy() -> bool {
return system_state.processing;
}
fn system_error() -> bool {
return system_state.error;
}
fn system_reset() -> void {
system_init();
mac_result = 0;
uart_tx_data = 0;
}
fn set_mac_result(value: i32) -> void {
mac_result = value;
system_state.processing = false;
}
fn get_mac_result() -> i32 {
return mac_result;
}
fn set_uart_data(data: u8) -> void {
uart_tx_data = data;
}
fn get_uart_data() -> u8 {
return uart_tx_data;
}
fn start_processing() -> void {
if (system_ready()) {
system_state.processing = true;
}
}
fn stop_processing() -> void {
system_state.processing = false;
}
fn set_error() -> void {
system_state.error = true;
system_state.processing = false;
}
fn clear_error() -> void {
system_state.error = false;
}
test system_initially_ready
given ready = system_ready()
then ready == true
test system_initially_not_busy
given busy = system_busy()
then busy == false
test system_initially_no_error
given error = system_error()
then error == false
test system_reset_clears_state
given set_error()
and system_reset()
and ready = system_ready()
and error = system_error()
then ready == true and error == false
test start_processing_sets_busy
given start_processing()
and busy = system_busy()
then busy == true
test stop_processing_clears_busy
given start_processing()
and stop_processing()
and busy = system_busy()
then busy == false
test set_error_clears_busy
given start_processing()
and set_error()
and busy = system_busy()
and error = system_error()
then busy == false and error == true
test get_mac_result_after_set
given set_mac_result(42)
and result = get_mac_result()
then result == 42
test get_uart_data_after_set
given set_uart_data(0xAA)
and data = get_uart_data()
then data == 0xAA
test mac_result_clears_processing
given start_processing()
and set_mac_result(100)
and busy = system_busy()
then busy == false
test constants_clk_freq
then CLK_FREQ_HZ == 100_000_000
and SYSTICK_HZ == 1000
and NUM_MAC_UNITS == 8
and DATA_WIDTH == 32
test command_constants
then CMD_NOP == 0
and CMD_MAC_MULT == 1
and CMD_MAC_DOT == 2
and CMD_UART_SEND == 3
and CMD_RESET == 0xFF
test system_reset_clears_mac_result
given set_mac_result(999)
and system_reset()
then get_mac_result() == 0
test system_reset_clears_uart_data
given set_uart_data(0xFF)
and system_reset()
then get_uart_data() == 0
test clear_error_does_not_affect_ready
given set_error()
and clear_error()
then system_error() == false
and system_ready() == true
test start_processing_requires_ready
given system_state.mac_ready = false
then system_ready() == false
test set_mac_result_negative
given set_mac_result(-42)
then get_mac_result() == -42
test set_uart_data_boundary
given set_uart_data(0)
then get_uart_data() == 0
given set_uart_data(255)
then get_uart_data() == 255
test system_init_resets_state
given system_init()
and ready = system_ready()
and busy = system_busy()
and error = system_error()
then ready == true
and busy == false
and error == false
invariant system_ready_when_not_processing
given busy = system_busy()
and ready = system_ready()
assert busy == true or ready == true
invariant system_error_implies_not_busy
given error = system_error()
and busy = system_busy()
assert error == false or busy == false
invariant system_ready_implies_mac_uart_ready
given ready = system_ready()
assert ready == false or system_state.mac_ready == true
// Implementation: call the function to measure its latency
bench system_ready_latency
measure: nanoseconds to system_ready()
target: < 20ns
// Implementation: call the function to measure its latency
bench system_reset_latency
measure: nanoseconds to system_reset()
target: < 100ns
}
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.