cndm: Add consumer pointer and arm bit to completion queue

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-03-09 14:50:07 -07:00
parent e514869d70
commit c37d967de9
10 changed files with 156 additions and 27 deletions

View File

@@ -45,6 +45,9 @@ module cndm_micro_cpl_wr #(
*/
taxi_axis_if.src m_axis_irq,
/*
* Completion input
*/
taxi_axis_if.snk s_axis_cpl
);
@@ -58,6 +61,7 @@ logic cq_req_ready;
logic [IRQN_W-1:0] cq_rsp_irqn;
logic [DMA_ADDR_W-1:0] cq_rsp_addr;
logic cq_rsp_phase_tag;
logic cq_rsp_arm;
logic cq_rsp_error;
logic cq_rsp_valid;
logic cq_rsp_ready_reg = 1'b0;
@@ -96,6 +100,7 @@ cq_mgr_inst (
.rsp_dqn(cq_rsp_irqn),
.rsp_addr(cq_rsp_addr),
.rsp_phase_tag(cq_rsp_phase_tag),
.rsp_arm(cq_rsp_arm),
.rsp_error(cq_rsp_error),
.rsp_valid(cq_rsp_valid),
.rsp_ready(cq_rsp_ready_reg)
@@ -110,6 +115,7 @@ typedef enum logic [1:0] {
state_t state_reg = STATE_IDLE;
logic phase_tag_reg = 1'b0;
logic arm_reg = 1'b0;
logic [IRQN_W-1:0] m_axis_irq_irqn_reg = '0;
logic m_axis_irq_tvalid_reg = 1'b0;
@@ -167,6 +173,7 @@ always_ff @(posedge clk) begin
m_axis_irq_irqn_reg <= cq_rsp_irqn;
dma_wr_desc_req.req_dst_addr <= cq_rsp_addr;
phase_tag_reg <= cq_rsp_phase_tag;
arm_reg <= cq_rsp_arm;
if (cq_rsp_error) begin
// drop completion
@@ -181,7 +188,7 @@ always_ff @(posedge clk) begin
STATE_WRITE_DATA: begin
if (dma_wr_desc_sts.sts_valid) begin
s_axis_cpl.tready <= 1'b1;
m_axis_irq_tvalid_reg <= 1'b1;
m_axis_irq_tvalid_reg <= arm_reg; // only generate interrupt when armed
state_reg <= STATE_IDLE;
end
end

View File

@@ -100,6 +100,7 @@ wq_mgr_inst (
.rsp_dqn(wq_rsp_cqn),
.rsp_addr(wq_rsp_addr),
.rsp_phase_tag(),
.rsp_arm(),
.rsp_error(wq_rsp_error),
.rsp_valid(wq_rsp_valid),
.rsp_ready(wq_rsp_ready_reg)

View File

@@ -694,7 +694,11 @@ always_comb begin
// reset queue 2
// store doorbell offset
cmd_ram_wr_data = host_ptr_reg + 'h0008;
if (qtype_reg == QTYPE_SQ || qtype_reg == QTYPE_RQ) begin
cmd_ram_wr_data = host_ptr_reg + 'h0008;
end else begin
cmd_ram_wr_data = host_ptr_reg + 'h000C;
end
cmd_ram_wr_addr = 7;
cmd_ram_wr_en = 1'b1;

View File

@@ -513,6 +513,9 @@ cpl_wr_inst (
*/
.m_axis_irq(m_axis_irq),
/*
* Completion input
*/
.s_axis_cpl(axis_cpl)
);

View File

@@ -49,6 +49,7 @@ module cndm_micro_queue_state #(
output wire logic [DQN_W-1:0] rsp_dqn,
output wire logic [DMA_ADDR_W-1:0] rsp_addr,
output wire logic rsp_phase_tag,
output wire logic rsp_arm,
output wire logic rsp_error,
output wire logic rsp_valid,
input wire logic rsp_ready
@@ -119,6 +120,7 @@ logic [QN_W-1:0] rsp_qn_reg = '0, rsp_qn_next;
logic [DQN_W-1:0] rsp_dqn_reg = '0, rsp_dqn_next;
logic [DMA_ADDR_W-1:0] rsp_addr_reg = '0, rsp_addr_next;
logic rsp_phase_tag_reg = 1'b0, rsp_phase_tag_next;
logic rsp_arm_reg = 1'b0, rsp_arm_next;
logic rsp_error_reg = 1'b0, rsp_error_next;
logic rsp_valid_reg = 1'b0, rsp_valid_next;
@@ -127,11 +129,14 @@ assign rsp_qn = rsp_qn_reg;
assign rsp_dqn = rsp_dqn_reg;
assign rsp_addr = rsp_addr_reg;
assign rsp_phase_tag = rsp_phase_tag_reg;
assign rsp_arm = IS_CQ ? rsp_arm_reg : 1'b0;
assign rsp_error = rsp_error_reg;
assign rsp_valid = rsp_valid_reg;
logic [2**QN_W-1:0] queue_enable_reg = '0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic queue_mem_arm[2**QN_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [2:0] queue_mem_qtype[2**QN_W] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [DQN_W-1:0] queue_mem_dqn[2**QN_W] = '{default: '0};
@@ -148,6 +153,7 @@ logic queue_mem_wr_en;
logic [QN_W-1:0] queue_mem_addr;
wire queue_mem_rd_enable = queue_enable_reg[queue_mem_addr];
wire queue_mem_rd_arm = queue_mem_arm[queue_mem_addr];
wire [2:0] queue_mem_rd_qtype = queue_mem_qtype[queue_mem_addr];
wire [DQN_W-1:0] queue_mem_rd_dqn = queue_mem_dqn[queue_mem_addr];
wire [3:0] queue_mem_rd_log_size = queue_mem_log_size[queue_mem_addr];
@@ -155,7 +161,11 @@ wire [DMA_ADDR_W-1:0] queue_mem_rd_base_addr = queue_mem_base_addr[queue_mem_add
wire [PTR_W-1:0] queue_mem_rd_prod_ptr = queue_mem_prod_ptr[queue_mem_addr];
wire [PTR_W-1:0] queue_mem_rd_cons_ptr = queue_mem_cons_ptr[queue_mem_addr];
wire queue_mem_rd_status_empty = queue_mem_rd_prod_ptr == queue_mem_rd_cons_ptr;
wire queue_mem_rd_status_full = ($unsigned(queue_mem_rd_prod_ptr - queue_mem_rd_cons_ptr) & ({PTR_W{1'b1}} << queue_mem_rd_log_size)) != 0;
logic queue_mem_wr_enable;
logic queue_mem_wr_arm;
logic [2:0] queue_mem_wr_qtype;
logic [DQN_W-1:0] queue_mem_wr_dqn;
logic [3:0] queue_mem_wr_log_size;
@@ -180,6 +190,7 @@ always_comb begin
rsp_dqn_next = rsp_dqn_reg;
rsp_addr_next = rsp_addr_reg;
rsp_phase_tag_next = rsp_phase_tag_reg;
rsp_arm_next = rsp_arm_reg;
rsp_error_next = rsp_error_reg;
rsp_valid_next = rsp_valid_reg && !rsp_ready;
@@ -187,6 +198,7 @@ always_comb begin
queue_mem_addr = '0;
queue_mem_wr_enable = queue_mem_rd_enable;
queue_mem_wr_arm = queue_mem_rd_arm;
queue_mem_wr_qtype = queue_mem_rd_qtype;
queue_mem_wr_dqn = queue_mem_rd_dqn;
queue_mem_wr_log_size = queue_mem_rd_log_size;
@@ -194,13 +206,6 @@ always_comb begin
queue_mem_wr_prod_ptr = queue_mem_rd_prod_ptr;
queue_mem_wr_cons_ptr = queue_mem_rd_cons_ptr;
// terminate AXI lite writes
if (IS_CQ && s_axil_ctrl_wr.awvalid && s_axil_ctrl_wr.wvalid && !s_axil_ctrl_bvalid_reg) begin
s_axil_ctrl_awready_next = 1'b1;
s_axil_ctrl_wready_next = 1'b1;
s_axil_ctrl_bvalid_next = 1'b1;
end
// terminate AXI lite reads
if (s_axil_ctrl_rd.arvalid && !s_axil_ctrl_rvalid_reg) begin
s_axil_ctrl_rdata_next = '0;
@@ -209,7 +214,7 @@ always_comb begin
s_axil_ctrl_rvalid_next = 1'b1;
end
if (!IS_CQ && s_axil_ctrl_wr.awvalid && s_axil_ctrl_wr.wvalid && !s_axil_ctrl_bvalid_reg) begin
if (s_axil_ctrl_wr.awvalid && s_axil_ctrl_wr.wvalid && !s_axil_ctrl_bvalid_reg) begin
// AXI lite write
s_axil_ctrl_awready_next = 1'b1;
s_axil_ctrl_wready_next = 1'b1;
@@ -219,7 +224,19 @@ always_comb begin
queue_mem_addr = s_axil_ctrl_awaddr_queue_index;
case (s_axil_ctrl_awaddr_reg_index)
3'd2: queue_mem_wr_prod_ptr = s_axil_ctrl_wr.wdata[15:0];
3'd2: begin
if (!IS_CQ) begin
queue_mem_wr_prod_ptr = s_axil_ctrl_wr.wdata[15:0];
end
end
3'd3: begin
if (IS_CQ) begin
queue_mem_wr_cons_ptr = s_axil_ctrl_wr.wdata[15:0];
if (s_axil_ctrl_wr.wdata[31]) begin
queue_mem_wr_arm = 1'b1;
end
end
end
default: begin end
endcase
@@ -236,12 +253,18 @@ always_comb begin
case (s_apb_dp_ctrl_paddr_reg_index)
3'd0: begin
queue_mem_wr_enable = s_apb_dp_ctrl.pwdata[0];
queue_mem_wr_arm = s_apb_dp_ctrl.pwdata[1];
queue_mem_wr_log_size = s_apb_dp_ctrl.pwdata[19:16];
queue_mem_wr_qtype = 3'(s_apb_dp_ctrl.pwdata[23:20]);
end
3'd1: queue_mem_wr_dqn = s_apb_dp_ctrl.pwdata[DQN_W-1:0];
3'd2: queue_mem_wr_prod_ptr = s_apb_dp_ctrl.pwdata[15:0];
3'd3: queue_mem_wr_cons_ptr = s_apb_dp_ctrl.pwdata[15:0];
3'd3: begin
queue_mem_wr_cons_ptr = s_apb_dp_ctrl.pwdata[15:0];
if (s_apb_dp_ctrl.pwdata[31]) begin
queue_mem_wr_arm = 1'b1;
end
end
3'd6: queue_mem_wr_base_addr[31:0] = s_apb_dp_ctrl.pwdata;
3'd7: queue_mem_wr_base_addr[63:32] = s_apb_dp_ctrl.pwdata;
default: begin end
@@ -251,12 +274,13 @@ always_comb begin
case (s_apb_dp_ctrl_paddr_reg_index)
3'd0: begin
s_apb_dp_ctrl_prdata_next[0] = queue_mem_rd_enable;
s_apb_dp_ctrl_prdata_next[1] = IS_CQ ? queue_mem_rd_arm : 1'b0;
s_apb_dp_ctrl_prdata_next[19:16] = queue_mem_rd_log_size;
s_apb_dp_ctrl_prdata_next[23:20] = 4'(queue_mem_rd_qtype);
s_apb_dp_ctrl_prdata_next[23:20] = QTYPE_EN ? 4'(queue_mem_rd_qtype) : '0;
end
3'd1: s_apb_dp_ctrl_prdata_next = 32'(queue_mem_rd_dqn);
3'd2: s_apb_dp_ctrl_prdata_next[15:0] = queue_mem_rd_prod_ptr;
3'd3: s_apb_dp_ctrl_prdata_next[15:0] = IS_CQ ? '0 : queue_mem_rd_cons_ptr;
3'd2: s_apb_dp_ctrl_prdata_next = 32'(queue_mem_rd_prod_ptr);
3'd3: s_apb_dp_ctrl_prdata_next = 32'(queue_mem_rd_cons_ptr);
3'd6: s_apb_dp_ctrl_prdata_next = queue_mem_rd_base_addr[31:0];
3'd7: s_apb_dp_ctrl_prdata_next = queue_mem_rd_base_addr[63:32];
default: begin end
@@ -267,17 +291,21 @@ always_comb begin
req_ready_next = 1'b1;
queue_mem_addr = req_qn;
queue_mem_wr_arm = 1'b0;
rsp_arm_next = queue_mem_rd_arm;
rsp_qn_next = req_qn;
rsp_dqn_next = queue_mem_rd_dqn;
rsp_error_next = !queue_mem_rd_enable || (QTYPE_EN && req_qtype != queue_mem_rd_qtype);
if (IS_CQ) begin
rsp_addr_next = queue_mem_rd_base_addr + DMA_ADDR_W'(16'(queue_mem_rd_prod_ptr & ({16{1'b1}} >> (16 - queue_mem_rd_log_size))) * QE_SIZE);
rsp_phase_tag_next = !queue_mem_rd_prod_ptr[queue_mem_rd_log_size];
if (queue_mem_rd_status_full)
rsp_error_next = 1'b1;
queue_mem_wr_prod_ptr = queue_mem_rd_prod_ptr + 1;
end else begin
rsp_addr_next = queue_mem_rd_base_addr + DMA_ADDR_W'(16'(queue_mem_rd_cons_ptr & ({16{1'b1}} >> (16 - queue_mem_rd_log_size))) * QE_SIZE);
if (queue_mem_rd_prod_ptr == queue_mem_rd_cons_ptr)
if (queue_mem_rd_status_empty)
rsp_error_next = 1'b1;
queue_mem_wr_cons_ptr = queue_mem_rd_cons_ptr + 1;
end
@@ -306,11 +334,13 @@ always @(posedge clk) begin
rsp_dqn_reg <= rsp_dqn_next;
rsp_addr_reg <= rsp_addr_next;
rsp_phase_tag_reg <= rsp_phase_tag_next;
rsp_arm_reg <= rsp_arm_next;
rsp_error_reg <= rsp_error_next;
rsp_valid_reg <= rsp_valid_next;
if (queue_mem_wr_en) begin
queue_enable_reg[queue_mem_addr] <= queue_mem_wr_enable;
queue_mem_arm[queue_mem_addr] <= queue_mem_wr_arm;
queue_mem_qtype[queue_mem_addr] <= queue_mem_wr_qtype;
queue_mem_dqn[queue_mem_addr] <= queue_mem_wr_dqn;
queue_mem_log_size[queue_mem_addr] <= queue_mem_wr_log_size;