diff --git a/rtl/controller/src/axi4l_reg_map_controller.sv b/rtl/controller/src/axi4l_reg_map_controller.sv index cf02244..24a42e3 100644 --- a/rtl/controller/src/axi4l_reg_map_controller.sv +++ b/rtl/controller/src/axi4l_reg_map_controller.sv @@ -51,7 +51,7 @@ module axi4l_reg_map_controller #( input logic busy_i, input logic [7:0] error_code_i ); - import axi4l_reg_map_example_pkg::*; + import axi4l_reg_map_controller_pkg::*; localparam int unsigned N_REGS = AXI4L_REG_MAP_EXAMPLE_N_REGS; logic [N_REGS-1:0][31:0] reg_i; diff --git a/rtl/controller/tests/tb_controller_wrapper_axil.sv b/rtl/controller/tests/tb_controller_wrapper_axil.sv index 91a64d5..8458e25 100644 --- a/rtl/controller/tests/tb_controller_wrapper_axil.sv +++ b/rtl/controller/tests/tb_controller_wrapper_axil.sv @@ -1,8 +1,22 @@ module tb_controller_wrapper_axil #( - parameter int unsigned DAC_DATA_WIDTH = 12, - parameter int unsigned ADDR_W = 16, - parameter int unsigned DATA_W = 32, - parameter int unsigned USER_W = 1 + parameter int unsigned ADDR_W = 16, + parameter int unsigned DATA_W = 32, + parameter int unsigned USER_W = 1, + + parameter int unsigned DAC_DATA_WIDTH = 12, + + parameter int unsigned AXI_ADDR_WIDTH = 16, + parameter int unsigned AXIS_ID_WIDTH = 8, + parameter int unsigned LEN_WIDTH = 20, + parameter int unsigned AXIS_USER_WIDTH = 1, + parameter int unsigned AXIS_DEST_WIDTH = 8, + parameter int unsigned TAG_WIDTH = 8, + + parameter int unsigned READ_DESC_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH + AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH, + parameter int unsigned WRITE_DESC_WIDTH = AXI_ADDR_WIDTH + LEN_WIDTH + TAG_WIDTH, + + parameter int unsigned READ_STATUS_WIDTH = TAG_WIDTH + 4, + parameter int unsigned WRITE_STATUS_WIDTH = LEN_WIDTH + TAG_WIDTH + AXIS_ID_WIDTH + AXIS_DEST_WIDTH + AXIS_USER_WIDTH + 4 )( input logic ctrl_clk, input logic rst, @@ -35,6 +49,7 @@ module tb_controller_wrapper_axil #( logic rst_n; assign rst_n = ~rst; + // Для минимального теста держим все clock domain-ы на одном clock. logic dac_clk_in; logic adc_clk_in; assign dac_clk_in = ctrl_clk; @@ -84,6 +99,7 @@ module tb_controller_wrapper_axil #( .m_axil(axil_bus) ); + // Controller ADC/DAC outputs. logic [31:0] adc_window_size; logic [31:0] dac_pulse_width; logic [31:0] dac_pulse_period; @@ -96,11 +112,45 @@ module tb_controller_wrapper_axil #( logic dac_rst; logic adc_rst; + // DMA side. Для базового AXI-Lite теста даём спокойные значения. + logic ready_desc_read; + logic ready_desc_write; + logic ready_status_read; + logic ready_status_write; + + logic valid_desc_read; + logic valid_desc_write; + logic valid_status_read; + logic valid_status_write; + + logic [READ_STATUS_WIDTH-1:0] status_read_cmd_in; + logic [WRITE_STATUS_WIDTH-1:0] status_write_cmd_in; + + logic [READ_DESC_WIDTH-1:0] desc_read_cmd_out; + logic [WRITE_DESC_WIDTH-1:0] desc_write_cmd_out; + + assign ready_desc_read = 1'b1; + assign ready_desc_write = 1'b1; + assign valid_status_read = 1'b0; + assign valid_status_write = 1'b0; + assign status_read_cmd_in = '0; + assign status_write_cmd_in = '0; + controller_wrapper_axil #( - .DAC_DATA_WIDTH(DAC_DATA_WIDTH), .ADDR_W(ADDR_W), .DATA_W(DATA_W), - .USER_W(USER_W) + .USER_W(USER_W), + .DAC_DATA_WIDTH(DAC_DATA_WIDTH), + .AXI_ADDR_WIDTH(AXI_ADDR_WIDTH), + .AXIS_ID_WIDTH(AXIS_ID_WIDTH), + .LEN_WIDTH(LEN_WIDTH), + .AXIS_USER_WIDTH(AXIS_USER_WIDTH), + .AXIS_DEST_WIDTH(AXIS_DEST_WIDTH), + .TAG_WIDTH(TAG_WIDTH), + .READ_DESC_WIDTH(READ_DESC_WIDTH), + .WRITE_DESC_WIDTH(WRITE_DESC_WIDTH), + .READ_STATUS_WIDTH(READ_STATUS_WIDTH), + .WRITE_STATUS_WIDTH(WRITE_STATUS_WIDTH) ) dut ( .ctrl_clk(ctrl_clk), .dac_clk_in(dac_clk_in), @@ -122,7 +172,25 @@ module tb_controller_wrapper_axil #( .dac_start(dac_start), .adc_start(adc_start), .dac_rst(dac_rst), - .adc_rst(adc_rst) + .adc_rst(adc_rst), + + .ready_desc_read(ready_desc_read), + .ready_desc_write(ready_desc_write), + + .ready_status_read(ready_status_read), + .ready_status_write(ready_status_write), + + .valid_desc_read(valid_desc_read), + .valid_desc_write(valid_desc_write), + + .valid_status_read(valid_status_read), + .valid_status_write(valid_status_write), + + .status_read_cmd_in(status_read_cmd_in), + .status_write_cmd_in(status_write_cmd_in), + + .desc_read_cmd_out(desc_read_cmd_out), + .desc_write_cmd_out(desc_write_cmd_out) ); endmodule diff --git a/rtl/controller/tests/test_controller.py b/rtl/controller/tests/test_controller.py index ceb8b79..f141ff5 100644 --- a/rtl/controller/tests/test_controller.py +++ b/rtl/controller/tests/test_controller.py @@ -4,21 +4,45 @@ from cocotb.triggers import RisingEdge from cocotbext.axi import AxiLiteBus, AxiLiteMaster -# register indexes from axi4l_reg_map_controller_pkg.sv +# Register indexes from axi4l_reg_map_controller_pkg.sv REG_CONTROL = 0 +REG_STATUS = 1 REG_DAC_WIDTH = 2 REG_DAC_PERIOD = 3 REG_DAC_PULSE_NUM = 4 REG_DAC_PULSE_HEIGHT = 5 REG_ADC_PERIOD = 6 REG_WINDOW_SIZE = 7 +REG_ERROR = 8 +REG_DESC_READ_ADDR = 9 +REG_DESC_READ_LEN = 10 +REG_DESC_READ_CONFIG = 11 +REG_READ_STATUS = 12 +REG_DESC_WRITE_ADDR = 13 +REG_DESC_WRITE_LEN_AND_TAG = 14 +REG_STATUS_WRITE_LEN = 15 +REG_STATUS_WRITE_CONFIG = 16 + + +# REG_CONTROL pulse bits +CTRL_START = 0 +CTRL_RST_SOFT = 1 +CTRL_CFG_BUS_VALID = 2 +CTRL_SEND_DESC_READ = 3 +CTRL_SEND_DESC_WRITE = 4 +CTRL_TAKE_STATUS_READ = 5 +CTRL_TAKE_STATUS_WRITE = 6 def reg_addr(reg_index: int) -> int: - # AXI-Lite usually uses byte addresses for 32-bit regs + # AXI-Lite uses byte addresses, 32-bit registers are spaced by 4 bytes. return reg_index * 4 +def u32(value: int) -> bytes: + return int(value & 0xFFFFFFFF).to_bytes(4, "little") + + class TB: def __init__(self, dut): self.dut = dut @@ -40,22 +64,61 @@ class TB: for _ in range(5): await RisingEdge(self.dut.ctrl_clk) + async def write_reg(self, reg_index: int, value: int): + await self.axil.write(reg_addr(reg_index), u32(value)) + + async def read_reg(self, reg_index: int) -> int: + resp = await self.axil.read(reg_addr(reg_index), 4) + return int.from_bytes(bytes(resp.data), "little") + @cocotb.test() -async def simple_axil_write(dut): +async def simple_axil_write_read(dut): tb = TB(dut) await tb.reset() - # Простая запись в RW-регистр REG_DAC_WIDTH. - await tb.axil.write(reg_addr(REG_DAC_WIDTH), (0x0000_0123).to_bytes(4, "little")) + await tb.write_reg(REG_DAC_WIDTH, 0x0000_0123) - # Не обязательно, но удобно проверить, что запись прошла через AXI-Lite. - resp = await tb.axil.read(reg_addr(REG_DAC_WIDTH), 4) - value = int.from_bytes(bytes(resp.data), "little") + value = await tb.read_reg(REG_DAC_WIDTH) assert value == 0x0000_0123 - # Пример W1S-записи в control: bit 3 = cfg_bus_valid pulse. - # Дальше уже можно проверять твою логику контроллера. - await tb.axil.write(reg_addr(REG_CONTROL), (1 << 3).to_bytes(4, "little")) + +@cocotb.test() +async def simple_controller_config_write(dut): + tb = TB(dut) + await tb.reset() + + await tb.write_reg(REG_DAC_WIDTH, 0x10) + await tb.write_reg(REG_DAC_PERIOD, 0x40) + await tb.write_reg(REG_DAC_PULSE_NUM, 3) + await tb.write_reg(REG_DAC_PULSE_HEIGHT, 0x7FF) + await tb.write_reg(REG_ADC_PERIOD, 0x80) + await tb.write_reg(REG_WINDOW_SIZE, 16) + + assert await tb.read_reg(REG_DAC_WIDTH) == 0x10 + assert await tb.read_reg(REG_WINDOW_SIZE) == 16 + + # W1S pulse: bit 2 = cfg_bus_valid_o. + await tb.write_reg(REG_CONTROL, 1 << CTRL_CFG_BUS_VALID) await RisingEdge(dut.ctrl_clk) + + +@cocotb.test() +async def simple_dma_desc_register_write(dut): + tb = TB(dut) + await tb.reset() + + # mock + await tb.write_reg(REG_DESC_READ_ADDR, 0x0000_1000) + await tb.write_reg(REG_DESC_READ_LEN, 64) + await tb.write_reg(REG_DESC_READ_CONFIG, 0x0000_0001) + + assert await tb.read_reg(REG_DESC_READ_ADDR) == 0x0000_1000 + assert await tb.read_reg(REG_DESC_READ_LEN) == 64 + + # W1S pulse: bit 3 = send_desc_read_o. + await tb.write_reg(REG_CONTROL, 1 << CTRL_SEND_DESC_READ) + + for _ in range(3): + await RisingEdge(dut.ctrl_clk)