diff --git a/rtl/controller/tests/tb_controller_wrapper_axil.sv b/rtl/controller/tests/tb_controller_wrapper_axil.sv new file mode 100644 index 0000000..91a64d5 --- /dev/null +++ b/rtl/controller/tests/tb_controller_wrapper_axil.sv @@ -0,0 +1,128 @@ +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 +)( + input logic ctrl_clk, + input logic rst, + + input logic [ADDR_W-1:0] s_axil_awaddr, + input logic [2:0] s_axil_awprot, + input logic s_axil_awvalid, + output logic s_axil_awready, + + input logic [DATA_W-1:0] s_axil_wdata, + input logic [DATA_W/8-1:0] s_axil_wstrb, + input logic s_axil_wvalid, + output logic s_axil_wready, + + output logic [1:0] s_axil_bresp, + output logic s_axil_bvalid, + input logic s_axil_bready, + + input logic [ADDR_W-1:0] s_axil_araddr, + input logic [2:0] s_axil_arprot, + input logic s_axil_arvalid, + output logic s_axil_arready, + + output logic [DATA_W-1:0] s_axil_rdata, + output logic [1:0] s_axil_rresp, + output logic s_axil_rvalid, + input logic s_axil_rready +); + + logic rst_n; + assign rst_n = ~rst; + + logic dac_clk_in; + logic adc_clk_in; + assign dac_clk_in = ctrl_clk; + assign adc_clk_in = ctrl_clk; + + logic finish; + assign finish = 1'b0; + + axi4l_if #( + .ADDR_W(ADDR_W), + .DATA_W(DATA_W), + .USER_W(USER_W) + ) axil_bus ( + .aclk(ctrl_clk), + .aresetn(rst_n) + ); + + axi4l_flat_to_if #( + .ADDR_W(ADDR_W), + .DATA_W(DATA_W), + .USER_W(USER_W) + ) u_flat_to_if ( + .s_axil_awaddr (s_axil_awaddr), + .s_axil_awprot (s_axil_awprot), + .s_axil_awvalid(s_axil_awvalid), + .s_axil_awready(s_axil_awready), + + .s_axil_wdata (s_axil_wdata), + .s_axil_wstrb (s_axil_wstrb), + .s_axil_wvalid (s_axil_wvalid), + .s_axil_wready (s_axil_wready), + + .s_axil_bresp (s_axil_bresp), + .s_axil_bvalid (s_axil_bvalid), + .s_axil_bready (s_axil_bready), + + .s_axil_araddr (s_axil_araddr), + .s_axil_arprot (s_axil_arprot), + .s_axil_arvalid(s_axil_arvalid), + .s_axil_arready(s_axil_arready), + + .s_axil_rdata (s_axil_rdata), + .s_axil_rresp (s_axil_rresp), + .s_axil_rvalid (s_axil_rvalid), + .s_axil_rready (s_axil_rready), + + .m_axil(axil_bus) + ); + + logic [31:0] adc_window_size; + logic [31:0] dac_pulse_width; + logic [31:0] dac_pulse_period; + logic [DAC_DATA_WIDTH-1:0] dac_pulse_height; + logic [15:0] dac_pulse_num; + logic [31:0] adc_pulse_period; + logic [15:0] adc_pulse_num; + logic dac_start; + logic adc_start; + logic dac_rst; + logic adc_rst; + + controller_wrapper_axil #( + .DAC_DATA_WIDTH(DAC_DATA_WIDTH), + .ADDR_W(ADDR_W), + .DATA_W(DATA_W), + .USER_W(USER_W) + ) dut ( + .ctrl_clk(ctrl_clk), + .dac_clk_in(dac_clk_in), + .adc_clk_in(adc_clk_in), + .rst_n(rst_n), + .s_axil(axil_bus), + + .finish(finish), + .adc_window_size(adc_window_size), + + .dac_pulse_width(dac_pulse_width), + .dac_pulse_period(dac_pulse_period), + .dac_pulse_height(dac_pulse_height), + .dac_pulse_num(dac_pulse_num), + + .adc_pulse_period(adc_pulse_period), + .adc_pulse_num(adc_pulse_num), + + .dac_start(dac_start), + .adc_start(adc_start), + .dac_rst(dac_rst), + .adc_rst(adc_rst) + ); + +endmodule diff --git a/rtl/controller/tests/test_controller.py b/rtl/controller/tests/test_controller.py new file mode 100644 index 0000000..ceb8b79 --- /dev/null +++ b/rtl/controller/tests/test_controller.py @@ -0,0 +1,61 @@ +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge +from cocotbext.axi import AxiLiteBus, AxiLiteMaster + + +# register indexes from axi4l_reg_map_controller_pkg.sv +REG_CONTROL = 0 +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 + + +def reg_addr(reg_index: int) -> int: + # AXI-Lite usually uses byte addresses for 32-bit regs + return reg_index * 4 + + +class TB: + def __init__(self, dut): + self.dut = dut + + cocotb.start_soon(Clock(dut.ctrl_clk, 10, units="ns").start()) + + self.axil = AxiLiteMaster( + AxiLiteBus.from_prefix(dut, "s_axil"), + dut.ctrl_clk, + dut.rst, + ) + + async def reset(self): + self.dut.rst.value = 1 + for _ in range(5): + await RisingEdge(self.dut.ctrl_clk) + + self.dut.rst.value = 0 + for _ in range(5): + await RisingEdge(self.dut.ctrl_clk) + + +@cocotb.test() +async def simple_axil_write(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")) + + # Не обязательно, но удобно проверить, что запись прошла через AXI-Lite. + resp = await tb.axil.read(reg_addr(REG_DAC_WIDTH), 4) + value = int.from_bytes(bytes(resp.data), "little") + 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")) + + await RisingEdge(dut.ctrl_clk)