From 600fba5d3ede828cf21596fe4a4d3132104a69be Mon Sep 17 00:00:00 2001 From: Phil Date: Wed, 17 Jun 2026 17:16:07 +0300 Subject: [PATCH] tests: add axi4l_reg test wrapper --- axi/tb/axil_reg_cocotb/tb_axi4l_reg_map.sv | 163 +++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 axi/tb/axil_reg_cocotb/tb_axi4l_reg_map.sv diff --git a/axi/tb/axil_reg_cocotb/tb_axi4l_reg_map.sv b/axi/tb/axil_reg_cocotb/tb_axi4l_reg_map.sv new file mode 100644 index 0000000..264f6f7 --- /dev/null +++ b/axi/tb/axil_reg_cocotb/tb_axi4l_reg_map.sv @@ -0,0 +1,163 @@ +module tb_axi4l_reg_map; + + localparam int unsigned ADDR_W = 16; + localparam int unsigned DATA_W = 32; + localparam int unsigned USER_W = 1; + localparam int unsigned N_REGS = 3; + + localparam logic [2:0] REG_BIT_RSVD = 3'd0; + localparam logic [2:0] REG_BIT_RO = 3'd1; + localparam logic [2:0] REG_BIT_RW = 3'd2; + localparam logic [2:0] REG_BIT_W1S = 3'd3; + localparam logic [2:0] REG_BIT_W1C = 3'd4; + + function automatic logic [N_REGS-1:0][31:0][2:0] make_reg_mode(); + logic [N_REGS-1:0][31:0][2:0] mode; + + mode = '{default: REG_BIT_RSVD}; + + // REG0 - 0x00: mixed control register + // bit 0 : W1S + // bit 1 : RW + // bit 2 : W1C + mode[0][0] = REG_BIT_W1S; + mode[0][1] = REG_BIT_RW; + mode[0][2] = REG_BIT_W1C; + + // REG1 - 0x04: status register + // bit 0 : RO busy + // bits 15:8 : RO error_code + mode[1][0] = REG_BIT_RO; + for (int i = 8; i < 16; i++) begin + mode[1][i] = REG_BIT_RO; + end + + // REG2 - 0x08: full RW config register + for (int i = 0; i < 32; i++) begin + mode[2][i] = REG_BIT_RW; + end + + return mode; + endfunction + + function automatic logic [N_REGS-1:0][31:0] make_reg_rst(); + logic [N_REGS-1:0][31:0] rst; + + rst = '{default: 32'h0000_0000}; + rst[0] = 32'h0000_0004; // W1C sticky bit starts set + rst[2] = 32'h1234_5678; // RW config reset value + + return rst; + endfunction + + localparam logic [N_REGS-1:0][31:0][2:0] REG_MODE = make_reg_mode(); + localparam logic [N_REGS-1:0][31:0] REG_RST = make_reg_rst(); + + logic clk = 1'b0; + logic rst = 1'b0; + logic rst_n; + + assign rst_n = ~rst; + + always #5ns clk = ~clk; + + // flat axil + logic [ADDR_W-1:0] s_axil_awaddr; + logic [2:0] s_axil_awprot; + logic s_axil_awvalid; + logic s_axil_awready; + + logic [DATA_W-1:0] s_axil_wdata; + logic [DATA_W/8-1:0] s_axil_wstrb; + logic s_axil_wvalid; + logic s_axil_wready; + + logic [1:0] s_axil_bresp; + logic s_axil_bvalid; + logic s_axil_bready; + + logic [ADDR_W-1:0] s_axil_araddr; + logic [2:0] s_axil_arprot; + logic s_axil_arvalid; + logic s_axil_arready; + + logic [DATA_W-1:0] s_axil_rdata; + logic [1:0] s_axil_rresp; + logic s_axil_rvalid; + logic s_axil_rready; + + // simple external status inputs driven from cocotb + logic busy_i; + logic [7:0] error_code_i; + + logic [N_REGS-1:0][31:0] reg_i; + logic [N_REGS-1:0][31:0] reg_o; + + // debug probes visible from cocotb. they are useful for checking W1S pulse-like behavior + logic [31:0] reg0_o; + logic [31:0] reg1_o; + logic [31:0] reg2_o; + + assign reg0_o = reg_o[0]; + assign reg1_o = reg_o[1]; + assign reg2_o = reg_o[2]; + + always_comb begin + reg_i = '0; + reg_i[1][0] = busy_i; + reg_i[1][15:8] = error_code_i; + end + + axi4l_if #( + .ADDR_W(ADDR_W), + .DATA_W(DATA_W), + .USER_W(USER_W) + ) s_axil_if ( + .aclk (clk), + .aresetn (rst_n) + ); + + + assign s_axil_if.req.aw.addr = s_axil_awaddr; + assign s_axil_if.req.aw.prot = s_axil_awprot; + assign s_axil_if.req.aw.user = '0; + assign s_axil_if.req.aw.valid = s_axil_awvalid; + assign s_axil_awready = s_axil_if.resp.aw_ready; + + assign s_axil_if.req.w.data = s_axil_wdata; + assign s_axil_if.req.w.strb = s_axil_wstrb; + assign s_axil_if.req.w.user = '0; + assign s_axil_if.req.w.valid = s_axil_wvalid; + assign s_axil_wready = s_axil_if.resp.w_ready; + + assign s_axil_bresp = s_axil_if.resp.b.resp; + assign s_axil_bvalid = s_axil_if.resp.b.valid; + assign s_axil_if.req.b_ready = s_axil_bready; + + assign s_axil_if.req.ar.addr = s_axil_araddr; + assign s_axil_if.req.ar.prot = s_axil_arprot; + assign s_axil_if.req.ar.user = '0; + assign s_axil_if.req.ar.valid = s_axil_arvalid; + assign s_axil_arready = s_axil_if.resp.ar_ready; + + assign s_axil_rdata = s_axil_if.resp.r.data; + assign s_axil_rresp = s_axil_if.resp.r.resp; + assign s_axil_rvalid = s_axil_if.resp.r.valid; + assign s_axil_if.req.r_ready = s_axil_rready; + + axi4l_reg_map #( + .ADDR_W (ADDR_W), + .DATA_W (DATA_W), + .USER_W (USER_W), + .N_REGS (N_REGS), + .REG_MODE(REG_MODE), + .REG_RST (REG_RST) + ) u_reg_map ( + .clk (clk), + .rst_n (rst_n), + .s_axil (s_axil_if.slave), + .reg_i (reg_i), + .reg_o (reg_o) + ); + +endmodule