From c21c9d2ab5b403e4159aef22902fe26a5217fd92 Mon Sep 17 00:00:00 2001 From: otroubi Date: Tue, 28 Jul 2026 12:50:30 +0300 Subject: [PATCH] transferring test for controller dma ram connective --- .../src/axi_dma_wrapper_if.sv | 189 +++++++++++ .../src/axi_ram_wrapper.sv | 60 ++++ .../src/wrapper_controller_dma.sv | 193 ++++++++++++ .../controller_dma_connective/tests/Makefile | 48 +++ .../tests/tb_controller_dma_wrapper_axil.sv | 298 ++++++++++++++++++ .../tests/test_controller_and_dma.py | 194 ++++++++++++ .../tests/test_timing.xdc | 13 + 7 files changed, 995 insertions(+) create mode 100644 designs/controller_dma_connective/src/axi_dma_wrapper_if.sv create mode 100644 designs/controller_dma_connective/src/axi_ram_wrapper.sv create mode 100644 designs/controller_dma_connective/src/wrapper_controller_dma.sv create mode 100644 designs/controller_dma_connective/tests/Makefile create mode 100644 designs/controller_dma_connective/tests/tb_controller_dma_wrapper_axil.sv create mode 100644 designs/controller_dma_connective/tests/test_controller_and_dma.py create mode 100644 designs/controller_dma_connective/tests/test_timing.xdc diff --git a/designs/controller_dma_connective/src/axi_dma_wrapper_if.sv b/designs/controller_dma_connective/src/axi_dma_wrapper_if.sv new file mode 100644 index 0000000..c5ea91e --- /dev/null +++ b/designs/controller_dma_connective/src/axi_dma_wrapper_if.sv @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: MIT +// +// SystemVerilog interface wrapper around alexforencich/verilog-axi axi_dma.v. +// +// AXI memory, AXI-Stream data, DMA descriptor, and DMA status channels are all +// exposed through compact interfaces. The original Forencich core remains +// untouched and is connected through local flat wires. + +`default_nettype none +import dma_reg_pkg::*; + +// DMA Specific wrappers & converters +module axi_dma_wrapper #( + parameter int unsigned AXI_DATA_WIDTH = 32, + + parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8, + parameter int unsigned AXI_ID_WIDTH = 8, + parameter int unsigned AXI_USER_WIDTH = 1, + parameter int unsigned AXI_MAX_BURST_LEN = 16, + + parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH, + parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8, + parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8, + parameter int unsigned AXIS_LAST_ENABLE = 1, + parameter int unsigned AXIS_ID_ENABLE = 1, + parameter int unsigned AXIS_DEST_ENABLE = 0, + parameter int unsigned AXIS_USER_ENABLE = 1, + + parameter int unsigned ENABLE_SG = 0, + parameter int unsigned ENABLE_UNALIGNED = 0 +)( + input logic clk, + input logic rst, + + axis_if.slave s_axis_read_desc, + + axis_if.master m_axis_read_desc_status, + + axis_if.master m_axis_read_data, + + axis_if.slave s_axis_write_desc, + + axis_if.master m_axis_write_desc_status, + + axis_if.slave s_axis_write_data, + + axi4_if.master m_axi +); + + dma_read_desc_t read_desc; + assign read_desc = dma_read_desc_t'(s_axis_read_desc.req.t.data); + + + dma_write_desc_t write_desc; + assign write_desc = dma_write_desc_t'(s_axis_write_desc.req.t.data); + + + dma_read_status_t read_status; + assign m_axis_read_desc_status.req.t.data = read_status; + logic m_axis_read_desc_status_valid; + assign m_axis_read_desc_status.req.t.valid = m_axis_read_desc_status_valid; + + + + dma_write_status_t write_status; + assign m_axis_write_desc_status.req.t.data = write_status; + logic m_axis_write_desc_status_valid; + assign m_axis_write_desc_status.req.t.valid = m_axis_write_desc_status_valid; + + + // Original DMA: flat ports only. + axi_dma #( + .AXI_DATA_WIDTH (AXI_DATA_WIDTH), + .AXI_ADDR_WIDTH (dma_reg_pkg::AXI_ADDR_WIDTH), + .AXI_STRB_WIDTH (AXI_STRB_WIDTH), + .AXI_ID_WIDTH (AXI_ID_WIDTH), + .AXI_MAX_BURST_LEN (AXI_MAX_BURST_LEN), + .AXIS_DATA_WIDTH (AXIS_DATA_WIDTH), + .AXIS_KEEP_ENABLE (AXIS_KEEP_ENABLE), + .AXIS_KEEP_WIDTH (AXIS_KEEP_WIDTH), + .AXIS_LAST_ENABLE (AXIS_LAST_ENABLE), + .AXIS_ID_ENABLE (AXIS_ID_ENABLE), + .AXIS_ID_WIDTH (dma_reg_pkg::AXIS_ID_WIDTH), + .AXIS_DEST_ENABLE (AXIS_DEST_ENABLE), + .AXIS_DEST_WIDTH (dma_reg_pkg::AXIS_DEST_WIDTH), + .AXIS_USER_ENABLE (AXIS_USER_ENABLE), + .AXIS_USER_WIDTH (dma_reg_pkg::AXIS_USER_WIDTH), + .LEN_WIDTH (dma_reg_pkg::LEN_WIDTH), + .TAG_WIDTH (dma_reg_pkg::TAG_WIDTH), + .ENABLE_SG (ENABLE_SG), + .ENABLE_UNALIGNED (ENABLE_UNALIGNED) + ) i_axi_dma ( + .clk (clk), + .rst (rst), + + .s_axis_read_desc_addr (read_desc.addr), + .s_axis_read_desc_len (read_desc.len), + .s_axis_read_desc_tag (read_desc.tag), + .s_axis_read_desc_id (read_desc.id), + .s_axis_read_desc_dest (read_desc.dest), + .s_axis_read_desc_user (read_desc.user), + .s_axis_read_desc_valid (s_axis_read_desc.req.t.valid), + .s_axis_read_desc_ready (s_axis_read_desc.resp.ready), + + .m_axis_read_desc_status_tag (read_status.tag), + .m_axis_read_desc_status_error (read_status.error), + .m_axis_read_desc_status_valid (m_axis_read_desc_status_valid), + + .m_axis_read_data_tdata (m_axis_read_data.req.t.data), + .m_axis_read_data_tkeep (m_axis_read_data.req.t.keep), + .m_axis_read_data_tvalid (m_axis_read_data.req.t.valid), + .m_axis_read_data_tready (m_axis_read_data.resp.ready), + .m_axis_read_data_tlast (m_axis_read_data.req.t.last), + .m_axis_read_data_tid (m_axis_read_data.req.t.id), + .m_axis_read_data_tdest (m_axis_read_data.req.t.dest), + .m_axis_read_data_tuser (m_axis_read_data.req.t.user), + + .s_axis_write_desc_addr (write_desc.addr), + .s_axis_write_desc_len (write_desc.len), + .s_axis_write_desc_tag (write_desc.tag), + .s_axis_write_desc_valid (s_axis_write_desc.req.t.valid), + .s_axis_write_desc_ready (s_axis_write_desc.resp.ready), + + .m_axis_write_desc_status_len (write_status.len), + .m_axis_write_desc_status_tag (write_status.tag), + .m_axis_write_desc_status_id (write_status.id), + .m_axis_write_desc_status_dest (write_status.dest), + .m_axis_write_desc_status_user (write_status.user), + .m_axis_write_desc_status_error (write_status.error), + .m_axis_write_desc_status_valid (m_axis_write_desc_status_valid), + + .s_axis_write_data_tdata (s_axis_write_data.req.t.data), + .s_axis_write_data_tkeep (s_axis_write_data.req.t.keep), + .s_axis_write_data_tvalid (s_axis_write_data.req.t.valid), + .s_axis_write_data_tready (s_axis_write_data.resp.ready), + .s_axis_write_data_tlast (s_axis_write_data.req.t.last), + .s_axis_write_data_tid (s_axis_write_data.req.t.id), + .s_axis_write_data_tdest (s_axis_write_data.req.t.dest), + .s_axis_write_data_tuser (s_axis_write_data.req.t.user), + + .m_axi_awid (m_axi.req.aw.id), + .m_axi_awaddr (m_axi.req.aw.addr), + .m_axi_awlen (m_axi.req.aw.len), + .m_axi_awsize (m_axi.req.aw.size), + .m_axi_awburst (m_axi.req.aw.burst), + .m_axi_awlock (m_axi.req.aw.lock), + .m_axi_awcache (m_axi.req.aw.cache), + .m_axi_awprot (m_axi.req.aw.prot), + .m_axi_awvalid (m_axi.req.aw.valid), + .m_axi_awready (m_axi.resp.aw_ready), + + .m_axi_wdata (m_axi.req.w.data), + .m_axi_wstrb (m_axi.req.w.strb), + .m_axi_wlast ( m_axi.req.w.last), + .m_axi_wvalid (m_axi.req.w.valid), + .m_axi_wready (m_axi.resp.w_ready), + + .m_axi_bid (m_axi.resp.b.id), + .m_axi_bresp (m_axi.resp.b.resp), + .m_axi_bvalid (m_axi.resp.b.valid), + .m_axi_bready (m_axi.req.b_ready), + + .m_axi_arid (m_axi.req.ar.id), + .m_axi_araddr (m_axi.req.ar.addr), + .m_axi_arlen (m_axi.req.ar.len), + .m_axi_arsize (m_axi.req.ar.size), + .m_axi_arburst (m_axi.req.ar.burst), + .m_axi_arlock (m_axi.req.ar.lock), + .m_axi_arcache (m_axi.req.ar.cache), + .m_axi_arprot (m_axi.req.ar.prot), + .m_axi_arvalid (m_axi.req.ar.valid), + .m_axi_arready (m_axi.resp.ar_ready), + + .m_axi_rid (m_axi.resp.r.id), + .m_axi_rdata (m_axi.resp.r.data), + .m_axi_rresp (m_axi.resp.r.resp), + .m_axi_rlast (m_axi.resp.r.last), + .m_axi_rvalid (m_axi.resp.r.valid), + .m_axi_rready (m_axi.req.r_ready), + + .read_enable (1'b1), + .write_enable (1'b1), + .write_abort (1'b0) + ); + + +endmodule : axi_dma_wrapper + +`default_nettype wire diff --git a/designs/controller_dma_connective/src/axi_ram_wrapper.sv b/designs/controller_dma_connective/src/axi_ram_wrapper.sv new file mode 100644 index 0000000..48588af --- /dev/null +++ b/designs/controller_dma_connective/src/axi_ram_wrapper.sv @@ -0,0 +1,60 @@ +module axi_ram_wrapper +#( + parameter int unsigned DATA_WIDTH = 32, + parameter int unsigned ADDR_WIDTH = 16, + parameter int unsigned ID_WIDTH = 8, + parameter int unsigned PIPELINE_OUTPUT = 0 +) +( + input logic clk, + input logic rst, + axi4_if.slave s_axi +); + +axi_ram +#( + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH), + .ID_WIDTH(ID_WIDTH), + .PIPELINE_OUTPUT(PIPELINE_OUTPUT) +) axi_ram_inst +( + .clk(clk), + .rst(rst), + .s_axi_awid(s_axi.req.aw.id), + .s_axi_awaddr(s_axi.req.aw.addr), + .s_axi_awlen(s_axi.req.aw.len), + .s_axi_awsize(s_axi.req.aw.size), + .s_axi_awburst(s_axi.req.aw.burst), + .s_axi_awlock(s_axi.req.aw.lock), + .s_axi_awcache(s_axi.req.aw.cache), + .s_axi_awprot(s_axi.req.aw.prot), + .s_axi_awvalid(s_axi.req.aw.valid), + .s_axi_awready(s_axi.resp.aw_ready), + .s_axi_wdata(s_axi.req.w.data), + .s_axi_wstrb(s_axi.req.w.strb), + .s_axi_wlast(s_axi.req.w.last), + .s_axi_wvalid(s_axi.req.w.valid), + .s_axi_wready(s_axi.resp.w_ready), + .s_axi_bid(s_axi.resp.b.id), + .s_axi_bresp(s_axi.resp.b.resp), + .s_axi_bvalid(s_axi.resp.b.valid), + .s_axi_bready(s_axi.req.b_ready), + .s_axi_arid(s_axi.req.ar.id), + .s_axi_araddr(s_axi.req.ar.addr), + .s_axi_arlen(s_axi.req.ar.len), + .s_axi_arsize(s_axi.req.ar.size), + .s_axi_arburst(s_axi.req.ar.burst), + .s_axi_arlock(s_axi.req.ar.lock), + .s_axi_arcache(s_axi.req.ar.cache), + .s_axi_arprot(s_axi.req.ar.prot), + .s_axi_arvalid(s_axi.req.ar.valid), + .s_axi_arready(s_axi.resp.ar_ready), + .s_axi_rid(s_axi.resp.r.id), + .s_axi_rdata(s_axi.resp.r.data), + .s_axi_rresp(s_axi.resp.r.resp), + .s_axi_rlast(s_axi.resp.r.last), + .s_axi_rvalid(s_axi.resp.r.valid), + .s_axi_rready(s_axi.req.r_ready) +); +endmodule \ No newline at end of file diff --git a/designs/controller_dma_connective/src/wrapper_controller_dma.sv b/designs/controller_dma_connective/src/wrapper_controller_dma.sv new file mode 100644 index 0000000..c8b3202 --- /dev/null +++ b/designs/controller_dma_connective/src/wrapper_controller_dma.sv @@ -0,0 +1,193 @@ +import dma_reg_pkg::*; + +module wrapper_controller_dma +#( + 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_DATA_WIDTH = 32, + + parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8, + parameter int unsigned AXI_ID_WIDTH = 8, + parameter int unsigned AXI_USER_WIDTH = 1, + parameter int unsigned AXI_MAX_BURST_LEN = 16, + + parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH, + parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8, + parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8, + parameter int unsigned AXIS_LAST_ENABLE = 1, + parameter int unsigned AXIS_ID_ENABLE = 1, + parameter int unsigned AXIS_DEST_ENABLE = 0, + parameter int unsigned AXIS_USER_ENABLE = 1, + + parameter int unsigned ENABLE_SG = 0, + parameter int unsigned ENABLE_UNALIGNED = 0, + + parameter int unsigned PIPELINE_OUTPUT = 0 +) +( + input logic ctrl_clk, + input logic dac_clk_in, + input logic adc_clk_in, + input logic rst_n, + axi4l_if.slave s_axil, + + // adc_clk_in domain + input logic finish, + output logic [31:0] adc_window_size, + + // dac_clk_in domain outputs + output logic [31:0] dac_pulse_width, + output logic [31:0] dac_pulse_period, + output logic [DAC_DATA_WIDTH-1:0] dac_pulse_height, + output logic [15:0] dac_pulse_num, + + // adc_clk_in domain outputs + output logic [31:0] adc_pulse_period, + output logic [15:0] adc_pulse_num, + + // pulse outputs + output logic dac_start, + output logic adc_start, + output logic dac_rst, + output logic adc_rst, + + axis_if.master m_axis_read_data, + axis_if.slave s_axis_write_data +); + +axis_if #( + .DATA_W($bits(dma_read_status_t)), + .KEEP_W(($bits(dma_read_status_t)+7)/8), + .ID_W(dma_reg_pkg::AXIS_ID_WIDTH), + .DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH), + .USER_W(dma_reg_pkg::AXIS_USER_WIDTH) + ) s_axis_status_read ( + .aclk(ctrl_clk), + .aresetn(rst_n) + ); + + axis_if #( + .DATA_W($bits(dma_write_status_t)), + .KEEP_W(($bits(dma_write_status_t)+7)/8), + .ID_W(dma_reg_pkg::AXIS_ID_WIDTH), + .DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH), + .USER_W(dma_reg_pkg::AXIS_USER_WIDTH) + ) s_axis_status_write ( + .aclk(ctrl_clk), + .aresetn(rst_n) + ); + + axis_if #( + .DATA_W($bits(dma_read_desc_t)), + .KEEP_W(($bits(dma_read_desc_t)+7)/8), + .ID_W(dma_reg_pkg::AXIS_ID_WIDTH), + .DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH), + .USER_W(dma_reg_pkg::AXIS_USER_WIDTH) + ) m_axis_desc_read ( + .aclk(ctrl_clk), + .aresetn(rst_n) + ); + + axis_if #( + .DATA_W($bits(dma_write_desc_t)), + .KEEP_W(($bits(dma_write_desc_t)+7)/8), + .ID_W(dma_reg_pkg::AXIS_ID_WIDTH), + .DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH), + .USER_W(dma_reg_pkg::AXIS_USER_WIDTH) + ) m_axis_desc_write ( + .aclk(ctrl_clk), + .aresetn(rst_n) + ); + +controller_wrapper_axil +#( + .ADDR_W(ADDR_W), + .DATA_W(DATA_W), + .USER_W(USER_W), + .DAC_DATA_WIDTH(DAC_DATA_WIDTH) +) +controller_wrapper_axil_inst +( + .ctrl_clk(ctrl_clk), + .dac_clk_in(dac_clk_in), + .adc_clk_in(adc_clk_in), + .rst_n(rst_n), + + .s_axil(s_axil), + + .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), + + .s_axis_status_read(s_axis_status_read), + .s_axis_status_write(s_axis_status_write), + .m_axis_desc_read(m_axis_desc_read), + .m_axis_desc_write(m_axis_desc_write) +); + +axi4_if #( + .ADDR_W(dma_reg_pkg::AXI_ADDR_WIDTH), + .DATA_W(AXI_DATA_WIDTH), + .ID_W (AXI_ID_WIDTH), + .USER_W(AXI_USER_WIDTH) + ) m_axi ( + .aclk(ctrl_clk), + .aresetn(rst_n) + ); + +axi_dma_wrapper +#( + .AXI_DATA_WIDTH(AXI_DATA_WIDTH), + .AXI_STRB_WIDTH(AXI_STRB_WIDTH), + .AXI_USER_WIDTH(AXI_USER_WIDTH), + .AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN), + .AXIS_DATA_WIDTH(AXIS_DATA_WIDTH), + .AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE), + .AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH), + .AXIS_LAST_ENABLE(AXIS_LAST_ENABLE), + .AXIS_ID_ENABLE(AXIS_ID_ENABLE), + .AXIS_DEST_ENABLE(AXIS_DEST_ENABLE), + .AXIS_USER_ENABLE(AXIS_USER_ENABLE), + .ENABLE_SG(ENABLE_SG), + .ENABLE_UNALIGNED(ENABLE_UNALIGNED) +) +axi_dma_wrapper_inst +( + .clk(ctrl_clk), + .rst(!rst_n), + .s_axis_read_desc(m_axis_desc_read), + .m_axis_read_desc_status(s_axis_status_read), + .m_axis_read_data(m_axis_read_data), + .s_axis_write_desc(m_axis_desc_write), + .m_axis_write_desc_status(s_axis_status_write), + .s_axis_write_data(s_axis_write_data), + .m_axi(m_axi) +); + +axi_ram_wrapper +#( + .DATA_WIDTH(AXI_DATA_WIDTH), + .ADDR_WIDTH(dma_reg_pkg::AXI_ADDR_WIDTH), + .ID_WIDTH(dma_reg_pkg::AXIS_ID_WIDTH), + .PIPELINE_OUTPUT(PIPELINE_OUTPUT) +) axi_ram_wrapper_inst +( + .clk(ctrl_clk), + .rst(!rst_n), + .s_axi(m_axi) +); + +endmodule \ No newline at end of file diff --git a/designs/controller_dma_connective/tests/Makefile b/designs/controller_dma_connective/tests/Makefile new file mode 100644 index 0000000..3dc8182 --- /dev/null +++ b/designs/controller_dma_connective/tests/Makefile @@ -0,0 +1,48 @@ +TOPLEVEL_LANG = verilog +SIM ?= verilator + +PWD := $(shell pwd) + +WRAP_DIR = $(PWD)/../src +RTL_DIR = $(PWD)/../../controller/src +LIBS_DIR = $(PWD)/../../../external/rtl_libs + +VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi_pkg.sv +VERILOG_SOURCES += $(RTL_DIR)/dma_reg_pkg.sv +VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi_if.sv +VERILOG_SOURCES += $(LIBS_DIR)/axi/axi_reg/axi4l_reg_map.sv +VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma_rd.v +VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma_wr.v +VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma.v +VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_ram.v +VERILOG_SOURCES += $(RTL_DIR)/axi_ram_wrapper.sv +VERILOG_SOURCES += $(RTL_DIR)/controller.sv +VERILOG_SOURCES += $(RTL_DIR)/dma_controller.sv +VERILOG_SOURCES += $(RTL_DIR)/shaper_axis_desc.sv +VERILOG_SOURCES += $(RTL_DIR)/shaper_axis_status.sv +VERILOG_SOURCES += $(RTL_DIR)/controller_wrapper_axil.sv +VERILOG_SOURCES += $(RTL_DIR)/axi4l_reg_map_controller_pkg.sv +VERILOG_SOURCES += $(RTL_DIR)/axis_defaults_helper.sv +VERILOG_SOURCES += $(RTL_DIR)/axi4l_reg_map_controller.sv +VERILOG_SOURCES += $(WRAP_DIR)/wrapper_controller_dma.sv +VERILOG_SOURCES += $(WRAP_DIR)/axi_dma_wrapper_if.sv +VERILOG_SOURCES += $(PWD)/tb_controller_dma_wrapper_axil.sv + +TOPLEVEL = tb_controller_dma_wrapper_axil +MODULE = test_controller_and_dma + + +ifeq ($(SIM),verilator) + EXTRA_ARGS += --trace --trace-structs + EXTRA_ARGS += -I$(LIBS_DIR)/axi/rtl/ + COMPILE_ARGS += -Wno-fatal + COMPILE_ARGS += -I$(LIBS_DIR)/axi/rtl/ + EXTRA_ARGS += --trace + EXTRA_ARGS += --trace-structs + EXTRA_ARGS += --public-flat-rw + EXTRA_ARGS += -Wno-fatal + EXTRA_ARGS += --timing +endif + + +include $(shell cocotb-config --makefiles)/Makefile.sim diff --git a/designs/controller_dma_connective/tests/tb_controller_dma_wrapper_axil.sv b/designs/controller_dma_connective/tests/tb_controller_dma_wrapper_axil.sv new file mode 100644 index 0000000..76c2cac --- /dev/null +++ b/designs/controller_dma_connective/tests/tb_controller_dma_wrapper_axil.sv @@ -0,0 +1,298 @@ + +import dma_reg_pkg::*; + +module tb_controller_wrapper_axil #( + 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_DATA_WIDTH = 32, + + parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8, + parameter int unsigned AXI_ID_WIDTH = 8, + parameter int unsigned AXI_USER_WIDTH = 1, + parameter int unsigned AXI_MAX_BURST_LEN = 16, + + parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH, + parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8, + parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8, + parameter int unsigned AXIS_LAST_ENABLE = 1, + parameter int unsigned AXIS_ID_ENABLE = 1, + parameter int unsigned AXIS_DEST_ENABLE = 0, + parameter int unsigned AXIS_USER_ENABLE = 1, + + parameter int unsigned ENABLE_SG = 0, + parameter int unsigned ENABLE_UNALIGNED = 0 +)( + 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, + + input wire [AXIS_DATA_WIDTH-1:0] s_axis_write_data_tdata, + input wire [AXIS_KEEP_WIDTH-1:0] s_axis_write_data_tkeep, + input wire s_axis_write_data_tvalid, + output wire s_axis_write_data_tready, + input wire s_axis_write_data_tlast, + input wire [AXIS_ID_WIDTH-1:0] s_axis_write_data_tid, + input wire [AXIS_DEST_WIDTH-1:0] s_axis_write_data_tdest, + input wire [AXIS_USER_WIDTH-1:0] s_axis_write_data_tuser, + + output wire [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata, + output wire [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep, + output wire m_axis_read_data_tvalid, + input wire m_axis_read_data_tready, + output wire m_axis_read_data_tlast, + output wire [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid, + output wire [AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest, + output wire [AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser, + + output wire [AXI_ID_WIDTH-1:0] m_axi_awid, + output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr, + output wire [7:0] m_axi_awlen, + output wire [2:0] m_axi_awsize, + output wire [1:0] m_axi_awburst, + output wire m_axi_awlock, + output wire [3:0] m_axi_awcache, + output wire [2:0] m_axi_awprot, + output wire m_axi_awvalid, + input wire m_axi_awready, + output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata, + output wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb, + output wire m_axi_wlast, + output wire m_axi_wvalid, + input wire m_axi_wready, + input wire [AXI_ID_WIDTH-1:0] m_axi_bid, + input wire [1:0] m_axi_bresp, + input wire m_axi_bvalid, + output wire m_axi_bready, + output wire [AXI_ID_WIDTH-1:0] m_axi_arid, + output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr, + output wire [7:0] m_axi_arlen, + output wire [2:0] m_axi_arsize, + output wire [1:0] m_axi_arburst, + output wire m_axi_arlock, + output wire [3:0] m_axi_arcache, + output wire [2:0] m_axi_arprot, + output wire m_axi_arvalid, + input wire m_axi_arready, + input wire [AXI_ID_WIDTH-1:0] m_axi_rid, + input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata, + input wire [1:0] m_axi_rresp, + input wire m_axi_rlast, + input wire m_axi_rvalid, + output wire m_axi_rready + + +); + + logic rst_n; + assign rst_n = ~rst; + + // Для минимального теста держим все clock domain-ы на одном clock. + 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; + + // --------------------------------------------------------------------------- + // AXI-Lite flat -> axi4l_if + // --------------------------------------------------------------------------- + + 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_axil_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) + ); + + // --------------------------------------------------------------------------- + // AXIS interfaces for the updated controller_wrapper_axil + // --------------------------------------------------------------------------- + +// AXIS READ DMA MASTER output + axis_if #( + .DATA_W (AXIS_DATA_WIDTH), + .KEEP_W (AXIS_KEEP_WIDTH), + .ID_W (AXIS_ID_WIDTH), + .DEST_W (AXIS_DEST_WIDTH), + .USER_W (AXIS_USER_WIDTH) + ) dma_read_data ( + .aclk(ctrl_clk), + .aresetn(rst_n) + ); + +logic [AXIS_KEEP_WIDTH-1:0] unused_read_tstrb; + +axis_if_to_flat #( + .DATA_W (AXIS_DATA_WIDTH), + .KEEP_W (AXIS_KEEP_WIDTH), + .ID_W (AXIS_ID_WIDTH), + .DEST_W (AXIS_DEST_WIDTH), + .USER_W (AXIS_USER_WIDTH) +) u_read_data_if_to_flat ( + .s_axis(dma_read_data), + + .m_axis_tdata (m_axis_read_data_tdata), + .m_axis_tkeep (m_axis_read_data_tkeep), + .m_axis_tstrb (unused_read_tstrb), + .m_axis_tlast (m_axis_read_data_tlast), + .m_axis_tid (m_axis_read_data_tid), + .m_axis_tdest (m_axis_read_data_tdest), + .m_axis_tuser (m_axis_read_data_tuser), + .m_axis_tvalid(m_axis_read_data_tvalid), + .m_axis_tready(m_axis_read_data_tready) +); + +// AXIS WRITE DMA SLAVE input + axis_if #( + .DATA_W (AXIS_DATA_WIDTH), + .KEEP_W (AXIS_KEEP_WIDTH), + .ID_W (AXIS_ID_WIDTH), + .DEST_W (AXIS_DEST_WIDTH), + .USER_W (AXIS_USER_WIDTH) + ) dma_write_data ( + .aclk(ctrl_clk), + .aresetn(rst_n) + ); + + +axis_flat_to_if #( + .DATA_W (AXIS_DATA_WIDTH), + .KEEP_W (AXIS_KEEP_WIDTH), + .ID_W (AXIS_ID_WIDTH), + .DEST_W (AXIS_DEST_WIDTH), + .USER_W (AXIS_USER_WIDTH) +) u_write_data_flat_to_if ( + .s_axis_tdata (s_axis_write_data_tdata), + .s_axis_tkeep (s_axis_write_data_tkeep), + .s_axis_tstrb (s_axis_write_data_tkeep), + .s_axis_tlast (s_axis_write_data_tlast), + .s_axis_tid (s_axis_write_data_tid), + .s_axis_tdest (s_axis_write_data_tdest), + .s_axis_tuser (s_axis_write_data_tuser), + .s_axis_tvalid(s_axis_write_data_tvalid), + .s_axis_tready(s_axis_write_data_tready), + + .m_axis(dma_write_data) +); + + + + // Controller ADC/DAC outputs. + 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; + + wrapper_controller_dma #( + .ADDR_W(ADDR_W), + .DATA_W(DATA_W), + .USER_W(USER_W), + .DAC_DATA_WIDTH(DAC_DATA_WIDTH), + .AXI_DATA_WIDTH(AXI_DATA_WIDTH), + .AXI_ID_WIDTH(AXI_ID_WIDTH), + .AXI_USER_WIDTH(AXI_USER_WIDTH), + .AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN), + .AXIS_LAST_ENABLE(AXIS_LAST_ENABLE), + .AXIS_ID_ENABLE(AXIS_ID_ENABLE), + .AXIS_DEST_ENABLE(AXIS_DEST_ENABLE), + .AXIS_USER_ENABLE(AXIS_USER_ENABLE), + .ENABLE_SG(ENABLE_SG), + .ENABLE_UNALIGNED(ENABLE_UNALIGNED) + ) 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), + + .m_axis_read_data(dma_read_data), + .s_axis_write_data(dma_write_data) + ); + +endmodule : tb_controller_wrapper_axil diff --git a/designs/controller_dma_connective/tests/test_controller_and_dma.py b/designs/controller_dma_connective/tests/test_controller_and_dma.py new file mode 100644 index 0000000..bb6ed98 --- /dev/null +++ b/designs/controller_dma_connective/tests/test_controller_and_dma.py @@ -0,0 +1,194 @@ +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge +from cocotbext.axi import AxiLiteBus, AxiLiteMaster +from cocotbext.axi import AxiBus, AxiRam, AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamFrame + + +# 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 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 + + 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 + ) + + + self.axis_source = AxiStreamSource( + AxiStreamBus.from_prefix(dut, "s_axis_write_data"), + dut.ctrl_clk, + dut.rst + ) + + self.axis_sink = AxiStreamSink( + AxiStreamBus.from_prefix(dut, "m_axis_read_data"), + 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) + + 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_read(dut): + tb = TB(dut) + await tb.reset() + + await tb.write_reg(REG_DAC_WIDTH, 0x0000_0123) + + value = await tb.read_reg(REG_DAC_WIDTH) + assert value == 0x0000_0123 + + +@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 + + # write data: set cfg_bus_valid signal + await tb.write_reg(REG_CONTROL, 1 << CTRL_CFG_BUS_VALID) + + # wait + for _ in range(30): + await RisingEdge(dut.ctrl_clk) + + # check config + assert int(dut.dac_pulse_width) == 0x10 + assert int(dut.dac_pulse_period) == 0x40 + assert int(dut.dac_pulse_num) == 3 + assert int(dut.dac_pulse_height) == 0x7FF + assert int(dut.adc_pulse_period) == 0x80 + assert int(dut.adc_window_size) == 16 + + await RisingEdge(dut.ctrl_clk) + + +@cocotb.test() +async def simple_controller_start_check(dut): + tb = TB(dut) + await tb.reset() + await tb.write_reg(REG_CONTROL, 1 << CTRL_START) + + await RisingEdge(dut.dac_start) + +@cocotb.test() +async def simple_dma_mem_to_mem(dut): + tb = TB(dut) + await tb.reset() + + SRC_ADDR = 0x1000 + LENGTH = 8 + + tx_data = bytes([ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 ]) + + ## write part + + await tb.write_reg(REG_DESC_WRITE_ADDR, SRC_ADDR) + await tb.write_reg(REG_DESC_WRITE_LEN_AND_TAG, LENGTH) + + await tb.write_reg(REG_CONTROL, 1 << CTRL_SEND_DESC_WRITE) + + await tb.axis_source.send(AxiStreamFrame(tx_data)) + + for _ in range(20): + await RisingEdge(dut.ctrl_clk) + + await tb.write_reg(REG_CONTROL, 1 << CTRL_TAKE_STATUS_WRITE) + + for _ in range(10): + await RisingEdge(dut.ctrl_clk) + + + assert await tb.read_reg(REG_STATUS_WRITE_CONFIG) == 0 + assert await tb.read_reg(REG_STATUS_WRITE_LEN) == 0x8 + + ## read part + + await tb.write_reg(REG_DESC_READ_ADDR, SRC_ADDR) + await tb.write_reg(REG_DESC_READ_LEN, LENGTH) + await tb.write_reg(REG_DESC_READ_CONFIG, 0x0000_0001) + + await tb.write_reg(REG_CONTROL, 1 << CTRL_SEND_DESC_READ) + + rx_frame = await tb.axis_sink.recv() + + for _ in range(20): + await RisingEdge(dut.ctrl_clk) + + await tb.write_reg(REG_CONTROL, 1 << CTRL_TAKE_STATUS_READ) + + for _ in range(10): + await RisingEdge(dut.ctrl_clk) + + assert await tb.read_reg(REG_READ_STATUS) == 0x1 + + assert bytes(rx_frame) == tx_data + + diff --git a/designs/controller_dma_connective/tests/test_timing.xdc b/designs/controller_dma_connective/tests/test_timing.xdc new file mode 100644 index 0000000..2ecbc36 --- /dev/null +++ b/designs/controller_dma_connective/tests/test_timing.xdc @@ -0,0 +1,13 @@ +# Primary clocks +create_clock -name eth_clk -period 8.000 [get_ports eth_clk_in] +create_clock -name dac_clk -period 7.692 [get_ports dac_clk_in] +create_clock -name adc_clk -period 15.385 [get_ports adc_clk_in] + + +# Asynchronous clock groups +# eth, dac, adc are independent domains + +set_clock_groups -name ASYNC_ETH_DAC_ADC -asynchronous \ + -group [get_clocks eth_clk] \ + -group [get_clocks dac_clk] \ + -group [get_clocks adc_clk]