cndm: Initial implementation of command interface

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-03-01 13:16:24 -08:00
parent 0ff8e5fb9e
commit e27b5c0b94
16 changed files with 1578 additions and 208 deletions

View File

@@ -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

View File

@@ -20,6 +20,8 @@ Authors:
#include <linux/ptp_clock_kernel.h>
#include <net/devlink.h>
#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

View File

@@ -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);
}

View File

@@ -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 <linux/types.h>
#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

View File

@@ -9,6 +9,7 @@ Authors:
*/
#include "cndm.h"
#include "cndm_hw.h"
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/version.h>
@@ -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;

View File

@@ -9,6 +9,7 @@ Authors:
*/
#include "cndm.h"
#include "cndm_hw.h"
#include <linux/version.h>
@@ -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);

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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("<HHLLLLLLLLLLLLL",
0, # rsvd
CNDM_CMD_OP_CREATE_CQ, # opcode
0x00000000, # flags
self.index, # port
0, # cqn
0, # eqn
0, # pd
self.rxcq_log_size, # size
0, # dboffs
addr, # base addr
0, # ptr2
0, # prod_ptr
0, # cons_ptr
0, # rsvd
0, # rsvd
))
print(rsp)
self.rxq = self.driver.pool.alloc_region(self.rxq_size*16)
addr = self.rxq.get_absolute_address(0)
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLLLLLLL",
0, # rsvd
CNDM_CMD_OP_CREATE_RQ, # opcode
0x00000000, # flags
self.index, # port
0, # rqn
0, # cqn
0, # pd
self.rxq_log_size, # size
0, # dboffs
addr, # base addr
0, # ptr2
0, # prod_ptr
0, # cons_ptr
0, # rsvd
0, # rsvd
))
print(rsp)
self.rxq_db_offs = struct.unpack_from("<L", rsp, 7*4)[0]
self.txcq = self.driver.pool.alloc_region(self.txcq_size*16)
addr = self.txcq.get_absolute_address(0)
await self.hw_regs.write_dword(0x0300, 0x00000000)
await self.hw_regs.write_dword(0x0308, addr & 0xffffffff)
await self.hw_regs.write_dword(0x030c, addr >> 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("<HHLLLLLLLLLLLLL",
0, # rsvd
CNDM_CMD_OP_CREATE_CQ, # opcode
0x00000000, # flags
self.index, # port
1, # cqn
0, # eqn
0, # pd
self.txcq_log_size, # size
0, # dboffs
addr, # base addr
0, # ptr2
0, # prod_ptr
0, # cons_ptr
0, # rsvd
0, # rsvd
))
print(rsp)
self.txq = self.driver.pool.alloc_region(self.txq_size*16)
addr = self.txq.get_absolute_address(0)
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLLLLLLL",
0, # rsvd
CNDM_CMD_OP_CREATE_SQ, # opcode
0x00000000, # flags
self.index, # port
0, # sqn
1, # cqn
0, # pd
self.txq_log_size, # size
0, # dboffs
addr, # base addr
0, # ptr2
0, # prod_ptr
0, # cons_ptr
0, # rsvd
0, # rsvd
))
print(rsp)
self.txq_db_offs = struct.unpack_from("<L", rsp, 7*4)[0]
await self.refill_rx_buffers()
@@ -101,7 +197,7 @@ class Port:
struct.pack_into('<xxxxLQ', self.txq.mem, 16*index, len(data), ptr+headroom)
self.tx_info[index] = tx_buf
self.txq_prod += 1
await self.hw_regs.write_dword(0x0104, self.txq_prod & 0xffff)
await self.hw_regs.write_dword(self.txq_db_offs, self.txq_prod & 0xffff)
async def recv(self):
return await self.rx_queue.get()
@@ -177,7 +273,7 @@ class Port:
self.prepare_rx_desc(self.rxq_prod & self.rxq_mask)
self.rxq_prod += 1
await self.hw_regs.write_dword(0x0204, self.rxq_prod & 0xffff)
await self.hw_regs.write_dword(self.rxq_db_offs, self.rxq_prod & 0xffff)
async def process_rx_cq(self):
@@ -229,6 +325,8 @@ class Driver:
self.pool = None
self.hw_regs = None
self.port_count = None
self.ports = []
self.free_packets = deque()
@@ -256,12 +354,40 @@ class Driver:
self.log.info("Port stride: 0x%x", self.port_stride)
for k in range(self.port_count):
port = Port(self, k, self.hw_regs.create_window(self.port_offset + self.port_stride*k))
port = Port(self, k)
await port.init()
self.dev.request_irq(k, port.interrupt_handler)
self.ports.append(port)
async def exec_cmd(self, cmd):
return await self.exec_mbox_cmd(cmd)
async def exec_mbox_cmd(self, cmd):
cmd = bytes(cmd)
cmd = cmd.ljust(64, b'\x00')
if len(cmd) != 64:
raise ValueError("Invalid command length")
# write command to mailbox
a = array.array("I")
a.frombytes(cmd)
for k, dw in enumerate(a):
await self.hw_regs.write_dword(0x10000+k*4, dw)
# execute it
await self.hw_regs.write_dword(0x0200, 0x00000001)
# wait for completion
while await self.hw_regs.read_dword(0x0200) & 0x00000001:
pass
# read response from mailbox
for k in range(16):
a[k] = await self.hw_regs.read_dword(0x10040+k*4)
return a.tobytes()
def alloc_pkt(self):
if self.free_packets:
return self.free_packets.popleft()