diff --git a/.gitignore b/.gitignore index 76aace2..6f05e21 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ .Xil/ .venv/ + +sim_build/ +__pycache__/ \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 68cd974..4c6a4bd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,7 @@ scapy cocotb cocotbext-axi cocotbext-eth +cocotbext-pcie rtl-manifest build_fpga fpga-sim diff --git a/sim/alibaba_pcie.py b/sim/alibaba_pcie.py new file mode 100644 index 0000000..df33610 --- /dev/null +++ b/sim/alibaba_pcie.py @@ -0,0 +1,121 @@ +import logging +import cocotb + +from cocotb.triggers import Timer, FallingEdge +from cocotb.clock import Clock + +from cocotbext.axi import AxiStreamBus +from cocotbext.pcie.core import RootComplex +from cocotbext.pcie.xilinx.us import UltraScalePlusPcieDevice + +CLK_PERIOD = 4 + +class TB: + + def __init__(self, dut): + self.dut = dut + + self.log = logging.getLogger("cocotb.tb") + self.log.setLevel(logging.INFO) + + self.rc = RootComplex() + + self.dev = UltraScalePlusPcieDevice( + # configuration options + pcie_generation=3, + # pcie_link_width=2, + # user_clk_frequency=250e6, + alignment="dword", + cq_straddle=False, + cc_straddle=False, + rq_straddle=False, + rc_straddle=False, + rc_4tlp_straddle=False, + pf_count=1, + max_payload_size=1024, + enable_client_tag=True, + enable_extended_tag=True, + enable_parity=False, + enable_rx_msg_interface=False, + enable_sriov=False, + enable_extended_configuration=False, + + pf0_msi_enable=True, + pf0_msi_count=32, + pf1_msi_enable=False, + pf1_msi_count=1, + pf2_msi_enable=False, + pf2_msi_count=1, + pf3_msi_enable=False, + pf3_msi_count=1, + pf0_msix_enable=False, + pf0_msix_table_size=0, + pf0_msix_table_bir=0, + pf0_msix_table_offset=0x00000000, + pf0_msix_pba_bir=0, + pf0_msix_pba_offset=0x00000000, + pf1_msix_enable=False, + pf1_msix_table_size=0, + pf1_msix_table_bir=0, + pf1_msix_table_offset=0x00000000, + pf1_msix_pba_bir=0, + pf1_msix_pba_offset=0x00000000, + pf2_msix_enable=False, + pf2_msix_table_size=0, + pf2_msix_table_bir=0, + pf2_msix_table_offset=0x00000000, + pf2_msix_pba_bir=0, + pf2_msix_pba_offset=0x00000000, + pf3_msix_enable=False, + pf3_msix_table_size=0, + pf3_msix_table_bir=0, + pf3_msix_table_offset=0x00000000, + pf3_msix_pba_bir=0, + pf3_msix_pba_offset=0x00000000, + + # signals + user_clk=dut.clk_250, + user_reset=dut.rst_250, + user_lnk_up=dut.user_lnk_up, + + rq_bus=AxiStreamBus.from_entity(dut.s_axis_rq), + rc_bus=AxiStreamBus.from_entity(dut.m_axis_rc), + cq_bus=AxiStreamBus.from_entity(dut.m_axis_cq), + cc_bus=AxiStreamBus.from_entity(dut.s_axis_cc), + ) + + self.dev.functions[0].configure_bar(0, 64*1024) + + self.rc.make_port().connect(self.dev) + +@cocotb.test +async def test_sanity(dut): + tb = TB(dut) + + await FallingEdge(dut.rst_250) + await Timer(100, 'ns') + + await tb.rc.enumerate() + + mem = tb.rc.mem_pool.alloc_region(16*1024*1024) + + dev = tb.rc.find_device(tb.dev.functions[0].pcie_id) + await dev.enable_device() + await dev.set_master() + + dev_bar0 = dev.bar_window[0] + + tb.log.info(dev_bar0.write) + + message = b"Hello, world! This is a long string of data with many letters and words." + + await mem.write(0, message) + + await dev_bar0.write_dword(0x0, 0x00000000) + await dev_bar0.write_dword(0x4, 0x00000000) + await dev_bar0.write_dword(0x8, 0x00000000) + await dev_bar0.write_dword(0xc, len(message)) + await dev_bar0.write_dword(0x10, 0x00000001) + + + await Timer(10, "us") \ No newline at end of file diff --git a/sim/alibaba_pcie.yaml b/sim/alibaba_pcie.yaml new file mode 100644 index 0000000..180896b --- /dev/null +++ b/sim/alibaba_pcie.yaml @@ -0,0 +1,10 @@ +tests: + - name: "alibaba_pcie" + toplevel: "alibaba_pcie" + modules: + - "alibaba_pcie" + sources: "../sources.list" + waves: True + +defines: + SIM: "" \ No newline at end of file diff --git a/sources.list b/sources.list index f0906fd..90d63b9 100644 --- a/sources.list +++ b/sources.list @@ -1,4 +1,8 @@ ip/pcie4_uscale_plus_0/pcie4_uscale_plus_0.xci src/alibaba_cloud.xdc src/alibaba_pcie_top.sv +src/regs/verilator.vlt +src/regs/pcie_dma_regs_pkg.sv +src/regs/pcie_dma_regs.sv +src/pcie_dma_wrapper.sv sub/taxi_sources.list diff --git a/src/alibaba_pcie_top.sv b/src/alibaba_pcie_top.sv index 894c819..f20d6ee 100644 --- a/src/alibaba_pcie_top.sv +++ b/src/alibaba_pcie_top.sv @@ -48,14 +48,15 @@ logic phy_rdy_out; taxi_axis_if #(.DATA_W(256), .USER_EN(1), .USER_W(33), .KEEP_W(8)) s_axis_cc(); taxi_axis_if #(.DATA_W(256), .USER_EN(1), .USER_W(88), .KEEP_W(8)) m_axis_cq(); -taxi_axis_if #(.DATA_W(256), .USER_EN(1), .USER_W(85), .KEEP_W(8)) s_axis_rq(); +taxi_axis_if #(.DATA_W(256), .USER_EN(1), .USER_W(62), .KEEP_W(8)) s_axis_rq(); taxi_axis_if #(.DATA_W(256), .USER_EN(1), .USER_W(75), .KEEP_W(8)) m_axis_rc(); taxi_axil_if m_axil_rd(); taxi_axil_if m_axil_wr(); -taxi_apb_if m_apb(); +taxi_apb_if #(.ADDR_W(5)) m_apb(); +`ifndef SIM IBUFDS_GTE4 m_ibufds ( .CEB('0), .I(pcie_mgt_refclk_p), @@ -63,6 +64,7 @@ IBUFDS_GTE4 m_ibufds ( .O(clk_pcie_gt), .ODIV2(clk_pcie) ); +`endif assign Led_o[0] = user_lnk_up; assign Led_o[1] = phy_rdy_out; @@ -85,8 +87,8 @@ taxi_pcie_us_axil_master u_taxi_pcie_us_axil_master ( ); taxi_axil_apb_adapter u_taxi_axil_apb_adapter ( - .clk (clk), - .rst (rst), + .clk (clk_250), + .rst (rst_250), .s_axil_wr (m_axil_wr), .s_axil_rd (m_axil_rd), @@ -104,6 +106,7 @@ pcie_dma_wrapper u_pcie_dma_wrapper ( .s_apb (m_apb) ); +`ifndef SIM pcie4_uscale_plus_0 u_pcie4_uscale_plus_0 ( .pci_exp_txn(pci_exp_txn), .pci_exp_txp(pci_exp_txp), @@ -167,5 +170,6 @@ pcie4_uscale_plus_0 u_pcie4_uscale_plus_0 ( .sys_reset(pcie_reset_n), .phy_rdy_out(phy_rdy_out) ); +`endif endmodule diff --git a/src/pcie_dma_wrapper.sv b/src/pcie_dma_wrapper.sv index 5170a7a..e8e1e65 100644 --- a/src/pcie_dma_wrapper.sv +++ b/src/pcie_dma_wrapper.sv @@ -15,14 +15,90 @@ logic [5:0] seq_num_1; logic seq_num_valid_1; -taxi_dma_if_pcie_us #( +taxi_dma_desc_if #(.DST_ADDR_W(16)) rd_desc(); +taxi_dma_desc_if #(.SRC_ADDR_W(16)) wr_desc(); +// the dma just reads and writes from the same memory +taxi_dma_ram_if #(.SEGS(4)) dma_ram_if(); + +pcie_dma_regs_pkg::pcie_dma_regs__in_t hwif_in; +pcie_dma_regs_pkg::pcie_dma_regs__out_t hwif_out; + +pcie_dma_regs u_pcie_dma_regs( + .clk (clk), + .rst (rst), + + .s_apb_psel (s_apb.psel), + .s_apb_penable (s_apb.penable), + .s_apb_pwrite (s_apb.pwrite), + .s_apb_pprot (s_apb.pprot), + .s_apb_paddr (s_apb.paddr), + .s_apb_pwdata (s_apb.pwdata), + .s_apb_pstrb (s_apb.pstrb), + .s_apb_pready (s_apb.pready), + .s_apb_prdata (s_apb.prdata), + .s_apb_pslverr (s_apb.pslverr), + + .hwif_in (hwif_in), + .hwif_out (hwif_out) +); + +taxi_dma_psdpram #( + .SIZE(16384) +) u_taxi_dma_psdpram ( + .clk (clk), + .rst (rst), + + .dma_ram_wr (dma_ram_if), + .dma_ram_rd (dma_ram_if) +); + +logic [7:0] read_tag; + +always_ff @(posedge clk) begin + if (rst) begin + read_tag <= '0; + end else begin + if (rd_desc.req_valid && rd_desc.req_ready) begin + read_tag <= read_tag + 1; + end + end +end + + +always_comb begin + rd_desc.req_src_addr = {hwif_out.dma_rd.src_addr_high.addr.value, hwif_out.dma_rd.src_addr_low.addr.value}; + rd_desc.req_src_sel = '0; + rd_desc.req_dst_addr = hwif_out.dma_rd.dst_addr.addr.value; + rd_desc.req_dst_sel = '0; + rd_desc.req_imm = '0; + rd_desc.req_imm_en = '0; + rd_desc.req_len = hwif_out.dma_rd.length.len.value; + rd_desc.req_tag = read_tag; + rd_desc.req_id = '0; + rd_desc.req_dest = '0; + rd_desc.req_user = '0; + + rd_desc.req_valid = hwif_out.dma_rd.trigger.trigger.value; + + hwif_in.dma_rd.trigger.trigger.hwclr = (rd_desc.req_valid && rd_desc.req_ready); + + hwif_in.dma_rd.done.done.hwset = rd_desc.sts_valid; +end + + +taxi_dma_if_pcie_us #( + // disable flow control, shouldn't be needed + .RD_TX_FC_EN('0), + .WR_TX_FC_EN('0), + .PCIE_TAG_CNT(256), + .RD_CPLH_FC_LIMIT(512) ) u_taxi_dma_if_pcie_us ( .clk (clk), .rst (rst), .m_axis_rq (m_axis_rq), - .m_axis_rc (m_axis_rc), + .s_axis_rc (s_axis_rc), .s_axis_rq_seq_num_0 (seq_num_0), .s_axis_rq_seq_num_valid_0 (seq_num_valid_0), @@ -32,6 +108,61 @@ taxi_dma_if_pcie_us #( .pcie_tx_fc_nph_av ('0), .pcie_tx_fc_ph_av ('0), .pcie_tx_fc_pd_av ('0), + + .rd_desc_req (rd_desc), + .rd_desc_sts (rd_desc), + + .wr_desc_req (wr_desc), + .wr_desc_sts (wr_desc), + + .dma_ram_wr (dma_ram_if), + .dma_ram_rd (dma_ram_if), + + .read_enable ('1), + .write_enable ('1), + .ext_tag_en ('0), + .rcb_128b ('0), // not sure what this actually does + .requester_id ('0), + .requester_id_en ('0), + .max_rd_req_size (3'b010), + .max_payload_size ('0), + + .stat_rd_busy (), + .stat_wr_busy (), + .stat_err_cor (), + .stat_err_uncor (), + + .stat_rd_op_start_tag (), + .stat_rd_op_start_valid (), + .stat_rd_op_finish_tag (), + .stat_rd_op_finish_status (), + .stat_rd_op_finish_valid (), + .stat_rd_req_start_tag (), + .stat_rd_req_start_len (), + .stat_rd_req_start_valid (), + .stat_rd_req_finish_tag (), + .stat_rd_req_finish_status (), + .stat_rd_req_finish_valid (), + .stat_rd_req_timeout (), + .stat_rd_op_tbl_full (), + .stat_rd_no_tags (), + .stat_rd_tx_limit (), + .stat_rd_tx_stall (), + .stat_wr_op_start_tag (), + .stat_wr_op_start_valid (), + .stat_wr_op_finish_tag (), + .stat_wr_op_finish_status (), + .stat_wr_op_finish_valid (), + .stat_wr_req_start_tag (), + .stat_wr_req_start_len (), + .stat_wr_req_start_valid (), + .stat_wr_req_finish_tag (), + .stat_wr_req_finish_status (), + .stat_wr_req_finish_valid (), + .stat_wr_op_tbl_full (), + .stat_wr_tx_limit (), + .stat_wr_tx_stall () + ); endmodule \ No newline at end of file diff --git a/src/regs/compile_regs.sh b/src/regs/compile_regs.sh new file mode 100755 index 0000000..f542ff6 --- /dev/null +++ b/src/regs/compile_regs.sh @@ -0,0 +1 @@ +peakrdl regblock -t pcie_dma_regs pcie_dma_regs.rdl -o . --cpuif apb4-flat \ No newline at end of file diff --git a/src/regs/pcie_dma_regs.rdl b/src/regs/pcie_dma_regs.rdl new file mode 100644 index 0000000..4144083 --- /dev/null +++ b/src/regs/pcie_dma_regs.rdl @@ -0,0 +1,88 @@ +addrmap pcie_dma_regs { + name = "PCIe DMA Regs"; + desc = ""; + + regfile { + reg { + name = "DMA Read Source Address Low"; + desc = "Address which will be read over PCIe (System Address)"; + + field { + name = "addr"; + desc = ""; + hw = r; + sw = rw; + } addr[31:0] = 0x0; + + } src_addr_low @ 0x0; + + reg { + name = "DMA Read Source Address High"; + desc = "Address which will be read over PCIe (System Address)"; + + field { + name = "addr"; + desc = ""; + hw = r; + sw = rw; + } addr[31:0] = 0x0; + + } src_addr_high @ 0x4; + + reg { + name = "DMA Read Dest Address"; + desc = "Address where data will be written on chip (Local Address)"; + + field { + name = "addr"; + desc = ""; + hw = r; + sw = rw; + } addr[15:0] = 0x0; + + } dst_addr @ 0x8; + + reg { + name = "Length"; + desc = ""; + + field { + name = "Length"; + desc = ""; + hw = r; + sw = rw; + } len[15:0] = 0x0; + + } length @ 0xc; + + reg { + name = "Trigger"; + desc = "Trigger DMA"; + + field { + name = "Trigger"; + desc = ""; + hwclr; + + hw = r; + sw = w; + } trigger[0:0] = 0x0; + + } trigger @ 0x10; + + reg { + name = "Done"; + desc = "DMA is done"; + + field { + name = "Done"; + desc = ""; + hwset; + rclr; + hw = r; + sw = r; + } done[0:0] = 0x0; + + } done @ 0x14; + } dma_rd @ 0x0; +}; \ No newline at end of file diff --git a/src/regs/pcie_dma_regs.sv b/src/regs/pcie_dma_regs.sv new file mode 100644 index 0000000..c3b2097 --- /dev/null +++ b/src/regs/pcie_dma_regs.sv @@ -0,0 +1,391 @@ +// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-regblock + +module pcie_dma_regs ( + input wire clk, + input wire rst, + + input wire s_apb_psel, + input wire s_apb_penable, + input wire s_apb_pwrite, + input wire [2:0] s_apb_pprot, + input wire [4:0] s_apb_paddr, + input wire [31:0] s_apb_pwdata, + input wire [3:0] s_apb_pstrb, + output logic s_apb_pready, + output logic [31:0] s_apb_prdata, + output logic s_apb_pslverr, + + input pcie_dma_regs_pkg::pcie_dma_regs__in_t hwif_in, + output pcie_dma_regs_pkg::pcie_dma_regs__out_t hwif_out + ); + + //-------------------------------------------------------------------------- + // CPU Bus interface logic + //-------------------------------------------------------------------------- + logic cpuif_req; + logic cpuif_req_is_wr; + logic [4:0] cpuif_addr; + logic [31:0] cpuif_wr_data; + logic [31:0] cpuif_wr_biten; + logic cpuif_req_stall_wr; + logic cpuif_req_stall_rd; + + logic cpuif_rd_ack; + logic cpuif_rd_err; + logic [31:0] cpuif_rd_data; + + logic cpuif_wr_ack; + logic cpuif_wr_err; + + // Request + logic is_active; + always_ff @(posedge clk) begin + if(rst) begin + is_active <= '0; + cpuif_req <= '0; + cpuif_req_is_wr <= '0; + cpuif_addr <= '0; + cpuif_wr_data <= '0; + cpuif_wr_biten <= '0; + end else begin + if(~is_active) begin + if(s_apb_psel) begin + is_active <= '1; + cpuif_req <= '1; + cpuif_req_is_wr <= s_apb_pwrite; + cpuif_addr <= {s_apb_paddr[4:2], 2'b0}; + cpuif_wr_data <= s_apb_pwdata; + for(int i=0; i<4; i++) begin + cpuif_wr_biten[i*8 +: 8] <= {8{s_apb_pstrb[i]}}; + end + end + end else begin + cpuif_req <= '0; + if(cpuif_rd_ack || cpuif_wr_ack) begin + is_active <= '0; + end + end + end + end + + // Response + assign s_apb_pready = cpuif_rd_ack | cpuif_wr_ack; + assign s_apb_prdata = cpuif_rd_data; + assign s_apb_pslverr = cpuif_rd_err | cpuif_wr_err; + + logic cpuif_req_masked; + + // Read & write latencies are balanced. Stalls not required + assign cpuif_req_stall_rd = '0; + assign cpuif_req_stall_wr = '0; + assign cpuif_req_masked = cpuif_req + & !(!cpuif_req_is_wr & cpuif_req_stall_rd) + & !(cpuif_req_is_wr & cpuif_req_stall_wr); + + //-------------------------------------------------------------------------- + // Address Decode + //-------------------------------------------------------------------------- + typedef struct { + struct { + logic src_addr_low; + logic src_addr_high; + logic dst_addr; + logic length; + logic trigger; + logic done; + } dma_rd; + } decoded_reg_strb_t; + decoded_reg_strb_t decoded_reg_strb; + logic decoded_err; + logic decoded_req; + logic decoded_req_is_wr; + logic [31:0] decoded_wr_data; + logic [31:0] decoded_wr_biten; + + always_comb begin + automatic logic is_valid_addr; + automatic logic is_invalid_rw; + is_valid_addr = '1; // No error checking on valid address access + is_invalid_rw = '0; + decoded_reg_strb.dma_rd.src_addr_low = cpuif_req_masked & (cpuif_addr == 5'h0); + decoded_reg_strb.dma_rd.src_addr_high = cpuif_req_masked & (cpuif_addr == 5'h4); + decoded_reg_strb.dma_rd.dst_addr = cpuif_req_masked & (cpuif_addr == 5'h8); + decoded_reg_strb.dma_rd.length = cpuif_req_masked & (cpuif_addr == 5'hc); + decoded_reg_strb.dma_rd.trigger = cpuif_req_masked & (cpuif_addr == 5'h10) & cpuif_req_is_wr; + decoded_reg_strb.dma_rd.done = cpuif_req_masked & (cpuif_addr == 5'h14) & !cpuif_req_is_wr; + decoded_err = (~is_valid_addr | is_invalid_rw) & decoded_req; + end + + // Pass down signals to next stage + assign decoded_req = cpuif_req_masked; + assign decoded_req_is_wr = cpuif_req_is_wr; + assign decoded_wr_data = cpuif_wr_data; + assign decoded_wr_biten = cpuif_wr_biten; + + //-------------------------------------------------------------------------- + // Field logic + //-------------------------------------------------------------------------- + typedef struct { + struct { + struct { + struct { + logic [31:0] next; + logic load_next; + } addr; + } src_addr_low; + struct { + struct { + logic [31:0] next; + logic load_next; + } addr; + } src_addr_high; + struct { + struct { + logic [15:0] next; + logic load_next; + } addr; + } dst_addr; + struct { + struct { + logic [15:0] next; + logic load_next; + } len; + } length; + struct { + struct { + logic next; + logic load_next; + } trigger; + } trigger; + struct { + struct { + logic next; + logic load_next; + } done; + } done; + } dma_rd; + } field_combo_t; + field_combo_t field_combo; + + typedef struct { + struct { + struct { + struct { + logic [31:0] value; + } addr; + } src_addr_low; + struct { + struct { + logic [31:0] value; + } addr; + } src_addr_high; + struct { + struct { + logic [15:0] value; + } addr; + } dst_addr; + struct { + struct { + logic [15:0] value; + } len; + } length; + struct { + struct { + logic value; + } trigger; + } trigger; + struct { + struct { + logic value; + } done; + } done; + } dma_rd; + } field_storage_t; + field_storage_t field_storage; + + // Field: pcie_dma_regs.dma_rd.src_addr_low.addr + always_comb begin + automatic logic [31:0] next_c; + automatic logic load_next_c; + next_c = field_storage.dma_rd.src_addr_low.addr.value; + load_next_c = '0; + if(decoded_reg_strb.dma_rd.src_addr_low && decoded_req_is_wr) begin // SW write + next_c = (field_storage.dma_rd.src_addr_low.addr.value & ~decoded_wr_biten[31:0]) | (decoded_wr_data[31:0] & decoded_wr_biten[31:0]); + load_next_c = '1; + end + field_combo.dma_rd.src_addr_low.addr.next = next_c; + field_combo.dma_rd.src_addr_low.addr.load_next = load_next_c; + end + always_ff @(posedge clk) begin + if(rst) begin + field_storage.dma_rd.src_addr_low.addr.value <= 32'h0; + end else begin + if(field_combo.dma_rd.src_addr_low.addr.load_next) begin + field_storage.dma_rd.src_addr_low.addr.value <= field_combo.dma_rd.src_addr_low.addr.next; + end + end + end + assign hwif_out.dma_rd.src_addr_low.addr.value = field_storage.dma_rd.src_addr_low.addr.value; + // Field: pcie_dma_regs.dma_rd.src_addr_high.addr + always_comb begin + automatic logic [31:0] next_c; + automatic logic load_next_c; + next_c = field_storage.dma_rd.src_addr_high.addr.value; + load_next_c = '0; + if(decoded_reg_strb.dma_rd.src_addr_high && decoded_req_is_wr) begin // SW write + next_c = (field_storage.dma_rd.src_addr_high.addr.value & ~decoded_wr_biten[31:0]) | (decoded_wr_data[31:0] & decoded_wr_biten[31:0]); + load_next_c = '1; + end + field_combo.dma_rd.src_addr_high.addr.next = next_c; + field_combo.dma_rd.src_addr_high.addr.load_next = load_next_c; + end + always_ff @(posedge clk) begin + if(rst) begin + field_storage.dma_rd.src_addr_high.addr.value <= 32'h0; + end else begin + if(field_combo.dma_rd.src_addr_high.addr.load_next) begin + field_storage.dma_rd.src_addr_high.addr.value <= field_combo.dma_rd.src_addr_high.addr.next; + end + end + end + assign hwif_out.dma_rd.src_addr_high.addr.value = field_storage.dma_rd.src_addr_high.addr.value; + // Field: pcie_dma_regs.dma_rd.dst_addr.addr + always_comb begin + automatic logic [15:0] next_c; + automatic logic load_next_c; + next_c = field_storage.dma_rd.dst_addr.addr.value; + load_next_c = '0; + if(decoded_reg_strb.dma_rd.dst_addr && decoded_req_is_wr) begin // SW write + next_c = (field_storage.dma_rd.dst_addr.addr.value & ~decoded_wr_biten[15:0]) | (decoded_wr_data[15:0] & decoded_wr_biten[15:0]); + load_next_c = '1; + end + field_combo.dma_rd.dst_addr.addr.next = next_c; + field_combo.dma_rd.dst_addr.addr.load_next = load_next_c; + end + always_ff @(posedge clk) begin + if(rst) begin + field_storage.dma_rd.dst_addr.addr.value <= 16'h0; + end else begin + if(field_combo.dma_rd.dst_addr.addr.load_next) begin + field_storage.dma_rd.dst_addr.addr.value <= field_combo.dma_rd.dst_addr.addr.next; + end + end + end + assign hwif_out.dma_rd.dst_addr.addr.value = field_storage.dma_rd.dst_addr.addr.value; + // Field: pcie_dma_regs.dma_rd.length.len + always_comb begin + automatic logic [15:0] next_c; + automatic logic load_next_c; + next_c = field_storage.dma_rd.length.len.value; + load_next_c = '0; + if(decoded_reg_strb.dma_rd.length && decoded_req_is_wr) begin // SW write + next_c = (field_storage.dma_rd.length.len.value & ~decoded_wr_biten[15:0]) | (decoded_wr_data[15:0] & decoded_wr_biten[15:0]); + load_next_c = '1; + end + field_combo.dma_rd.length.len.next = next_c; + field_combo.dma_rd.length.len.load_next = load_next_c; + end + always_ff @(posedge clk) begin + if(rst) begin + field_storage.dma_rd.length.len.value <= 16'h0; + end else begin + if(field_combo.dma_rd.length.len.load_next) begin + field_storage.dma_rd.length.len.value <= field_combo.dma_rd.length.len.next; + end + end + end + assign hwif_out.dma_rd.length.len.value = field_storage.dma_rd.length.len.value; + // Field: pcie_dma_regs.dma_rd.trigger.trigger + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.dma_rd.trigger.trigger.value; + load_next_c = '0; + if(decoded_reg_strb.dma_rd.trigger && decoded_req_is_wr) begin // SW write + next_c = (field_storage.dma_rd.trigger.trigger.value & ~decoded_wr_biten[0:0]) | (decoded_wr_data[0:0] & decoded_wr_biten[0:0]); + load_next_c = '1; + end else if(hwif_in.dma_rd.trigger.trigger.hwclr) begin // HW Clear + next_c = '0; + load_next_c = '1; + end + field_combo.dma_rd.trigger.trigger.next = next_c; + field_combo.dma_rd.trigger.trigger.load_next = load_next_c; + end + always_ff @(posedge clk) begin + if(rst) begin + field_storage.dma_rd.trigger.trigger.value <= 1'h0; + end else begin + if(field_combo.dma_rd.trigger.trigger.load_next) begin + field_storage.dma_rd.trigger.trigger.value <= field_combo.dma_rd.trigger.trigger.next; + end + end + end + assign hwif_out.dma_rd.trigger.trigger.value = field_storage.dma_rd.trigger.trigger.value; + // Field: pcie_dma_regs.dma_rd.done.done + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.dma_rd.done.done.value; + load_next_c = '0; + if(decoded_reg_strb.dma_rd.done && !decoded_req_is_wr) begin // SW clear on read + next_c = '0; + load_next_c = '1; + end else if(hwif_in.dma_rd.done.done.hwset) begin // HW Set + next_c = '1; + load_next_c = '1; + end + field_combo.dma_rd.done.done.next = next_c; + field_combo.dma_rd.done.done.load_next = load_next_c; + end + always_ff @(posedge clk) begin + if(rst) begin + field_storage.dma_rd.done.done.value <= 1'h0; + end else begin + if(field_combo.dma_rd.done.done.load_next) begin + field_storage.dma_rd.done.done.value <= field_combo.dma_rd.done.done.next; + end + end + end + assign hwif_out.dma_rd.done.done.value = field_storage.dma_rd.done.done.value; + + //-------------------------------------------------------------------------- + // Write response + //-------------------------------------------------------------------------- + assign cpuif_wr_ack = decoded_req & decoded_req_is_wr; + // Writes are always granted with no error response + assign cpuif_wr_err = '0; + + //-------------------------------------------------------------------------- + // Readback + //-------------------------------------------------------------------------- + + logic readback_err; + logic readback_done; + logic [31:0] readback_data; + + // Assign readback values to a flattened array + logic [31:0] readback_array[5]; + assign readback_array[0][31:0] = (decoded_reg_strb.dma_rd.src_addr_low && !decoded_req_is_wr) ? field_storage.dma_rd.src_addr_low.addr.value : '0; + assign readback_array[1][31:0] = (decoded_reg_strb.dma_rd.src_addr_high && !decoded_req_is_wr) ? field_storage.dma_rd.src_addr_high.addr.value : '0; + assign readback_array[2][15:0] = (decoded_reg_strb.dma_rd.dst_addr && !decoded_req_is_wr) ? field_storage.dma_rd.dst_addr.addr.value : '0; + assign readback_array[2][31:16] = '0; + assign readback_array[3][15:0] = (decoded_reg_strb.dma_rd.length && !decoded_req_is_wr) ? field_storage.dma_rd.length.len.value : '0; + assign readback_array[3][31:16] = '0; + assign readback_array[4][0:0] = (decoded_reg_strb.dma_rd.done && !decoded_req_is_wr) ? field_storage.dma_rd.done.done.value : '0; + assign readback_array[4][31:1] = '0; + + // Reduce the array + always_comb begin + automatic logic [31:0] readback_data_var; + readback_done = decoded_req & ~decoded_req_is_wr; + readback_err = '0; + readback_data_var = '0; + for(int i=0; i<5; i++) readback_data_var |= readback_array[i]; + readback_data = readback_data_var; + end + + assign cpuif_rd_ack = readback_done; + assign cpuif_rd_data = readback_data; + assign cpuif_rd_err = readback_err; +endmodule diff --git a/src/regs/pcie_dma_regs_pkg.sv b/src/regs/pcie_dma_regs_pkg.sv new file mode 100644 index 0000000..ccf5eb1 --- /dev/null +++ b/src/regs/pcie_dma_regs_pkg.sv @@ -0,0 +1,95 @@ +// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-regblock + +package pcie_dma_regs_pkg; + + localparam PCIE_DMA_REGS_DATA_WIDTH = 32; + localparam PCIE_DMA_REGS_MIN_ADDR_WIDTH = 5; + localparam PCIE_DMA_REGS_SIZE = 'h18; + + typedef struct { + logic hwclr; + } pcie_dma_regs__dma_rd__trigger__trigger__in_t; + + typedef struct { + pcie_dma_regs__dma_rd__trigger__trigger__in_t trigger; + } pcie_dma_regs__dma_rd__trigger__in_t; + + typedef struct { + logic hwset; + } pcie_dma_regs__dma_rd__done__done__in_t; + + typedef struct { + pcie_dma_regs__dma_rd__done__done__in_t done; + } pcie_dma_regs__dma_rd__done__in_t; + + typedef struct { + pcie_dma_regs__dma_rd__trigger__in_t trigger; + pcie_dma_regs__dma_rd__done__in_t done; + } pcie_dma_regs__dma_rd__in_t; + + typedef struct { + pcie_dma_regs__dma_rd__in_t dma_rd; + } pcie_dma_regs__in_t; + + typedef struct { + logic [31:0] value; + } pcie_dma_regs__dma_rd__src_addr_low__addr__out_t; + + typedef struct { + pcie_dma_regs__dma_rd__src_addr_low__addr__out_t addr; + } pcie_dma_regs__dma_rd__src_addr_low__out_t; + + typedef struct { + logic [31:0] value; + } pcie_dma_regs__dma_rd__src_addr_high__addr__out_t; + + typedef struct { + pcie_dma_regs__dma_rd__src_addr_high__addr__out_t addr; + } pcie_dma_regs__dma_rd__src_addr_high__out_t; + + typedef struct { + logic [15:0] value; + } pcie_dma_regs__dma_rd__dst_addr__addr__out_t; + + typedef struct { + pcie_dma_regs__dma_rd__dst_addr__addr__out_t addr; + } pcie_dma_regs__dma_rd__dst_addr__out_t; + + typedef struct { + logic [15:0] value; + } pcie_dma_regs__dma_rd__length__len__out_t; + + typedef struct { + pcie_dma_regs__dma_rd__length__len__out_t len; + } pcie_dma_regs__dma_rd__length__out_t; + + typedef struct { + logic value; + } pcie_dma_regs__dma_rd__trigger__trigger__out_t; + + typedef struct { + pcie_dma_regs__dma_rd__trigger__trigger__out_t trigger; + } pcie_dma_regs__dma_rd__trigger__out_t; + + typedef struct { + logic value; + } pcie_dma_regs__dma_rd__done__done__out_t; + + typedef struct { + pcie_dma_regs__dma_rd__done__done__out_t done; + } pcie_dma_regs__dma_rd__done__out_t; + + typedef struct { + pcie_dma_regs__dma_rd__src_addr_low__out_t src_addr_low; + pcie_dma_regs__dma_rd__src_addr_high__out_t src_addr_high; + pcie_dma_regs__dma_rd__dst_addr__out_t dst_addr; + pcie_dma_regs__dma_rd__length__out_t length; + pcie_dma_regs__dma_rd__trigger__out_t trigger; + pcie_dma_regs__dma_rd__done__out_t done; + } pcie_dma_regs__dma_rd__out_t; + + typedef struct { + pcie_dma_regs__dma_rd__out_t dma_rd; + } pcie_dma_regs__out_t; +endpackage diff --git a/src/regs/verilator.vlt b/src/regs/verilator.vlt new file mode 100644 index 0000000..d663d2f --- /dev/null +++ b/src/regs/verilator.vlt @@ -0,0 +1,4 @@ +`verilator_config + +lint_off -rule MULTIDRIVEN -file "**/regs/*" +lint_off -file "**/regs/*" \ No newline at end of file diff --git a/sub/taxi_sources.list b/sub/taxi_sources.list index d15bd55..d33f78d 100644 --- a/sub/taxi_sources.list +++ b/sub/taxi_sources.list @@ -63,3 +63,25 @@ taxi/src/pcie/rtl/taxi_pcie_us_axil_master.sv taxi/src/pcie/rtl/taxi_pcie_tlp_if.sv taxi/src/pcie/rtl/taxi_pcie_axil_master.sv taxi/src/pcie/rtl/taxi_pcie_axil_master_minimal.sv +taxi/src/dma/rtl/taxi_axi_cdma.sv +taxi/src/dma/rtl/taxi_axi_dma.f +taxi/src/dma/rtl/taxi_axi_dma.sv +taxi/src/dma/rtl/taxi_axi_dma_rd.sv +taxi/src/dma/rtl/taxi_axi_dma_wr.sv +taxi/src/dma/rtl/taxi_dma_client_axis_sink.sv +taxi/src/dma/rtl/taxi_dma_client_axis_source.sv +taxi/src/dma/rtl/taxi_dma_desc_if.sv +taxi/src/dma/rtl/taxi_dma_if_axi.f +taxi/src/dma/rtl/taxi_dma_if_axi.sv +taxi/src/dma/rtl/taxi_dma_if_axi_rd.sv +taxi/src/dma/rtl/taxi_dma_if_axi_wr.sv +taxi/src/dma/rtl/taxi_dma_if_pcie_us.f +taxi/src/dma/rtl/taxi_dma_if_pcie_us.sv +taxi/src/dma/rtl/taxi_dma_if_pcie_us_rd.sv +taxi/src/dma/rtl/taxi_dma_if_pcie_us_wr.sv +taxi/src/dma/rtl/taxi_dma_psdpram.sv +taxi/src/dma/rtl/taxi_dma_psdpram_async.sv +taxi/src/dma/rtl/taxi_dma_ram_if.sv +taxi/src/apb/rtl/taxi_apb_dp_ram.sv +taxi/src/apb/rtl/taxi_apb_if.sv +taxi/src/apb/rtl/taxi_apb_ram.sv