t27.aiРусский

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.

Open the interactive lesson →

tri fpga-next -- what the bench wants next
tri fpga-next -- what the bench wants next ↗

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
}

Open the lesson's spec in the player ↗

All lessons