Капстоун: что запускается дальше
Вы узнаете
Как куски курса сходятся в один дизайн и что запускается на стенде дальше.
Закройте курс там, где он начался, — у целого дизайна: top_level.t27 несёт CLK_FREQ_HZ 100,000,000, SYSTICK_HZ 1000, NUM_MAC_UNITS 8, DATA_WIDTH 32 и коды операций CMD_NOP, CMD_MAC_MULT, CMD_MAC_DOT и CMD_UART_SEND — девятнадцать тестов дизайна, который держит все шины, разобранные этим курсом. Запись читает, что стенд запускает дальше; боковые кнопки опускают весь дизайн в Verilog — и его верхний стенд вместе с ним.
Попробовать
В записи прочитайте, что запускается дальше; затем в спеке найдите четыре кода операций и посчитайте тесты дизайна.

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
}
Все уроки
Модуль 1 · Что такое шина
Зачем вообще существует шина: разговор по проводам, с кадрами и адресами, и кому позволено говорить.
Модуль 2 · Разговор по UART
Двухпроводная шина без такта: кадр, делитель, задающий скорость, и статус, который опрашивает драйвер.
Модуль 3 · SPI под тактом
Разговор под тактом: четыре режима, лестница предделителей и выбор кристалла на каждого подчинённого.
Модуль 4 · Регистровая шина APB
Шина регистров: PSEL и PENABLE, строобы и ожидания, и сколько адресных бит стоит количество периферии.
Модуль 5 · Пять каналов AXI4
Пять каналов: адрес, данные и отклик в обе стороны, lite или full, пакеты и идентификаторы.
Модуль 6 · Память
Что находится на дальнем конце каждой шины: карты памяти, типы портов и задержка, которую должно покрывать ожидание.
Модуль 7 · Мосты
Почему в дизайне появляется больше одной шины и пакетный мост, переносящий работу между ними.
Модуль 8 · Ethernet: кадры и тайминг
Кадры, контрольная сумма кадра, тайминг RGMII и заранее зарегистрированные шаги настоящего запуска.
Модуль 9 · Стенд
Дисциплина, оберегающая настоящее железо: кто держит IO, как взять и вернуть захват, и что запускается дальше.