diff --git a/src/cndm/modules/cndm/Makefile b/src/cndm/modules/cndm/Makefile index d66c86e..61f567e 100644 --- a/src/cndm/modules/cndm/Makefile +++ b/src/cndm/modules/cndm/Makefile @@ -7,6 +7,7 @@ obj-m += cndm.o cndm-y += cndm_main.o cndm-y += cndm_devlink.o cndm-y += cndm_irq.o +cndm-y += cndm_cmd.o cndm-y += cndm_dev.o cndm-y += cndm_netdev.o cndm-y += cndm_ethtool.o diff --git a/src/cndm/modules/cndm/cndm.h b/src/cndm/modules/cndm/cndm.h index 7a36b9d..26b7a81 100644 --- a/src/cndm/modules/cndm/cndm.h +++ b/src/cndm/modules/cndm/cndm.h @@ -20,6 +20,8 @@ Authors: #include #include +#include "cndm_hw.h" + #define DRIVER_VERSION "0.1" #define CNDM_MAX_IRQ 256 @@ -105,6 +107,7 @@ struct cndm_priv { u32 txq_mask; u32 txq_prod; u32 txq_cons; + u32 txq_db_offs; size_t rxq_region_len; void *rxq_region; @@ -115,6 +118,7 @@ struct cndm_priv { u32 rxq_mask; u32 rxq_prod; u32 rxq_cons; + u32 rxq_db_offs; size_t txcq_region_len; void *txcq_region; @@ -137,20 +141,9 @@ struct cndm_priv { u32 rxcq_cons; }; -struct cndm_desc { - __u8 rsvd[4]; - __le32 len; - __le64 addr; -}; - -struct cndm_cpl { - __u8 rsvd[4]; - __le32 len; - __le32 ts_ns; - __le16 ts_fns; - __u8 ts_s; - __u8 phase; -}; +// cndm_cmd.c +int cndm_exec_mbox_cmd(struct cndm_dev *cdev, void *cmd, void *rsp); +int cndm_exec_cmd(struct cndm_dev *cdev, void *cmd, void *rsp); // cndm_devlink.c struct devlink *cndm_devlink_alloc(struct device *dev); @@ -161,7 +154,7 @@ int cndm_irq_init_pcie(struct cndm_dev *cdev); void cndm_irq_deinit_pcie(struct cndm_dev *cdev); // cndm_netdev.c -struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port, void __iomem *hw_addr); +struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port); void cndm_destroy_netdev(struct net_device *ndev); // cndm_dev.c diff --git a/src/cndm/modules/cndm/cndm_cmd.c b/src/cndm/modules/cndm/cndm_cmd.c new file mode 100644 index 0000000..3cde67a --- /dev/null +++ b/src/cndm/modules/cndm/cndm_cmd.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL +/* + +Copyright (c) 2026 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +#include "cndm.h" + +int cndm_exec_mbox_cmd(struct cndm_dev *cdev, void *cmd, void *rsp) +{ + int k; + + if (!cmd || !rsp) + return -EINVAL; + + // write command to mailbox + for (k = 0; k < 16; k++) { + iowrite32(*((u32 *)(cmd + k*4)), cdev->hw_addr + 0x10000 + k*4); + } + + // execute it + iowrite32(0x00000001, cdev->hw_addr + 0x0200); + + // wait for completion + for (k = 0; k < 10; k++) { + if ((ioread32(cdev->hw_addr + 0x0200) & 0x00000001) == 0) { + break; + } + + udelay(100); + } + + // read response from mailbox + for (k = 0; k < 16; k++) { + *((u32 *)(rsp + k*4)) = ioread32(cdev->hw_addr + 0x10000 + 0x40 + k*4); + } + return 0; +} + +int cndm_exec_cmd(struct cndm_dev *cdev, void *cmd, void *rsp) +{ + return cndm_exec_mbox_cmd(cdev, cmd, rsp); +} diff --git a/src/cndm/modules/cndm/cndm_hw.h b/src/cndm/modules/cndm/cndm_hw.h new file mode 100644 index 0000000..a43b70d --- /dev/null +++ b/src/cndm/modules/cndm/cndm_hw.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL */ +/* + +Copyright (c) 2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +#ifndef CNDM_HW_H +#define CNDM_HW_H + +#include + +#define CNDM_CMD_OP_NOP 0x0000 + +#define CNDM_CMD_OP_CREATE_EQ 0x0200 +#define CNDM_CMD_OP_MODIFY_EQ 0x0201 +#define CNDM_CMD_OP_QUERY_EQ 0x0202 +#define CNDM_CMD_OP_DESTROY_EQ 0x0203 + +#define CNDM_CMD_OP_CREATE_CQ 0x0210 +#define CNDM_CMD_OP_MODIFY_CQ 0x0211 +#define CNDM_CMD_OP_QUERY_CQ 0x0212 +#define CNDM_CMD_OP_DESTROY_CQ 0x0213 + +#define CNDM_CMD_OP_CREATE_SQ 0x0220 +#define CNDM_CMD_OP_MODIFY_SQ 0x0221 +#define CNDM_CMD_OP_QUERY_SQ 0x0222 +#define CNDM_CMD_OP_DESTROY_SQ 0x0223 + +#define CNDM_CMD_OP_CREATE_RQ 0x0230 +#define CNDM_CMD_OP_MODIFY_RQ 0x0231 +#define CNDM_CMD_OP_QUERY_RQ 0x0232 +#define CNDM_CMD_OP_DESTROY_RQ 0x0233 + +#define CNDM_CMD_OP_CREATE_QP 0x0240 +#define CNDM_CMD_OP_MODIFY_QP 0x0241 +#define CNDM_CMD_OP_QUERY_QP 0x0242 +#define CNDM_CMD_OP_DESTROY_QP 0x0243 + +struct cndm_cmd { + __le16 rsvd; + union { + __le16 opcode; + __le16 status; + }; + __le32 flags; + __le32 port; + __le32 qn; + + __le32 qn2; + __le32 pd; + __le32 size; + __le32 dboffs; + + __le64 ptr1; + __le64 ptr2; + + __le32 dw12; + __le32 dw13; + __le32 dw14; + __le32 dw15; +}; + +struct cndm_desc { + __le16 rsvd0; + union { + struct { + __le16 csum_cmd; + } tx; + struct { + __le16 rsvd0; + } rx; + }; + + __le32 len; + __le64 addr; +}; + +struct cndm_cpl { + __u8 rsvd[4]; + __le32 len; + __le32 ts_ns; + __le16 ts_fns; + __u8 ts_s; + __u8 phase; +}; + +struct cndm_event { + __le16 type; + __le16 source; + __le32 rsvd0; + __le32 rsvd1; + __le32 rsvd2; + __le32 rsvd3; + __le32 rsvd4; + __le32 rsvd5; + __le32 phase; +}; + +#endif diff --git a/src/cndm/modules/cndm/cndm_main.c b/src/cndm/modules/cndm/cndm_main.c index c0c11d6..7951a79 100644 --- a/src/cndm/modules/cndm/cndm_main.c +++ b/src/cndm/modules/cndm/cndm_main.c @@ -9,6 +9,7 @@ Authors: */ #include "cndm.h" +#include "cndm_hw.h" #include #include #include @@ -68,7 +69,7 @@ static int cndm_common_probe(struct cndm_dev *cdev) for (k = 0; k < cdev->port_count; k++) { struct net_device *ndev; - ndev = cndm_create_netdev(cdev, k, cdev->hw_addr + cdev->port_offset + (cdev->port_stride*k)); + ndev = cndm_create_netdev(cdev, k); if (IS_ERR_OR_NULL(ndev)) { ret = PTR_ERR(ndev); goto fail_netdev; diff --git a/src/cndm/modules/cndm/cndm_netdev.c b/src/cndm/modules/cndm/cndm_netdev.c index d562260..ca63eac 100644 --- a/src/cndm/modules/cndm/cndm_netdev.c +++ b/src/cndm/modules/cndm/cndm_netdev.c @@ -9,6 +9,7 @@ Authors: */ #include "cndm.h" +#include "cndm_hw.h" #include @@ -170,13 +171,16 @@ static int cndm_netdev_irq(struct notifier_block *nb, unsigned long action, void return NOTIFY_DONE; } -struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port, void __iomem *hw_addr) +struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port) { struct device *dev = cdev->dev; struct net_device *ndev; struct cndm_priv *priv; int ret = 0; + struct cndm_cmd cmd; + struct cndm_cmd rsp; + ndev = alloc_etherdev_mqs(sizeof(*priv), 1, 1); if (!ndev) { dev_err(dev, "Failed to allocate net_device"); @@ -193,7 +197,7 @@ struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port, void __io priv->ndev = ndev; priv->cdev = cdev; - priv->hw_addr = hw_addr; + priv->hw_addr = cdev->hw_addr; netif_set_real_num_tx_queues(ndev, 1); netif_set_real_num_rx_queues(ndev, 1); @@ -281,27 +285,61 @@ struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port, void __io goto fail; } - iowrite32(0x00000000, priv->hw_addr + 0x200); - iowrite32(priv->rxq_prod & 0xffff, priv->hw_addr + 0x204); - iowrite32(priv->rxq_region_addr & 0xffffffff, priv->hw_addr + 0x208); - iowrite32(priv->rxq_region_addr >> 32, priv->hw_addr + 0x20c); - iowrite32(0x00000001 | (priv->rxq_log_size << 16), priv->hw_addr + 0x200); + cmd.opcode = CNDM_CMD_OP_CREATE_CQ; + cmd.flags = 0x00000000; + cmd.port = port; + cmd.qn = 0; + cmd.qn2 = 0; + cmd.pd = 0; + cmd.size = priv->rxcq_log_size; + cmd.dboffs = 0; + cmd.ptr1 = priv->rxcq_region_addr; + cmd.ptr2 = 0; - iowrite32(0x00000000, priv->hw_addr + 0x100); - iowrite32(priv->txq_prod & 0xffff, priv->hw_addr + 0x104); - iowrite32(priv->txq_region_addr & 0xffffffff, priv->hw_addr + 0x108); - iowrite32(priv->txq_region_addr >> 32, priv->hw_addr + 0x10c); - iowrite32(0x00000001 | (priv->txq_log_size << 16), priv->hw_addr + 0x100); + cndm_exec_cmd(cdev, &cmd, &rsp); - iowrite32(0x00000000, priv->hw_addr + 0x400); - iowrite32(priv->rxcq_region_addr & 0xffffffff, priv->hw_addr + 0x408); - iowrite32(priv->rxcq_region_addr >> 32, priv->hw_addr + 0x40c); - iowrite32(0x00000001 | (priv->rxcq_log_size << 16), priv->hw_addr + 0x400); + cmd.opcode = CNDM_CMD_OP_CREATE_RQ; + cmd.flags = 0x00000000; + cmd.port = port; + cmd.qn = 0; + cmd.qn2 = 0; + cmd.pd = 0; + cmd.size = priv->rxq_log_size; + cmd.dboffs = 0; + cmd.ptr1 = priv->rxq_region_addr; + cmd.ptr2 = 0; - iowrite32(0x00000000, priv->hw_addr + 0x300); - iowrite32(priv->txcq_region_addr & 0xffffffff, priv->hw_addr + 0x308); - iowrite32(priv->txcq_region_addr >> 32, priv->hw_addr + 0x30c); - iowrite32(0x00000001 | (priv->txcq_log_size << 16), priv->hw_addr + 0x300); + cndm_exec_cmd(cdev, &cmd, &rsp); + + priv->rxq_db_offs = rsp.dboffs; + + cmd.opcode = CNDM_CMD_OP_CREATE_CQ; + cmd.flags = 0x00000000; + cmd.port = port; + cmd.qn = 1; + cmd.qn2 = 0; + cmd.pd = 0; + cmd.size = priv->txcq_log_size; + cmd.dboffs = 0; + cmd.ptr1 = priv->txcq_region_addr; + cmd.ptr2 = 0; + + cndm_exec_cmd(cdev, &cmd, &rsp); + + cmd.opcode = CNDM_CMD_OP_CREATE_SQ; + cmd.flags = 0x00000000; + cmd.port = port; + cmd.qn = 0; + cmd.qn2 = 0; + cmd.pd = 0; + cmd.size = priv->txq_log_size; + cmd.dboffs = 0; + cmd.ptr1 = priv->txq_region_addr; + cmd.ptr2 = 0; + + cndm_exec_cmd(cdev, &cmd, &rsp); + + priv->txq_db_offs = rsp.dboffs; netif_carrier_off(ndev); @@ -332,12 +370,41 @@ fail: void cndm_destroy_netdev(struct net_device *ndev) { struct cndm_priv *priv = netdev_priv(ndev); + struct cndm_dev *cdev = priv->cdev; struct device *dev = priv->dev; - iowrite32(0x00000000, priv->hw_addr + 0x200); - iowrite32(0x00000000, priv->hw_addr + 0x100); - iowrite32(0x00000000, priv->hw_addr + 0x400); - iowrite32(0x00000000, priv->hw_addr + 0x300); + struct cndm_cmd cmd; + struct cndm_cmd rsp; + + cmd.opcode = CNDM_CMD_OP_DESTROY_CQ; + cmd.flags = 0x00000000; + cmd.port = ndev->dev_port; + cmd.qn = 0; + + cndm_exec_cmd(cdev, &cmd, &rsp); + + cmd.opcode = CNDM_CMD_OP_DESTROY_RQ; + cmd.flags = 0x00000000; + cmd.port = ndev->dev_port; + cmd.qn = 0; + + cndm_exec_cmd(cdev, &cmd, &rsp); + + priv->rxq_db_offs = rsp.dboffs; + + cmd.opcode = CNDM_CMD_OP_DESTROY_CQ; + cmd.flags = 0x00000000; + cmd.port = ndev->dev_port; + cmd.qn = 1; + + cndm_exec_cmd(cdev, &cmd, &rsp); + + cmd.opcode = CNDM_CMD_OP_DESTROY_SQ; + cmd.flags = 0x00000000; + cmd.port = ndev->dev_port; + cmd.qn = 0; + + cndm_exec_cmd(cdev, &cmd, &rsp); if (priv->irq) atomic_notifier_chain_unregister(&priv->irq->nh, &priv->irq_nb); diff --git a/src/cndm/modules/cndm/cndm_ptp.c b/src/cndm/modules/cndm/cndm_ptp.c index a9e7c9b..2c33ecc 100644 --- a/src/cndm/modules/cndm/cndm_ptp.c +++ b/src/cndm/modules/cndm/cndm_ptp.c @@ -148,12 +148,12 @@ void cndm_register_phc(struct cndm_dev *cdev) } // TODO - if (cdev->port_offset == 0x10000) { + if (cdev->port_offset == 0x20000) { dev_info(cdev->dev, "PTP clock not present"); return; } - cdev->phc_regs = cdev->hw_addr + 0x10000; // TODO + cdev->phc_regs = cdev->hw_addr + 0x20000; // TODO cdev->ptp_clock_info.owner = THIS_MODULE; snprintf(cdev->ptp_clock_info.name, sizeof(cdev->ptp_clock_info.name), "%s_phc", cdev->name); diff --git a/src/cndm/modules/cndm/cndm_rx.c b/src/cndm/modules/cndm/cndm_rx.c index 63f5fbd..05e00ae 100644 --- a/src/cndm/modules/cndm/cndm_rx.c +++ b/src/cndm/modules/cndm/cndm_rx.c @@ -92,7 +92,7 @@ int cndm_refill_rx_buffers(struct cndm_priv *priv) } dma_wmb(); - iowrite32(priv->rxq_prod & 0xffff, priv->hw_addr + 0x204); + iowrite32(priv->rxq_prod & 0xffff, priv->hw_addr + priv->rxq_db_offs); return ret; } diff --git a/src/cndm/modules/cndm/cndm_tx.c b/src/cndm/modules/cndm/cndm_tx.c index f4cb8c6..eec4a97 100644 --- a/src/cndm/modules/cndm/cndm_tx.c +++ b/src/cndm/modules/cndm/cndm_tx.c @@ -170,7 +170,7 @@ int cndm_start_xmit(struct sk_buff *skb, struct net_device *ndev) } dma_wmb(); - iowrite32(priv->txq_prod & 0xffff, priv->hw_addr + 0x104); + iowrite32(priv->txq_prod & 0xffff, priv->hw_addr + priv->txq_db_offs); return NETDEV_TX_OK; diff --git a/src/cndm/rtl/cndm_micro_cmd_mbox.sv b/src/cndm/rtl/cndm_micro_cmd_mbox.sv new file mode 100644 index 0000000..3dbcfbe --- /dev/null +++ b/src/cndm/rtl/cndm_micro_cmd_mbox.sv @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2026 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Command mailbox + */ +module cndm_micro_cmd_mbox +( + input wire logic clk, + input wire logic rst, + + /* + * AXI lite interface + */ + taxi_axil_if.wr_slv s_axil_wr, + taxi_axil_if.rd_slv s_axil_rd, + + /* + * Control + */ + input wire logic start, + output wire logic busy, + + /* + * Command interface + */ + taxi_axis_if.src m_axis_cmd, + taxi_axis_if.snk s_axis_rsp +); + +localparam ADDR_W = 7; + +// extract parameters +localparam DATA_W = s_axil_wr.DATA_W; +localparam STRB_W = s_axil_wr.STRB_W; + +localparam VALID_ADDR_W = ADDR_W - $clog2(STRB_W); +localparam BYTE_LANES = STRB_W; +localparam BYTE_W = DATA_W/BYTE_LANES; + +// check configuration +if (BYTE_W * STRB_W != DATA_W) + $fatal(0, "Error: AXI data width not evenly divisible (instance %m)"); + +if (2**$clog2(BYTE_LANES) != BYTE_LANES) + $fatal(0, "Error: AXI word width must be even power of two (instance %m)"); + +if (s_axil_rd.DATA_W != DATA_W) + $fatal(0, "Error: AXI interface configuration mismatch (instance %m)"); + +if (s_axil_wr.ADDR_W < ADDR_W || s_axil_wr.ADDR_W < ADDR_W) + $fatal(0, "Error: AXI address width is insufficient (instance %m)"); + +logic read_eligible; +logic write_eligible; + +logic axil_mem_wr_en; +logic axil_mem_rd_en; +logic [4:0] axil_mem_addr; + +logic cmd_mem_wr_en; +logic cmd_mem_rd_en; +logic [4:0] cmd_mem_addr; + +logic last_read_reg = 1'b0, last_read_next; + +logic [3:0] rd_ptr_reg = '0, rd_ptr_next; +logic [3:0] wr_ptr_reg = '0, wr_ptr_next; +logic busy_reg = 1'b0, busy_next; + +logic s_axil_awready_reg = 1'b0, s_axil_awready_next; +logic s_axil_wready_reg = 1'b0, s_axil_wready_next; +logic s_axil_bvalid_reg = 1'b0, s_axil_bvalid_next; +logic s_axil_arready_reg = 1'b0, s_axil_arready_next; +// logic [DATA_W-1:0] s_axil_rdata_reg = '0, s_axil_rdata_next; +logic s_axil_rvalid_reg = 1'b0, s_axil_rvalid_next; + +// logic [31:0] m_axis_cmd_tdata_reg = '0; +logic m_axis_cmd_tvalid_reg = 1'b0, m_axis_cmd_tvalid_next; +logic m_axis_cmd_tlast_reg = 1'b0, m_axis_cmd_tlast_next; + +logic s_axis_rsp_tready_reg = 1'b0, s_axis_rsp_tready_next; + +wire [VALID_ADDR_W-1:0] s_axil_awaddr_valid = VALID_ADDR_W'(s_axil_wr.awaddr >> (ADDR_W - VALID_ADDR_W)); +wire [VALID_ADDR_W-1:0] s_axil_araddr_valid = VALID_ADDR_W'(s_axil_rd.araddr >> (ADDR_W - VALID_ADDR_W)); + +assign s_axil_wr.awready = s_axil_awready_reg; +assign s_axil_wr.wready = s_axil_wready_reg; +assign s_axil_wr.bresp = 2'b00; +assign s_axil_wr.buser = '0; +assign s_axil_wr.bvalid = s_axil_bvalid_reg; + +assign s_axil_rd.arready = s_axil_arready_reg; +// assign s_axil_rd.rdata = s_axil_rdata_reg; +assign s_axil_rd.rresp = 2'b00; +assign s_axil_rd.ruser = '0; +assign s_axil_rd.rvalid = s_axil_rvalid_reg; + +// assign m_axis_cmd.tdata = m_axis_cmd_tdata_reg; +assign m_axis_cmd.tkeep = '1; +assign m_axis_cmd.tstrb = m_axis_cmd.tkeep; +assign m_axis_cmd.tvalid = m_axis_cmd_tvalid_reg; +assign m_axis_cmd.tlast = m_axis_cmd_tlast_reg; +assign m_axis_cmd.tid = '0; +assign m_axis_cmd.tdest = '0; +assign m_axis_cmd.tuser = '0; + +assign s_axis_rsp.tready = s_axis_rsp_tready_reg; + +assign busy = busy_reg; + +taxi_ram_2rw_1c #( + .ADDR_W(5), + .DATA_W(32), + .STRB_EN(1'b1), + .STRB_W(4) +) +ram_inst ( + .clk(clk), + + .a_en(axil_mem_wr_en || axil_mem_rd_en), + .a_addr(axil_mem_addr), + .a_wr_en(axil_mem_wr_en), + .a_wr_data(s_axil_wr.wdata), + .a_wr_strb(s_axil_wr.wstrb), + .a_rd_data(s_axil_rd.rdata), + + .b_en(cmd_mem_wr_en || cmd_mem_rd_en), + .b_addr(cmd_mem_addr), + .b_wr_en(cmd_mem_wr_en), + .b_wr_data(s_axis_rsp.tdata), + .b_wr_strb('1), + .b_rd_data(m_axis_cmd.tdata) +); + +// Register interface +always_comb begin + axil_mem_wr_en = 1'b0; + axil_mem_rd_en = 1'b0; + axil_mem_addr = s_axil_araddr_valid; + + last_read_next = last_read_reg; + + s_axil_awready_next = 1'b0; + s_axil_wready_next = 1'b0; + s_axil_bvalid_next = s_axil_bvalid_reg && !s_axil_wr.bready; + + s_axil_arready_next = 1'b0; + s_axil_rvalid_next = s_axil_rvalid_reg && !s_axil_rd.rready; + + write_eligible = s_axil_wr.awvalid && s_axil_wr.wvalid && (!s_axil_wr.bvalid || s_axil_wr.bready) && (!s_axil_wr.awready && !s_axil_wr.wready); + read_eligible = s_axil_rd.arvalid && (!s_axil_rd.rvalid || s_axil_rd.rready) && (!s_axil_rd.arready); + + if (write_eligible && (!read_eligible || last_read_reg)) begin + last_read_next = 1'b0; + + s_axil_awready_next = 1'b1; + s_axil_wready_next = 1'b1; + s_axil_bvalid_next = 1'b1; + + axil_mem_wr_en = 1'b1; + axil_mem_addr = s_axil_awaddr_valid; + end else if (read_eligible) begin + last_read_next = 1'b1; + + s_axil_arready_next = 1'b1; + s_axil_rvalid_next = 1'b1; + + axil_mem_rd_en = 1'b1; + axil_mem_addr = s_axil_araddr_valid; + end +end + +always_ff @(posedge clk) begin + last_read_reg <= last_read_next; + + s_axil_awready_reg <= s_axil_awready_next; + s_axil_wready_reg <= s_axil_wready_next; + s_axil_bvalid_reg <= s_axil_bvalid_next; + + s_axil_arready_reg <= s_axil_arready_next; + s_axil_rvalid_reg <= s_axil_rvalid_next; + + if (rst) begin + last_read_reg <= 1'b0; + + s_axil_awready_reg <= 1'b0; + s_axil_wready_reg <= 1'b0; + s_axil_bvalid_reg <= 1'b0; + + s_axil_arready_reg <= 1'b0; + s_axil_rvalid_reg <= 1'b0; + end +end + +// Command interface +always_comb begin + cmd_mem_rd_en = 1'b0; + cmd_mem_wr_en = 1'b0; + cmd_mem_addr = {1'b0, rd_ptr_reg}; + + rd_ptr_next = rd_ptr_reg; + wr_ptr_next = wr_ptr_reg; + busy_next = busy_reg; + + m_axis_cmd_tvalid_next = m_axis_cmd_tvalid_reg && !m_axis_cmd.tready; + m_axis_cmd_tlast_next = m_axis_cmd_tlast_reg; + + s_axis_rsp_tready_next = 1'b0; + + if ((!m_axis_cmd_tvalid_reg || m_axis_cmd.tready) && (rd_ptr_reg != 0 || start)) begin + cmd_mem_rd_en = 1'b1; + cmd_mem_addr = {1'b0, rd_ptr_reg}; + m_axis_cmd_tvalid_next = 1'b1; + m_axis_cmd_tlast_next = &rd_ptr_reg; + rd_ptr_next = rd_ptr_reg + 1; + busy_next = 1'b1; + end else if (s_axis_rsp.tvalid && !s_axis_rsp_tready_reg) begin + cmd_mem_wr_en = 1'b1; + cmd_mem_addr = {1'b1, wr_ptr_reg}; + s_axis_rsp_tready_next = 1'b1; + if (s_axis_rsp.tlast) begin + wr_ptr_next = '0; + busy_next = 1'b0; + end else begin + wr_ptr_next = wr_ptr_reg + 1; + end + end +end + +always_ff @(posedge clk) begin + rd_ptr_reg <= rd_ptr_next; + wr_ptr_reg <= wr_ptr_next; + busy_reg <= busy_next; + + m_axis_cmd_tvalid_reg <= m_axis_cmd_tvalid_next; + m_axis_cmd_tlast_reg <= m_axis_cmd_tlast_next; + + s_axis_rsp_tready_reg <= s_axis_rsp_tready_next; + + if (rst) begin + rd_ptr_reg <= '0; + wr_ptr_reg <= '0; + busy_reg <= 1'b0; + + m_axis_cmd_tvalid_reg <= 1'b0; + + s_axis_rsp_tready_reg <= 1'b0; + end +end + +endmodule + +`resetall diff --git a/src/cndm/rtl/cndm_micro_core.f b/src/cndm/rtl/cndm_micro_core.f index 33b90a4..422d878 100644 --- a/src/cndm/rtl/cndm_micro_core.f +++ b/src/cndm/rtl/cndm_micro_core.f @@ -1,13 +1,18 @@ cndm_micro_core.sv +cndm_micro_cmd_mbox.sv +cndm_micro_dp_mgr.sv cndm_micro_port.sv cndm_micro_rx.sv cndm_micro_tx.sv cndm_micro_desc_rd.sv cndm_micro_cpl_wr.sv +../lib/taxi/src/prim/rtl/taxi_ram_2rw_1c.sv ../lib/taxi/src/dma/rtl/taxi_dma_client_axis_source.sv ../lib/taxi/src/dma/rtl/taxi_dma_client_axis_sink.sv ../lib/taxi/src/dma/rtl/taxi_dma_if_mux.f ../lib/taxi/src/dma/rtl/taxi_dma_psdpram.sv +../lib/taxi/src/apb/rtl/taxi_apb_if.sv +../lib/taxi/src/apb/rtl/taxi_apb_interconnect.sv ../lib/taxi/src/axi/rtl/taxi_axil_interconnect_1s.f ../lib/taxi/src/axis/rtl/taxi_axis_async_fifo.f ../lib/taxi/src/axis/rtl/taxi_axis_arb_mux.f diff --git a/src/cndm/rtl/cndm_micro_core.sv b/src/cndm/rtl/cndm_micro_core.sv index d2f5e03..1e7d776 100644 --- a/src/cndm/rtl/cndm_micro_core.sv +++ b/src/cndm/rtl/cndm_micro_core.sv @@ -49,8 +49,8 @@ module cndm_micro_core #( /* * Control register interface */ - taxi_axil_if.wr_slv s_axil_wr, - taxi_axil_if.rd_slv s_axil_rd, + taxi_axil_if.wr_slv s_axil_ctrl_wr, + taxi_axil_if.rd_slv s_axil_ctrl_rd, /* * DMA @@ -97,8 +97,8 @@ module cndm_micro_core #( localparam CL_PORTS = $clog2(PORTS); -localparam AXIL_ADDR_W = s_axil_wr.ADDR_W; -localparam AXIL_DATA_W = s_axil_wr.DATA_W; +localparam AXIL_ADDR_W = s_axil_ctrl_wr.ADDR_W; +localparam AXIL_DATA_W = s_axil_ctrl_wr.DATA_W; localparam RAM_SEGS = dma_ram_wr.SEGS; localparam RAM_SEG_ADDR_W = dma_ram_wr.SEG_ADDR_W; @@ -106,32 +106,33 @@ localparam RAM_SEG_DATA_W = dma_ram_wr.SEG_DATA_W; localparam RAM_SEG_BE_W = dma_ram_wr.SEG_BE_W; localparam RAM_SEL_W = dma_ram_wr.SEL_W; -localparam PORT_OFFSET = PTP_TS_EN ? 2 : 1; +localparam PORT_OFFSET = PTP_TS_EN ? 3 : 2; +localparam PORT_BASE_ADDR = PTP_TS_EN ? 32'h00030000 : 32'h00020000; taxi_axil_if #( - .DATA_W(s_axil_wr.DATA_W), + .DATA_W(s_axil_ctrl_wr.DATA_W), .ADDR_W(16), - .STRB_W(s_axil_wr.STRB_W), - .AWUSER_EN(s_axil_wr.AWUSER_EN), - .AWUSER_W(s_axil_wr.AWUSER_W), - .WUSER_EN(s_axil_wr.WUSER_EN), - .WUSER_W(s_axil_wr.WUSER_W), - .BUSER_EN(s_axil_wr.BUSER_EN), - .BUSER_W(s_axil_wr.BUSER_W), - .ARUSER_EN(s_axil_wr.ARUSER_EN), - .ARUSER_W(s_axil_wr.ARUSER_W), - .RUSER_EN(s_axil_wr.RUSER_EN), - .RUSER_W(s_axil_wr.RUSER_W) + .STRB_W(s_axil_ctrl_wr.STRB_W), + .AWUSER_EN(s_axil_ctrl_wr.AWUSER_EN), + .AWUSER_W(s_axil_ctrl_wr.AWUSER_W), + .WUSER_EN(s_axil_ctrl_wr.WUSER_EN), + .WUSER_W(s_axil_ctrl_wr.WUSER_W), + .BUSER_EN(s_axil_ctrl_wr.BUSER_EN), + .BUSER_W(s_axil_ctrl_wr.BUSER_W), + .ARUSER_EN(s_axil_ctrl_wr.ARUSER_EN), + .ARUSER_W(s_axil_ctrl_wr.ARUSER_W), + .RUSER_EN(s_axil_ctrl_wr.RUSER_EN), + .RUSER_W(s_axil_ctrl_wr.RUSER_W) ) -s_axil_ctrl[PORTS+PORT_OFFSET](); +axil_ctrl[PORTS+PORT_OFFSET](); taxi_axil_interconnect_1s #( - .M_COUNT($size(s_axil_ctrl)), - .ADDR_W(s_axil_wr.ADDR_W), + .M_COUNT($size(axil_ctrl)), + .ADDR_W(s_axil_ctrl_wr.ADDR_W), .M_REGIONS(1), .M_BASE_ADDR('0), - .M_ADDR_W({$size(s_axil_ctrl){{1{32'd16}}}}), - .M_SECURE({$size(s_axil_ctrl){1'b0}}) + .M_ADDR_W({$size(axil_ctrl){{1{32'd16}}}}), + .M_SECURE({$size(axil_ctrl){1'b0}}) ) port_intercon_inst ( .clk(clk), @@ -140,14 +141,14 @@ port_intercon_inst ( /* * AXI4-lite slave interface */ - .s_axil_wr(s_axil_wr), - .s_axil_rd(s_axil_rd), + .s_axil_wr(s_axil_ctrl_wr), + .s_axil_rd(s_axil_ctrl_rd), /* * AXI4-lite master interfaces */ - .m_axil_wr(s_axil_ctrl), - .m_axil_rd(s_axil_ctrl) + .m_axil_wr(axil_ctrl), + .m_axil_rd(axil_ctrl) ); logic s_axil_awready_reg = 1'b0; @@ -158,53 +159,64 @@ logic s_axil_arready_reg = 1'b0; logic [AXIL_DATA_W-1:0] s_axil_rdata_reg = '0; logic s_axil_rvalid_reg = 1'b0; -assign s_axil_ctrl[0].awready = s_axil_awready_reg; -assign s_axil_ctrl[0].wready = s_axil_wready_reg; -assign s_axil_ctrl[0].bresp = '0; -assign s_axil_ctrl[0].buser = '0; -assign s_axil_ctrl[0].bvalid = s_axil_bvalid_reg; +assign axil_ctrl[0].awready = s_axil_awready_reg; +assign axil_ctrl[0].wready = s_axil_wready_reg; +assign axil_ctrl[0].bresp = '0; +assign axil_ctrl[0].buser = '0; +assign axil_ctrl[0].bvalid = s_axil_bvalid_reg; -assign s_axil_ctrl[0].arready = s_axil_arready_reg; -assign s_axil_ctrl[0].rdata = s_axil_rdata_reg; -assign s_axil_ctrl[0].rresp = '0; -assign s_axil_ctrl[0].ruser = '0; -assign s_axil_ctrl[0].rvalid = s_axil_rvalid_reg; +assign axil_ctrl[0].arready = s_axil_arready_reg; +assign axil_ctrl[0].rdata = s_axil_rdata_reg; +assign axil_ctrl[0].rresp = '0; +assign axil_ctrl[0].ruser = '0; +assign axil_ctrl[0].rvalid = s_axil_rvalid_reg; + +logic cmd_mbox_start_reg = 1'b0; +wire cmd_mbox_busy; always_ff @(posedge clk) begin s_axil_awready_reg <= 1'b0; s_axil_wready_reg <= 1'b0; - s_axil_bvalid_reg <= s_axil_bvalid_reg && !s_axil_ctrl[0].bready; + s_axil_bvalid_reg <= s_axil_bvalid_reg && !axil_ctrl[0].bready; s_axil_arready_reg <= 1'b0; - s_axil_rvalid_reg <= s_axil_rvalid_reg && !s_axil_ctrl[0].rready; + s_axil_rvalid_reg <= s_axil_rvalid_reg && !axil_ctrl[0].rready; - if (s_axil_ctrl[0].awvalid && s_axil_ctrl[0].wvalid && !s_axil_bvalid_reg) begin + cmd_mbox_start_reg <= 1'b0; + + if (axil_ctrl[0].awvalid && axil_ctrl[0].wvalid && !s_axil_bvalid_reg) begin s_axil_awready_reg <= 1'b1; s_axil_wready_reg <= 1'b1; s_axil_bvalid_reg <= 1'b1; - case ({s_axil_ctrl[0].awaddr[15:2], 2'b00}) + case ({axil_ctrl[0].awaddr[15:2], 2'b00}) // 16'h0100: begin - // txq_en_reg <= s_axil_ctrl[0].wdata[0]; - // txq_size_reg <= s_axil_ctrl[0].wdata[19:16]; + // txq_en_reg <= axil_ctrl[0].wdata[0]; + // txq_size_reg <= axil_ctrl[0].wdata[19:16]; // end - // 16'h0104: txq_prod_reg <= s_axil_ctrl[0].wdata[15:0]; - // 16'h0108: txq_base_addr_reg[31:0] <= s_axil_ctrl[0].wdata; - // 16'h010c: txq_base_addr_reg[63:32] <= s_axil_ctrl[0].wdata; + // 16'h0104: txq_prod_reg <= axil_ctrl[0].wdata[15:0]; + // 16'h0108: txq_base_addr_reg[31:0] <= axil_ctrl[0].wdata; + // 16'h010c: txq_base_addr_reg[63:32] <= axil_ctrl[0].wdata; + 16'h0200: begin + cmd_mbox_start_reg <= axil_ctrl[0].wdata[0]; + end default: begin end endcase end - if (s_axil_ctrl[0].arvalid && !s_axil_rvalid_reg) begin + if (axil_ctrl[0].arvalid && !s_axil_rvalid_reg) begin s_axil_rdata_reg <= '0; s_axil_arready_reg <= 1'b1; s_axil_rvalid_reg <= 1'b1; - case ({s_axil_ctrl[0].araddr[15:2], 2'b00}) + case ({axil_ctrl[0].araddr[15:2], 2'b00}) 16'h0100: s_axil_rdata_reg <= PORTS; // port count - 16'h0104: s_axil_rdata_reg <= PTP_TS_EN ? 32'h00020000 : 32'h00010000; // port offset + 16'h0104: s_axil_rdata_reg <= PORT_BASE_ADDR; // port offset 16'h0108: s_axil_rdata_reg <= 32'h00010000; // port stride + 16'h0200: begin + s_axil_rdata_reg[0] <= cmd_mbox_busy; + end default: begin end endcase end @@ -219,6 +231,106 @@ always_ff @(posedge clk) begin end end +// command mailbox +taxi_axis_if #( + .DATA_W(32), + .KEEP_EN(1), + .LAST_EN(1), + .ID_EN(0), + .DEST_EN(0), + .USER_EN(0) +) axis_cmd(); + +taxi_axis_if #( + .DATA_W(32), + .KEEP_EN(1), + .LAST_EN(1), + .ID_EN(0), + .DEST_EN(0), + .USER_EN(0) +) axis_rsp(); + +cndm_micro_cmd_mbox +cmd_mbox_inst ( + .clk(clk), + .rst(rst), + + /* + * AXI lite interface + */ + .s_axil_wr(axil_ctrl[1]), + .s_axil_rd(axil_ctrl[1]), + + /* + * Control + */ + .start(cmd_mbox_start_reg), + .busy(cmd_mbox_busy), + + /* + * Command interface + */ + .m_axis_cmd(axis_cmd), + .s_axis_rsp(axis_rsp) +); + +// datapath manager + +taxi_apb_if #( + .DATA_W(32), + .ADDR_W(16+CL_PORTS) +) +apb_dp_ctrl(); + +cndm_micro_dp_mgr #( + .PORTS(PORTS), + .PORT_BASE_ADDR(PORT_BASE_ADDR) +) +dp_mgr_inst ( + .clk(clk), + .rst(rst), + + /* + * Command interface + */ + .s_axis_cmd(axis_cmd), + .m_axis_rsp(axis_rsp), + + /* + * APB master interface (datapath control) + */ + .m_apb_dp_ctrl(apb_dp_ctrl) +); + +taxi_apb_if #( + .DATA_W(32), + .ADDR_W(16) +) +apb_port_dp_ctrl[PORTS](); + +taxi_apb_interconnect #( + .M_CNT($size(apb_port_dp_ctrl)), + .ADDR_W(apb_dp_ctrl.ADDR_W), + .M_REGIONS(1), + .M_BASE_ADDR('0), + .M_ADDR_W({$size(apb_port_dp_ctrl){{1{32'd16}}}}), + .M_SECURE({$size(apb_port_dp_ctrl){1'b0}}) +) +port_dp_intercon_inst ( + .clk(clk), + .rst(rst), + + /* + * APB slave interface + */ + .s_apb(apb_dp_ctrl), + + /* + * APB master interfaces + */ + .m_apb(apb_port_dp_ctrl) +); + if (PTP_TS_EN) begin : ptp taxi_ptp_td_phc_axil #( @@ -232,8 +344,8 @@ if (PTP_TS_EN) begin : ptp /* * Control register interface */ - .s_axil_wr(s_axil_ctrl[1]), - .s_axil_rd(s_axil_ctrl[1]), + .s_axil_wr(axil_ctrl[2]), + .s_axil_rd(axil_ctrl[2]), /* * PTP @@ -362,8 +474,13 @@ for (genvar p = 0; p < PORTS; p = p + 1) begin : port /* * Control register interface */ - .s_axil_wr(s_axil_ctrl[PORT_OFFSET+p]), - .s_axil_rd(s_axil_ctrl[PORT_OFFSET+p]), + .s_axil_ctrl_wr(axil_ctrl[PORT_OFFSET+p]), + .s_axil_ctrl_rd(axil_ctrl[PORT_OFFSET+p]), + + /* + * Datapath control register interface + */ + .s_apb_dp_ctrl(apb_port_dp_ctrl[p]), /* * DMA diff --git a/src/cndm/rtl/cndm_micro_dp_mgr.sv b/src/cndm/rtl/cndm_micro_dp_mgr.sv new file mode 100644 index 0000000..7079d69 --- /dev/null +++ b/src/cndm/rtl/cndm_micro_dp_mgr.sv @@ -0,0 +1,546 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2026 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Datapath manager + */ +module cndm_micro_dp_mgr # +( + parameter PORTS = 2, + parameter PORT_BASE_ADDR = 0 +) +( + input wire logic clk, + input wire logic rst, + + /* + * Command interface + */ + taxi_axis_if.snk s_axis_cmd, + taxi_axis_if.src m_axis_rsp, + + /* + * APB master interface (datapath control) + */ + taxi_apb_if.mst m_apb_dp_ctrl +); + +// extract parameters +localparam DP_APB_ADDR_W = m_apb_dp_ctrl.ADDR_W; +localparam DP_APB_DATA_W = m_apb_dp_ctrl.DATA_W; +localparam DP_APB_STRB_W = m_apb_dp_ctrl.STRB_W; + +typedef enum logic [15:0] { + CMD_OP_NOP = 16'h0000, + + CMD_OP_CREATE_EQ = 16'h0200, + CMD_OP_MODIFY_EQ = 16'h0201, + CMD_OP_QUERY_EQ = 16'h0202, + CMD_OP_DESTROY_EQ = 16'h0203, + + CMD_OP_CREATE_CQ = 16'h0210, + CMD_OP_MODIFY_CQ = 16'h0211, + CMD_OP_QUERY_CQ = 16'h0212, + CMD_OP_DESTROY_CQ = 16'h0213, + + CMD_OP_CREATE_SQ = 16'h0220, + CMD_OP_MODIFY_SQ = 16'h0221, + CMD_OP_QUERY_SQ = 16'h0222, + CMD_OP_DESTROY_SQ = 16'h0223, + + CMD_OP_CREATE_RQ = 16'h0230, + CMD_OP_MODIFY_RQ = 16'h0231, + CMD_OP_QUERY_RQ = 16'h0232, + CMD_OP_DESTROY_RQ = 16'h0233, + + CMD_OP_CREATE_QP = 16'h0240, + CMD_OP_MODIFY_QP = 16'h0241, + CMD_OP_QUERY_QP = 16'h0242, + CMD_OP_DESTROY_QP = 16'h0243 +} cmd_opcode_t; + +typedef enum logic [4:0] { + STATE_IDLE, + STATE_START, + STATE_Q_RESET_1, + STATE_Q_RESET_2, + STATE_Q_SET_BASE_L, + STATE_Q_SET_BASE_H, + STATE_Q_ENABLE, + STATE_Q_DISABLE, + STATE_SEND_RSP, + STATE_PAD_RSP +} state_t; + +state_t state_reg = STATE_IDLE, state_next; + +logic s_axis_cmd_tready_reg = 1'b0, s_axis_cmd_tready_next; + +logic [31:0] m_axis_rsp_tdata_reg = '0, m_axis_rsp_tdata_next; +logic m_axis_rsp_tvalid_reg = 1'b0, m_axis_rsp_tvalid_next; +logic m_axis_rsp_tlast_reg = 1'b0, m_axis_rsp_tlast_next; + +logic [DP_APB_ADDR_W-1:0] m_apb_dp_ctrl_paddr_reg = '0, m_apb_dp_ctrl_paddr_next; +logic m_apb_dp_ctrl_psel_reg = 1'b0, m_apb_dp_ctrl_psel_next; +logic m_apb_dp_ctrl_penable_reg = 1'b0, m_apb_dp_ctrl_penable_next; +logic m_apb_dp_ctrl_pwrite_reg = 1'b0, m_apb_dp_ctrl_pwrite_next; +logic [DP_APB_DATA_W-1:0] m_apb_dp_ctrl_pwdata_reg = '0, m_apb_dp_ctrl_pwdata_next; +logic [DP_APB_STRB_W-1:0] m_apb_dp_ctrl_pstrb_reg = '0, m_apb_dp_ctrl_pstrb_next; + +// command RAM +localparam CMD_AW = 4; + +logic [31:0] cmd_ram[2**CMD_AW]; +logic [31:0] cmd_ram_wr_data; +logic [CMD_AW-1:0] cmd_ram_wr_addr; +logic cmd_ram_wr_en; +logic [CMD_AW-1:0] cmd_ram_rd_addr; +wire [31:0] cmd_ram_rd_data = cmd_ram[cmd_ram_rd_addr]; + +assign s_axis_cmd.tready = s_axis_cmd_tready_reg; + +assign m_axis_rsp.tdata = m_axis_rsp_tdata_reg; +assign m_axis_rsp.tkeep = '1; +assign m_axis_rsp.tstrb = m_axis_rsp.tkeep; +assign m_axis_rsp.tvalid = m_axis_rsp_tvalid_reg; +assign m_axis_rsp.tlast = m_axis_rsp_tlast_reg; +assign m_axis_rsp.tid = '0; +assign m_axis_rsp.tdest = '0; +assign m_axis_rsp.tuser = '0; + +assign m_apb_dp_ctrl.paddr = m_apb_dp_ctrl_paddr_reg; +assign m_apb_dp_ctrl.pprot = 3'b010; +assign m_apb_dp_ctrl.psel = m_apb_dp_ctrl_psel_reg; +assign m_apb_dp_ctrl.penable = m_apb_dp_ctrl_penable_reg; +assign m_apb_dp_ctrl.pwrite = m_apb_dp_ctrl_pwrite_reg; +assign m_apb_dp_ctrl.pwdata = m_apb_dp_ctrl_pwdata_reg; +assign m_apb_dp_ctrl.pstrb = m_apb_dp_ctrl_pstrb_reg; +assign m_apb_dp_ctrl.pauser = '0; +assign m_apb_dp_ctrl.pwuser = '0; + +logic cmd_frame_reg = 1'b0, cmd_frame_next; +logic [3:0] cmd_ptr_reg = '0, cmd_ptr_next; +logic rsp_frame_reg = 1'b0, rsp_frame_next; +logic [3:0] rsp_ptr_reg = '0, rsp_ptr_next; + +logic drop_cmd_reg = 1'b0, drop_cmd_next; + +logic [15:0] opcode_reg = '0, opcode_next; +logic [31:0] flags_reg = '0, flags_next; +logic [15:0] port_reg = '0, port_next; +logic [23:0] qn_reg = '0, qn_next; + +logic [DP_APB_ADDR_W-1:0] block_base_addr_reg = '0, block_base_addr_next; + +always_comb begin + state_next = STATE_IDLE; + + s_axis_cmd_tready_next = 1'b0; + + m_axis_rsp_tdata_next = m_axis_rsp_tdata_reg; + m_axis_rsp_tvalid_next = m_axis_rsp_tvalid_reg && !m_axis_rsp.tready; + m_axis_rsp_tlast_next = m_axis_rsp_tlast_reg; + + m_apb_dp_ctrl_paddr_next = m_apb_dp_ctrl_paddr_reg; + m_apb_dp_ctrl_psel_next = m_apb_dp_ctrl_psel_reg && !m_apb_dp_ctrl.pready; + m_apb_dp_ctrl_penable_next = m_apb_dp_ctrl_psel_reg && !m_apb_dp_ctrl.pready; + m_apb_dp_ctrl_pwrite_next = m_apb_dp_ctrl_pwrite_reg; + m_apb_dp_ctrl_pwdata_next = m_apb_dp_ctrl_pwdata_reg; + m_apb_dp_ctrl_pstrb_next = m_apb_dp_ctrl_pstrb_reg; + + cmd_ram_wr_data = s_axis_cmd.tdata; + cmd_ram_wr_addr = cmd_ptr_reg; + cmd_ram_wr_en = 1'b0; + cmd_ram_rd_addr = '0; + + cmd_frame_next = cmd_frame_reg; + cmd_ptr_next = cmd_ptr_reg; + rsp_frame_next = rsp_frame_reg; + rsp_ptr_next = rsp_ptr_reg; + + drop_cmd_next = drop_cmd_reg; + + opcode_next = opcode_reg; + flags_next = flags_reg; + port_next = port_reg; + qn_next = qn_reg; + + block_base_addr_next = block_base_addr_reg; + + if (s_axis_cmd.tready && s_axis_cmd.tvalid) begin + if (s_axis_cmd.tlast) begin + cmd_frame_next = 1'b0; + cmd_ptr_next = '0; + end else begin + cmd_ptr_next = cmd_ptr_reg + 1; + cmd_frame_next = 1'b1; + end + end + + case (state_reg) + STATE_IDLE: begin + s_axis_cmd_tready_next = !m_axis_rsp_tvalid_reg && !rsp_frame_reg; + + cmd_ram_wr_data = s_axis_cmd.tdata; + cmd_ram_wr_addr = cmd_ptr_reg; + cmd_ram_wr_en = 1'b1; + + // save some important fields + case (cmd_ptr_reg) + 4'd0: opcode_next = s_axis_cmd.tdata[31:16]; + 4'd1: flags_next = s_axis_cmd.tdata; + 4'd2: port_next = s_axis_cmd.tdata[15:0]; + 4'd3: qn_next = s_axis_cmd.tdata[23:0]; + default: begin end + endcase + + if (s_axis_cmd.tready && s_axis_cmd.tvalid && !drop_cmd_reg) begin + if (s_axis_cmd.tlast || &cmd_ptr_reg) begin + drop_cmd_next = !s_axis_cmd.tlast; + state_next = STATE_START; + end else begin + state_next = STATE_IDLE; + end + end else begin + state_next = STATE_IDLE; + end + end + STATE_START: begin + // determine block base address + case (opcode_reg) + CMD_OP_CREATE_EQ, + CMD_OP_MODIFY_EQ, + CMD_OP_QUERY_EQ, + CMD_OP_DESTROY_EQ: + begin + // EQ + block_base_addr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 16'h0000); + end + CMD_OP_CREATE_CQ, + CMD_OP_MODIFY_CQ, + CMD_OP_QUERY_CQ, + CMD_OP_DESTROY_CQ: + begin + // CQ + if (qn_reg[0]) begin + block_base_addr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 16'h0300); + end else begin + block_base_addr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 16'h0400); + end + end + CMD_OP_CREATE_SQ, + CMD_OP_MODIFY_SQ, + CMD_OP_QUERY_SQ, + CMD_OP_DESTROY_SQ: + begin + // SQ + block_base_addr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 16'h0100); + end + CMD_OP_CREATE_RQ, + CMD_OP_MODIFY_RQ, + CMD_OP_QUERY_RQ, + CMD_OP_DESTROY_RQ: + begin + // RQ + block_base_addr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 16'h0200); + end + default: begin end + endcase + + case (opcode_reg) + 16'h0000: begin + // NOP + m_axis_rsp_tdata_next = '0; // TODO + m_axis_rsp_tvalid_next = 1'b1; + m_axis_rsp_tlast_next = 1'b0; + + state_next = STATE_SEND_RSP; + end + CMD_OP_CREATE_EQ, + CMD_OP_CREATE_CQ, + CMD_OP_CREATE_SQ, + CMD_OP_CREATE_RQ: + begin + // create queue operation + state_next = STATE_Q_RESET_1; + end + CMD_OP_MODIFY_EQ, + CMD_OP_MODIFY_CQ, + CMD_OP_MODIFY_SQ, + CMD_OP_MODIFY_RQ: + begin + // modify queue operation + m_axis_rsp_tdata_next = '0; // TODO + m_axis_rsp_tvalid_next = 1'b1; + m_axis_rsp_tlast_next = 1'b0; + + // determine base address + + state_next = STATE_PAD_RSP; + end + CMD_OP_QUERY_EQ, + CMD_OP_QUERY_CQ, + CMD_OP_QUERY_SQ, + CMD_OP_QUERY_RQ: + begin + // query queue operation + m_axis_rsp_tdata_next = '0; // TODO + m_axis_rsp_tvalid_next = 1'b1; + m_axis_rsp_tlast_next = 1'b0; + + // determine base address + + state_next = STATE_PAD_RSP; + end + CMD_OP_DESTROY_EQ, + CMD_OP_DESTROY_CQ, + CMD_OP_DESTROY_SQ, + CMD_OP_DESTROY_RQ: + begin + // destroy queue operation + state_next = STATE_Q_DISABLE; + end + default: begin + // unknown opcode + m_axis_rsp_tdata_next = '0; // TODO error code + m_axis_rsp_tvalid_next = 1'b1; + m_axis_rsp_tlast_next = 1'b0; + + state_next = STATE_PAD_RSP; + end + endcase + end + STATE_Q_RESET_1: begin + // reset queue 1 + if (!m_apb_dp_ctrl_psel_reg) begin + m_apb_dp_ctrl_paddr_next = block_base_addr_reg + 16'h0000; + m_apb_dp_ctrl_psel_next = 1'b1; + m_apb_dp_ctrl_pwrite_next = 1'b1; + m_apb_dp_ctrl_pwdata_next = 32'h00000000; + m_apb_dp_ctrl_pstrb_next = '1; + + state_next = STATE_Q_RESET_2; + end else begin + state_next = STATE_Q_RESET_1; + end + end + STATE_Q_RESET_2: begin + // reset queue 2 + + cmd_ram_wr_data = 32'(block_base_addr_reg + 16'h0004) + PORT_BASE_ADDR; + cmd_ram_wr_addr = 7; + cmd_ram_wr_en = 1'b1; + + if (!m_apb_dp_ctrl_psel_reg) begin + m_apb_dp_ctrl_paddr_next = block_base_addr_reg + 16'h0004; + m_apb_dp_ctrl_psel_next = 1'b1; + m_apb_dp_ctrl_pwrite_next = 1'b1; + m_apb_dp_ctrl_pwdata_next = 32'h00000000; + m_apb_dp_ctrl_pstrb_next = '1; + + state_next = STATE_Q_SET_BASE_L; + end else begin + state_next = STATE_Q_RESET_2; + end + end + STATE_Q_SET_BASE_L: begin + // set queue base addr (LSB) + cmd_ram_rd_addr = 8; + if (!m_apb_dp_ctrl_psel_reg) begin + m_apb_dp_ctrl_paddr_next = block_base_addr_reg + 16'h0008; + m_apb_dp_ctrl_psel_next = 1'b1; + m_apb_dp_ctrl_pwrite_next = 1'b1; + m_apb_dp_ctrl_pwdata_next = cmd_ram_rd_data; + m_apb_dp_ctrl_pstrb_next = '1; + + state_next = STATE_Q_SET_BASE_H; + end else begin + state_next = STATE_Q_SET_BASE_L; + end + end + STATE_Q_SET_BASE_H: begin + // set queue base addr (MSB) + cmd_ram_rd_addr = 9; + if (!m_apb_dp_ctrl_psel_reg) begin + m_apb_dp_ctrl_paddr_next = block_base_addr_reg + 16'h000C; + m_apb_dp_ctrl_psel_next = 1'b1; + m_apb_dp_ctrl_pwrite_next = 1'b1; + m_apb_dp_ctrl_pwdata_next = cmd_ram_rd_data; + m_apb_dp_ctrl_pstrb_next = '1; + + state_next = STATE_Q_ENABLE; + end else begin + state_next = STATE_Q_SET_BASE_H; + end + end + STATE_Q_ENABLE: begin + // enable queue + cmd_ram_rd_addr = 6; + if (!m_apb_dp_ctrl_psel_reg) begin + m_apb_dp_ctrl_paddr_next = block_base_addr_reg + 16'h0000; + m_apb_dp_ctrl_psel_next = 1'b1; + m_apb_dp_ctrl_pwrite_next = 1'b1; + m_apb_dp_ctrl_pwdata_next = '0; + m_apb_dp_ctrl_pwdata_next[19:16] = cmd_ram_rd_data[3:0]; + m_apb_dp_ctrl_pwdata_next[0] = 1'b1; + m_apb_dp_ctrl_pstrb_next = '1; + + m_axis_rsp_tdata_next = '0; // TODO + m_axis_rsp_tvalid_next = 1'b1; + m_axis_rsp_tlast_next = 1'b0; + + state_next = STATE_SEND_RSP; + end else begin + state_next = STATE_Q_ENABLE; + end + end + STATE_Q_DISABLE: begin + // disable queue + if (!m_apb_dp_ctrl_psel_reg) begin + m_apb_dp_ctrl_paddr_next = block_base_addr_reg + 16'h0000; + m_apb_dp_ctrl_psel_next = 1'b1; + m_apb_dp_ctrl_pwrite_next = 1'b1; + m_apb_dp_ctrl_pwdata_next = 32'h00000000; + m_apb_dp_ctrl_pstrb_next = '1; + + m_axis_rsp_tdata_next = '0; // TODO + m_axis_rsp_tvalid_next = 1'b1; + m_axis_rsp_tlast_next = 1'b0; + + state_next = STATE_SEND_RSP; + end else begin + state_next = STATE_Q_DISABLE; + end + end + STATE_SEND_RSP: begin + // send response in the form of an edited command + cmd_ram_rd_addr = rsp_ptr_reg; + if (m_axis_rsp.tready || !m_axis_rsp.tvalid) begin + m_axis_rsp_tdata_next = cmd_ram_rd_data; + m_axis_rsp_tvalid_next = 1'b1; + m_axis_rsp_tlast_next = &rsp_ptr_reg; + + if (&rsp_ptr_reg) begin + state_next = STATE_IDLE; + end else begin + state_next = STATE_SEND_RSP; + end + end else begin + state_next = STATE_SEND_RSP; + end + end + STATE_PAD_RSP: begin + // zero pad response + if (m_axis_rsp.tready || !m_axis_rsp.tvalid) begin + m_axis_rsp_tdata_next = '0; + m_axis_rsp_tvalid_next = 1'b1; + m_axis_rsp_tlast_next = &rsp_ptr_reg; + + if (&rsp_ptr_reg) begin + state_next = STATE_IDLE; + end else begin + state_next = STATE_PAD_RSP; + end + end else begin + state_next = STATE_PAD_RSP; + end + end + default: begin + // unknown state; return to idle + state_next = STATE_IDLE; + end + endcase + + if (drop_cmd_reg) begin + s_axis_cmd_tready_next = 1'b1; + + if (s_axis_cmd.tready && s_axis_cmd.tvalid) begin + drop_cmd_next = !s_axis_cmd.tlast; + end + end + + if (m_axis_rsp_tvalid_next && (!m_axis_rsp_tvalid_reg || m_axis_rsp.tready)) begin + if (m_axis_rsp_tlast_next) begin + rsp_ptr_next = '0; + end else begin + rsp_ptr_next = rsp_ptr_reg + 1; + rsp_frame_next = 1'b1; + end + end + + if (m_axis_rsp.tready && m_axis_rsp.tvalid) begin + if (m_axis_rsp.tlast) begin + rsp_frame_next = 1'b0; + rsp_ptr_next = '0; + end + end +end + +always_ff @(posedge clk) begin + if (cmd_ram_wr_en) begin + cmd_ram[cmd_ram_wr_addr] = cmd_ram_wr_data; + end +end + +always_ff @(posedge clk) begin + state_reg <= state_next; + + s_axis_cmd_tready_reg <= s_axis_cmd_tready_next; + + m_axis_rsp_tdata_reg <= m_axis_rsp_tdata_next; + m_axis_rsp_tvalid_reg <= m_axis_rsp_tvalid_next; + m_axis_rsp_tlast_reg <= m_axis_rsp_tlast_next; + + m_apb_dp_ctrl_paddr_reg <= m_apb_dp_ctrl_paddr_next; + m_apb_dp_ctrl_psel_reg <= m_apb_dp_ctrl_psel_next; + m_apb_dp_ctrl_penable_reg <= m_apb_dp_ctrl_penable_next; + m_apb_dp_ctrl_pwrite_reg <= m_apb_dp_ctrl_pwrite_next; + m_apb_dp_ctrl_pwdata_reg <= m_apb_dp_ctrl_pwdata_next; + m_apb_dp_ctrl_pstrb_reg <= m_apb_dp_ctrl_pstrb_next; + + cmd_frame_reg <= cmd_frame_next; + cmd_ptr_reg <= cmd_ptr_next; + rsp_frame_reg <= rsp_frame_next; + rsp_ptr_reg <= rsp_ptr_next; + + drop_cmd_reg <= drop_cmd_next; + + opcode_reg <= opcode_next; + flags_reg <= flags_next; + port_reg <= port_next; + qn_reg <= qn_next; + + block_base_addr_reg <= block_base_addr_next; + + if (rst) begin + state_reg <= STATE_IDLE; + + s_axis_cmd_tready_reg <= 1'b0; + m_axis_rsp_tvalid_reg <= 1'b0; + + m_apb_dp_ctrl_psel_reg <= 1'b0; + m_apb_dp_ctrl_penable_reg <= 1'b0; + + cmd_frame_reg <= 1'b0; + cmd_ptr_reg <= '0; + rsp_frame_reg <= 1'b0; + rsp_ptr_reg <= '0; + + drop_cmd_reg <= 1'b0; + end +end + +endmodule + +`resetall diff --git a/src/cndm/rtl/cndm_micro_pcie_us.sv b/src/cndm/rtl/cndm_micro_pcie_us.sv index 0a8b746..07eeadc 100644 --- a/src/cndm/rtl/cndm_micro_pcie_us.sv +++ b/src/cndm/rtl/cndm_micro_pcie_us.sv @@ -523,8 +523,8 @@ core_inst ( /* * Control register interface */ - .s_axil_wr(axil_ctrl_bar), - .s_axil_rd(axil_ctrl_bar), + .s_axil_ctrl_wr(axil_ctrl_bar), + .s_axil_ctrl_rd(axil_ctrl_bar), /* * DMA diff --git a/src/cndm/rtl/cndm_micro_port.sv b/src/cndm/rtl/cndm_micro_port.sv index 22b322b..2aa1785 100644 --- a/src/cndm/rtl/cndm_micro_port.sv +++ b/src/cndm/rtl/cndm_micro_port.sv @@ -26,8 +26,13 @@ module cndm_micro_port #( /* * Control register interface */ - taxi_axil_if.wr_slv s_axil_wr, - taxi_axil_if.rd_slv s_axil_rd, + taxi_axil_if.wr_slv s_axil_ctrl_wr, + taxi_axil_if.rd_slv s_axil_ctrl_rd, + + /* + * Datapath control register interface + */ + taxi_apb_if.slv s_apb_dp_ctrl, /* * DMA @@ -61,8 +66,8 @@ module cndm_micro_port #( taxi_axis_if.snk mac_axis_rx ); -localparam AXIL_ADDR_W = s_axil_wr.ADDR_W; -localparam AXIL_DATA_W = s_axil_wr.DATA_W; +localparam AXIL_ADDR_W = s_axil_ctrl_wr.ADDR_W; +localparam AXIL_DATA_W = s_axil_ctrl_wr.DATA_W; localparam RAM_SEGS = dma_ram_wr.SEGS; localparam RAM_SEG_ADDR_W = dma_ram_wr.SEG_ADDR_W; @@ -90,128 +95,222 @@ logic [3:0] rxcq_size_reg = '0; logic [63:0] rxcq_base_addr_reg = '0; wire [15:0] rxcq_prod; -logic s_axil_awready_reg = 1'b0; -logic s_axil_wready_reg = 1'b0; -logic s_axil_bvalid_reg = 1'b0; +logic s_axil_ctrl_awready_reg = 1'b0; +logic s_axil_ctrl_wready_reg = 1'b0; +logic s_axil_ctrl_bvalid_reg = 1'b0; -logic s_axil_arready_reg = 1'b0; -logic [AXIL_DATA_W-1:0] s_axil_rdata_reg = '0; -logic s_axil_rvalid_reg = 1'b0; +logic s_axil_ctrl_arready_reg = 1'b0; +logic [AXIL_DATA_W-1:0] s_axil_ctrl_rdata_reg = '0; +logic s_axil_ctrl_rvalid_reg = 1'b0; -assign s_axil_wr.awready = s_axil_awready_reg; -assign s_axil_wr.wready = s_axil_wready_reg; -assign s_axil_wr.bresp = '0; -assign s_axil_wr.buser = '0; -assign s_axil_wr.bvalid = s_axil_bvalid_reg; +assign s_axil_ctrl_wr.awready = s_axil_ctrl_awready_reg; +assign s_axil_ctrl_wr.wready = s_axil_ctrl_wready_reg; +assign s_axil_ctrl_wr.bresp = '0; +assign s_axil_ctrl_wr.buser = '0; +assign s_axil_ctrl_wr.bvalid = s_axil_ctrl_bvalid_reg; -assign s_axil_rd.arready = s_axil_arready_reg; -assign s_axil_rd.rdata = s_axil_rdata_reg; -assign s_axil_rd.rresp = '0; -assign s_axil_rd.ruser = '0; -assign s_axil_rd.rvalid = s_axil_rvalid_reg; +assign s_axil_ctrl_rd.arready = s_axil_ctrl_arready_reg; +assign s_axil_ctrl_rd.rdata = s_axil_ctrl_rdata_reg; +assign s_axil_ctrl_rd.rresp = '0; +assign s_axil_ctrl_rd.ruser = '0; +assign s_axil_ctrl_rd.rvalid = s_axil_ctrl_rvalid_reg; + +logic s_apb_dp_ctrl_pready_reg = 1'b0; +logic [AXIL_DATA_W-1:0] s_apb_dp_ctrl_prdata_reg = '0; + +assign s_apb_dp_ctrl.pready = s_apb_dp_ctrl_pready_reg; +assign s_apb_dp_ctrl.prdata = s_apb_dp_ctrl_prdata_reg; +assign s_apb_dp_ctrl.pslverr = 1'b0; +assign s_apb_dp_ctrl.pruser = '0; +assign s_apb_dp_ctrl.pbuser = '0; always_ff @(posedge clk) begin - s_axil_awready_reg <= 1'b0; - s_axil_wready_reg <= 1'b0; - s_axil_bvalid_reg <= s_axil_bvalid_reg && !s_axil_wr.bready; + s_axil_ctrl_awready_reg <= 1'b0; + s_axil_ctrl_wready_reg <= 1'b0; + s_axil_ctrl_bvalid_reg <= s_axil_ctrl_bvalid_reg && !s_axil_ctrl_wr.bready; - s_axil_arready_reg <= 1'b0; - s_axil_rvalid_reg <= s_axil_rvalid_reg && !s_axil_rd.rready; + s_axil_ctrl_arready_reg <= 1'b0; + s_axil_ctrl_rvalid_reg <= s_axil_ctrl_rvalid_reg && !s_axil_ctrl_rd.rready; - if (s_axil_wr.awvalid && s_axil_wr.wvalid && !s_axil_bvalid_reg) begin - s_axil_awready_reg <= 1'b1; - s_axil_wready_reg <= 1'b1; - s_axil_bvalid_reg <= 1'b1; + s_apb_dp_ctrl_pready_reg <= 1'b0; - case ({s_axil_wr.awaddr[15:2], 2'b00}) + if (s_axil_ctrl_wr.awvalid && s_axil_ctrl_wr.wvalid && !s_axil_ctrl_bvalid_reg) begin + s_axil_ctrl_awready_reg <= 1'b1; + s_axil_ctrl_wready_reg <= 1'b1; + s_axil_ctrl_bvalid_reg <= 1'b1; + + case ({s_axil_ctrl_wr.awaddr[15:2], 2'b00}) 16'h0100: begin - txq_en_reg <= s_axil_wr.wdata[0]; - txq_size_reg <= s_axil_wr.wdata[19:16]; + txq_en_reg <= s_axil_ctrl_wr.wdata[0]; + txq_size_reg <= s_axil_ctrl_wr.wdata[19:16]; end - 16'h0104: txq_prod_reg <= s_axil_wr.wdata[15:0]; - 16'h0108: txq_base_addr_reg[31:0] <= s_axil_wr.wdata; - 16'h010c: txq_base_addr_reg[63:32] <= s_axil_wr.wdata; + 16'h0104: txq_prod_reg <= s_axil_ctrl_wr.wdata[15:0]; + 16'h0108: txq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata; + 16'h010c: txq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata; 16'h0200: begin - rxq_en_reg <= s_axil_wr.wdata[0]; - rxq_size_reg <= s_axil_wr.wdata[19:16]; + rxq_en_reg <= s_axil_ctrl_wr.wdata[0]; + rxq_size_reg <= s_axil_ctrl_wr.wdata[19:16]; end - 16'h0204: rxq_prod_reg <= s_axil_wr.wdata[15:0]; - 16'h0208: rxq_base_addr_reg[31:0] <= s_axil_wr.wdata; - 16'h020c: rxq_base_addr_reg[63:32] <= s_axil_wr.wdata; + 16'h0204: rxq_prod_reg <= s_axil_ctrl_wr.wdata[15:0]; + 16'h0208: rxq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata; + 16'h020c: rxq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata; 16'h0300: begin - txcq_en_reg <= s_axil_wr.wdata[0]; - txcq_size_reg <= s_axil_wr.wdata[19:16]; + txcq_en_reg <= s_axil_ctrl_wr.wdata[0]; + txcq_size_reg <= s_axil_ctrl_wr.wdata[19:16]; end - 16'h0308: txcq_base_addr_reg[31:0] <= s_axil_wr.wdata; - 16'h030c: txcq_base_addr_reg[63:32] <= s_axil_wr.wdata; + 16'h0308: txcq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata; + 16'h030c: txcq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata; 16'h0400: begin - rxcq_en_reg <= s_axil_wr.wdata[0]; - rxcq_size_reg <= s_axil_wr.wdata[19:16]; + rxcq_en_reg <= s_axil_ctrl_wr.wdata[0]; + rxcq_size_reg <= s_axil_ctrl_wr.wdata[19:16]; end - 16'h0408: rxcq_base_addr_reg[31:0] <= s_axil_wr.wdata; - 16'h040c: rxcq_base_addr_reg[63:32] <= s_axil_wr.wdata; + 16'h0408: rxcq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata; + 16'h040c: rxcq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata; default: begin end endcase end - if (s_axil_rd.arvalid && !s_axil_rvalid_reg) begin - s_axil_rdata_reg <= '0; + if (s_axil_ctrl_rd.arvalid && !s_axil_ctrl_rvalid_reg) begin + s_axil_ctrl_rdata_reg <= '0; - s_axil_arready_reg <= 1'b1; - s_axil_rvalid_reg <= 1'b1; + s_axil_ctrl_arready_reg <= 1'b1; + s_axil_ctrl_rvalid_reg <= 1'b1; - case ({s_axil_rd.araddr[15:2], 2'b00}) + case ({s_axil_ctrl_rd.araddr[15:2], 2'b00}) 16'h0100: begin - s_axil_rdata_reg[0] <= txq_en_reg; - s_axil_rdata_reg[19:16] <= txq_size_reg; + s_axil_ctrl_rdata_reg[0] <= txq_en_reg; + s_axil_ctrl_rdata_reg[19:16] <= txq_size_reg; end 16'h0104: begin - s_axil_rdata_reg[15:0] <= txq_prod_reg; - s_axil_rdata_reg[31:16] <= txq_cons; + s_axil_ctrl_rdata_reg[15:0] <= txq_prod_reg; + s_axil_ctrl_rdata_reg[31:16] <= txq_cons; end - 16'h0108: s_axil_rdata_reg <= txq_base_addr_reg[31:0]; - 16'h010c: s_axil_rdata_reg <= txq_base_addr_reg[63:32]; + 16'h0108: s_axil_ctrl_rdata_reg <= txq_base_addr_reg[31:0]; + 16'h010c: s_axil_ctrl_rdata_reg <= txq_base_addr_reg[63:32]; 16'h0200: begin - s_axil_rdata_reg[0] <= rxq_en_reg; - s_axil_rdata_reg[19:16] <= rxq_size_reg; + s_axil_ctrl_rdata_reg[0] <= rxq_en_reg; + s_axil_ctrl_rdata_reg[19:16] <= rxq_size_reg; end 16'h0204: begin - s_axil_rdata_reg[15:0] <= rxq_prod_reg; - s_axil_rdata_reg[31:16] <= rxq_cons; + s_axil_ctrl_rdata_reg[15:0] <= rxq_prod_reg; + s_axil_ctrl_rdata_reg[31:16] <= rxq_cons; end - 16'h0208: s_axil_rdata_reg <= rxq_base_addr_reg[31:0]; - 16'h020c: s_axil_rdata_reg <= rxq_base_addr_reg[63:32]; + 16'h0208: s_axil_ctrl_rdata_reg <= rxq_base_addr_reg[31:0]; + 16'h020c: s_axil_ctrl_rdata_reg <= rxq_base_addr_reg[63:32]; 16'h0300: begin - s_axil_rdata_reg[0] <= txcq_en_reg; - s_axil_rdata_reg[19:16] <= txcq_size_reg; + s_axil_ctrl_rdata_reg[0] <= txcq_en_reg; + s_axil_ctrl_rdata_reg[19:16] <= txcq_size_reg; end - 16'h0304: s_axil_rdata_reg[15:0] <= txcq_prod; - 16'h0308: s_axil_rdata_reg <= txcq_base_addr_reg[31:0]; - 16'h030c: s_axil_rdata_reg <= txcq_base_addr_reg[63:32]; + 16'h0304: s_axil_ctrl_rdata_reg[15:0] <= txcq_prod; + 16'h0308: s_axil_ctrl_rdata_reg <= txcq_base_addr_reg[31:0]; + 16'h030c: s_axil_ctrl_rdata_reg <= txcq_base_addr_reg[63:32]; 16'h0400: begin - s_axil_rdata_reg[0] <= rxcq_en_reg; - s_axil_rdata_reg[19:16] <= rxcq_size_reg; + s_axil_ctrl_rdata_reg[0] <= rxcq_en_reg; + s_axil_ctrl_rdata_reg[19:16] <= rxcq_size_reg; end - 16'h0404: s_axil_rdata_reg[15:0] <= rxcq_prod; - 16'h0408: s_axil_rdata_reg <= rxcq_base_addr_reg[31:0]; - 16'h040c: s_axil_rdata_reg <= rxcq_base_addr_reg[63:32]; + 16'h0404: s_axil_ctrl_rdata_reg[15:0] <= rxcq_prod; + 16'h0408: s_axil_ctrl_rdata_reg <= rxcq_base_addr_reg[31:0]; + 16'h040c: s_axil_ctrl_rdata_reg <= rxcq_base_addr_reg[63:32]; + default: begin end + endcase + end + + if (s_apb_dp_ctrl.penable && s_apb_dp_ctrl.psel && !s_apb_dp_ctrl_pready_reg) begin + s_apb_dp_ctrl_pready_reg <= 1'b1; + s_apb_dp_ctrl_prdata_reg <= '0; + + if (s_apb_dp_ctrl.pwrite) begin + case ({s_apb_dp_ctrl.paddr[15:2], 2'b00}) + 16'h0100: begin + txq_en_reg <= s_apb_dp_ctrl.pwdata[0]; + txq_size_reg <= s_apb_dp_ctrl.pwdata[19:16]; + end + 16'h0104: txq_prod_reg <= s_apb_dp_ctrl.pwdata[15:0]; + 16'h0108: txq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata; + 16'h010c: txq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata; + + 16'h0200: begin + rxq_en_reg <= s_apb_dp_ctrl.pwdata[0]; + rxq_size_reg <= s_apb_dp_ctrl.pwdata[19:16]; + end + 16'h0204: rxq_prod_reg <= s_apb_dp_ctrl.pwdata[15:0]; + 16'h0208: rxq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata; + 16'h020c: rxq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata; + + 16'h0300: begin + txcq_en_reg <= s_apb_dp_ctrl.pwdata[0]; + txcq_size_reg <= s_apb_dp_ctrl.pwdata[19:16]; + end + 16'h0308: txcq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata; + 16'h030c: txcq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata; + + 16'h0400: begin + rxcq_en_reg <= s_apb_dp_ctrl.pwdata[0]; + rxcq_size_reg <= s_apb_dp_ctrl.pwdata[19:16]; + end + 16'h0408: rxcq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata; + 16'h040c: rxcq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata; + default: begin end + endcase + end + + case ({s_apb_dp_ctrl.paddr[15:2], 2'b00}) + 16'h0100: begin + s_apb_dp_ctrl_prdata_reg[0] <= txq_en_reg; + s_apb_dp_ctrl_prdata_reg[19:16] <= txq_size_reg; + end + 16'h0104: begin + s_apb_dp_ctrl_prdata_reg[15:0] <= txq_prod_reg; + s_apb_dp_ctrl_prdata_reg[31:16] <= txq_cons; + end + 16'h0108: s_apb_dp_ctrl_prdata_reg <= txq_base_addr_reg[31:0]; + 16'h010c: s_apb_dp_ctrl_prdata_reg <= txq_base_addr_reg[63:32]; + + 16'h0200: begin + s_apb_dp_ctrl_prdata_reg[0] <= rxq_en_reg; + s_apb_dp_ctrl_prdata_reg[19:16] <= rxq_size_reg; + end + 16'h0204: begin + s_apb_dp_ctrl_prdata_reg[15:0] <= rxq_prod_reg; + s_apb_dp_ctrl_prdata_reg[31:16] <= rxq_cons; + end + 16'h0208: s_apb_dp_ctrl_prdata_reg <= rxq_base_addr_reg[31:0]; + 16'h020c: s_apb_dp_ctrl_prdata_reg <= rxq_base_addr_reg[63:32]; + + 16'h0300: begin + s_apb_dp_ctrl_prdata_reg[0] <= txcq_en_reg; + s_apb_dp_ctrl_prdata_reg[19:16] <= txcq_size_reg; + end + 16'h0304: s_apb_dp_ctrl_prdata_reg[15:0] <= txcq_prod; + 16'h0308: s_apb_dp_ctrl_prdata_reg <= txcq_base_addr_reg[31:0]; + 16'h030c: s_apb_dp_ctrl_prdata_reg <= txcq_base_addr_reg[63:32]; + + 16'h0400: begin + s_apb_dp_ctrl_prdata_reg[0] <= rxcq_en_reg; + s_apb_dp_ctrl_prdata_reg[19:16] <= rxcq_size_reg; + end + 16'h0404: s_apb_dp_ctrl_prdata_reg[15:0] <= rxcq_prod; + 16'h0408: s_apb_dp_ctrl_prdata_reg <= rxcq_base_addr_reg[31:0]; + 16'h040c: s_apb_dp_ctrl_prdata_reg <= rxcq_base_addr_reg[63:32]; default: begin end endcase end if (rst) begin - s_axil_awready_reg <= 1'b0; - s_axil_wready_reg <= 1'b0; - s_axil_bvalid_reg <= 1'b0; + s_axil_ctrl_awready_reg <= 1'b0; + s_axil_ctrl_wready_reg <= 1'b0; + s_axil_ctrl_bvalid_reg <= 1'b0; - s_axil_arready_reg <= 1'b0; - s_axil_rvalid_reg <= 1'b0; + s_axil_ctrl_arready_reg <= 1'b0; + s_axil_ctrl_rvalid_reg <= 1'b0; + + s_apb_dp_ctrl_pready_reg <= 1'b0; end end diff --git a/src/cndm/tb/cndm.py b/src/cndm/tb/cndm.py index fd38da3..e259c01 100644 --- a/src/cndm/tb/cndm.py +++ b/src/cndm/tb/cndm.py @@ -8,18 +8,49 @@ Authors: """ +import array import logging import struct from collections import deque from cocotb.queue import Queue + +# Command opcodes +CNDM_CMD_OP_NOP = 0x0000 + +CNDM_CMD_OP_CREATE_EQ = 0x0200 +CNDM_CMD_OP_MODIFY_EQ = 0x0201 +CNDM_CMD_OP_QUERY_EQ = 0x0202 +CNDM_CMD_OP_DESTROY_EQ = 0x0203 + +CNDM_CMD_OP_CREATE_CQ = 0x0210 +CNDM_CMD_OP_MODIFY_CQ = 0x0211 +CNDM_CMD_OP_QUERY_CQ = 0x0212 +CNDM_CMD_OP_DESTROY_CQ = 0x0213 + +CNDM_CMD_OP_CREATE_SQ = 0x0220 +CNDM_CMD_OP_MODIFY_SQ = 0x0221 +CNDM_CMD_OP_QUERY_SQ = 0x0222 +CNDM_CMD_OP_DESTROY_SQ = 0x0223 + +CNDM_CMD_OP_CREATE_RQ = 0x0230 +CNDM_CMD_OP_MODIFY_RQ = 0x0231 +CNDM_CMD_OP_QUERY_RQ = 0x0232 +CNDM_CMD_OP_DESTROY_RQ = 0x0233 + +CNDM_CMD_OP_CREATE_QP = 0x0240 +CNDM_CMD_OP_MODIFY_QP = 0x0241 +CNDM_CMD_OP_QUERY_QP = 0x0242 +CNDM_CMD_OP_DESTROY_QP = 0x0243 + + class Port: - def __init__(self, driver, index, hw_regs): + def __init__(self, driver, index): self.driver = driver self.log = driver.log self.index = index - self.hw_regs = hw_regs + self.hw_regs = driver.hw_regs self.rxq_log_size = (256).bit_length()-1 self.rxq_size = 2**self.rxq_log_size @@ -27,6 +58,8 @@ class Port: self.rxq = None self.rxq_prod = 0 self.rxq_cons = 0 + self.rx_rqn = 0 + self.rxq_db_offs = 0 self.rx_info = [None] * self.rxq_size @@ -36,6 +69,7 @@ class Port: self.rxcq = None self.rxcq_prod = 0 self.rxcq_cons = 0 + self.rx_cqn = 0 self.txq_log_size = (256).bit_length()-1 self.txq_size = 2**self.txq_log_size @@ -43,6 +77,8 @@ class Port: self.txq = None self.txq_prod = 0 self.txq_cons = 0 + self.tx_sqn = 0 + self.txq_db_offs = 0 self.tx_info = [None] * self.txq_size @@ -52,43 +88,103 @@ class Port: self.txcq = None self.txcq_prod = 0 self.txcq_cons = 0 + self.tx_cqn = 0 self.rx_queue = Queue() async def init(self): - self.rxq = self.driver.pool.alloc_region(self.rxq_size*16) - addr = self.rxq.get_absolute_address(0) - await self.hw_regs.write_dword(0x0200, 0x00000000) - await self.hw_regs.write_dword(0x0204, 0x00000000) - await self.hw_regs.write_dword(0x0208, addr & 0xffffffff) - await self.hw_regs.write_dword(0x020c, addr >> 32) - await self.hw_regs.write_dword(0x0200, 0x00000001 | (self.rxq_log_size << 16)) - self.rxcq = self.driver.pool.alloc_region(self.rxcq_size*16) addr = self.rxcq.get_absolute_address(0) - await self.hw_regs.write_dword(0x0400, 0x00000000) - await self.hw_regs.write_dword(0x0408, addr & 0xffffffff) - await self.hw_regs.write_dword(0x040c, addr >> 32) - await self.hw_regs.write_dword(0x0400, 0x00000001 | (self.rxcq_log_size << 16)) - self.txq = self.driver.pool.alloc_region(self.txq_size*16) - addr = self.txq.get_absolute_address(0) - await self.hw_regs.write_dword(0x0100, 0x00000000) - await self.hw_regs.write_dword(0x0104, 0x00000000) - await self.hw_regs.write_dword(0x0108, addr & 0xffffffff) - await self.hw_regs.write_dword(0x010c, addr >> 32) - await self.hw_regs.write_dword(0x0100, 0x00000001 | (self.txq_log_size << 16)) + rsp = await self.driver.exec_cmd(struct.pack("> 32) - await self.hw_regs.write_dword(0x0300, 0x00000001 | (self.txcq_log_size << 16)) - # wait for writes to complete - await self.hw_regs.read_dword(0) + rsp = await self.driver.exec_cmd(struct.pack("