// SPDX-License-Identifier: BSD-2-Clause-Views /* * Copyright (c) 2019-2023 The Regents of the University of California */ // Language: Verilog 2001 `resetall `timescale 1ns / 1ps `default_nettype none /* * Queue manager */ module queue_manager # ( // Base address width parameter ADDR_WIDTH = 64, // Request tag field width parameter REQ_TAG_WIDTH = 8, // Number of outstanding operations parameter OP_TABLE_SIZE = 16, // Operation tag field width parameter OP_TAG_WIDTH = 8, // Queue index width (log2 of number of queues) parameter QUEUE_INDEX_WIDTH = 8, // Completion queue index width parameter CPL_INDEX_WIDTH = 8, // Queue element pointer width (log2 of number of elements) parameter QUEUE_PTR_WIDTH = 16, // Log queue size field width parameter LOG_QUEUE_SIZE_WIDTH = $clog2(QUEUE_PTR_WIDTH), // Queue element size parameter DESC_SIZE = 16, // Log desc block size field width parameter LOG_BLOCK_SIZE_WIDTH = 2, // Pipeline stages parameter PIPELINE = 2, // Width of AXI lite data bus in bits parameter AXIL_DATA_WIDTH = 32, // Width of AXI lite address bus in bits parameter AXIL_ADDR_WIDTH = QUEUE_INDEX_WIDTH+5, // Width of AXI lite wstrb (width of data bus in words) parameter AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8) ) ( input wire clk, input wire rst, /* * Dequeue request input */ input wire [QUEUE_INDEX_WIDTH-1:0] s_axis_dequeue_req_queue, input wire [REQ_TAG_WIDTH-1:0] s_axis_dequeue_req_tag, input wire s_axis_dequeue_req_valid, output wire s_axis_dequeue_req_ready, /* * Dequeue response output */ output wire [QUEUE_INDEX_WIDTH-1:0] m_axis_dequeue_resp_queue, output wire [QUEUE_PTR_WIDTH-1:0] m_axis_dequeue_resp_ptr, output wire m_axis_dequeue_resp_phase, output wire [ADDR_WIDTH-1:0] m_axis_dequeue_resp_addr, output wire [LOG_BLOCK_SIZE_WIDTH-1:0] m_axis_dequeue_resp_block_size, output wire [CPL_INDEX_WIDTH-1:0] m_axis_dequeue_resp_cpl, output wire [REQ_TAG_WIDTH-1:0] m_axis_dequeue_resp_tag, output wire [OP_TAG_WIDTH-1:0] m_axis_dequeue_resp_op_tag, output wire m_axis_dequeue_resp_empty, output wire m_axis_dequeue_resp_error, output wire m_axis_dequeue_resp_valid, input wire m_axis_dequeue_resp_ready, /* * Dequeue commit input */ input wire [OP_TAG_WIDTH-1:0] s_axis_dequeue_commit_op_tag, input wire s_axis_dequeue_commit_valid, output wire s_axis_dequeue_commit_ready, /* * Doorbell output */ output wire [QUEUE_INDEX_WIDTH-1:0] m_axis_doorbell_queue, output wire m_axis_doorbell_valid, /* * AXI-Lite slave interface */ input wire [AXIL_ADDR_WIDTH-1:0] s_axil_awaddr, input wire [2:0] s_axil_awprot, input wire s_axil_awvalid, output wire s_axil_awready, input wire [AXIL_DATA_WIDTH-1:0] s_axil_wdata, input wire [AXIL_STRB_WIDTH-1:0] s_axil_wstrb, input wire s_axil_wvalid, output wire s_axil_wready, output wire [1:0] s_axil_bresp, output wire s_axil_bvalid, input wire s_axil_bready, input wire [AXIL_ADDR_WIDTH-1:0] s_axil_araddr, input wire [2:0] s_axil_arprot, input wire s_axil_arvalid, output wire s_axil_arready, output wire [AXIL_DATA_WIDTH-1:0] s_axil_rdata, output wire [1:0] s_axil_rresp, output wire s_axil_rvalid, input wire s_axil_rready, /* * Configuration */ input wire enable ); parameter QUEUE_COUNT = 2**QUEUE_INDEX_WIDTH; parameter CL_OP_TABLE_SIZE = $clog2(OP_TABLE_SIZE); parameter CL_DESC_SIZE = $clog2(DESC_SIZE); parameter QUEUE_RAM_BE_WIDTH = 16; parameter QUEUE_RAM_WIDTH = QUEUE_RAM_BE_WIDTH*8; // bus width assertions initial begin if (OP_TAG_WIDTH < CL_OP_TABLE_SIZE) begin $error("Error: OP_TAG_WIDTH insufficient for OP_TABLE_SIZE (instance %m)"); $finish; end if (AXIL_DATA_WIDTH != 32) begin $error("Error: AXI lite interface width must be 32 (instance %m)"); $finish; end if (AXIL_STRB_WIDTH * 8 != AXIL_DATA_WIDTH) begin $error("Error: AXI lite interface requires byte (8-bit) granularity (instance %m)"); $finish; end if (AXIL_ADDR_WIDTH < QUEUE_INDEX_WIDTH+5) begin $error("Error: AXI lite address width too narrow (instance %m)"); $finish; end if (2**$clog2(DESC_SIZE) != DESC_SIZE) begin $error("Error: Descriptor size must be even power of two (instance %m)"); $finish; end if (PIPELINE < 2) begin $error("Error: PIPELINE must be at least 2 (instance %m)"); $finish; end end reg op_axil_write_pipe_hazard; reg op_axil_read_pipe_hazard; reg op_req_pipe_hazard; reg op_commit_pipe_hazard; reg stage_active; reg [PIPELINE-1:0] op_axil_write_pipe_reg = {PIPELINE{1'b0}}, op_axil_write_pipe_next; reg [PIPELINE-1:0] op_axil_read_pipe_reg = {PIPELINE{1'b0}}, op_axil_read_pipe_next; reg [PIPELINE-1:0] op_req_pipe_reg = {PIPELINE{1'b0}}, op_req_pipe_next; reg [PIPELINE-1:0] op_commit_pipe_reg = {PIPELINE{1'b0}}, op_commit_pipe_next; reg [QUEUE_INDEX_WIDTH-1:0] queue_ram_addr_pipeline_reg[PIPELINE-1:0], queue_ram_addr_pipeline_next[PIPELINE-1:0]; reg [2:0] axil_reg_pipeline_reg[PIPELINE-1:0], axil_reg_pipeline_next[PIPELINE-1:0]; reg [AXIL_DATA_WIDTH-1:0] write_data_pipeline_reg[PIPELINE-1:0], write_data_pipeline_next[PIPELINE-1:0]; reg [AXIL_STRB_WIDTH-1:0] write_strobe_pipeline_reg[PIPELINE-1:0], write_strobe_pipeline_next[PIPELINE-1:0]; reg [REQ_TAG_WIDTH-1:0] req_tag_pipeline_reg[PIPELINE-1:0], req_tag_pipeline_next[PIPELINE-1:0]; reg s_axis_dequeue_req_ready_reg = 1'b0, s_axis_dequeue_req_ready_next; reg [QUEUE_INDEX_WIDTH-1:0] m_axis_dequeue_resp_queue_reg = 0, m_axis_dequeue_resp_queue_next; reg [QUEUE_PTR_WIDTH-1:0] m_axis_dequeue_resp_ptr_reg = 0, m_axis_dequeue_resp_ptr_next; reg m_axis_dequeue_resp_phase_reg = 0, m_axis_dequeue_resp_phase_next; reg [ADDR_WIDTH-1:0] m_axis_dequeue_resp_addr_reg = 0, m_axis_dequeue_resp_addr_next; reg [LOG_BLOCK_SIZE_WIDTH-1:0] m_axis_dequeue_resp_block_size_reg = 0, m_axis_dequeue_resp_block_size_next; reg [CPL_INDEX_WIDTH-1:0] m_axis_dequeue_resp_cpl_reg = 0, m_axis_dequeue_resp_cpl_next; reg [REQ_TAG_WIDTH-1:0] m_axis_dequeue_resp_tag_reg = 0, m_axis_dequeue_resp_tag_next; reg [OP_TAG_WIDTH-1:0] m_axis_dequeue_resp_op_tag_reg = 0, m_axis_dequeue_resp_op_tag_next; reg m_axis_dequeue_resp_empty_reg = 1'b0, m_axis_dequeue_resp_empty_next; reg m_axis_dequeue_resp_error_reg = 1'b0, m_axis_dequeue_resp_error_next; reg m_axis_dequeue_resp_valid_reg = 1'b0, m_axis_dequeue_resp_valid_next; reg s_axis_dequeue_commit_ready_reg = 1'b0, s_axis_dequeue_commit_ready_next; reg [QUEUE_INDEX_WIDTH-1:0] m_axis_doorbell_queue_reg = 0, m_axis_doorbell_queue_next; reg m_axis_doorbell_valid_reg = 0, m_axis_doorbell_valid_next; reg s_axil_awready_reg = 0, s_axil_awready_next; reg s_axil_wready_reg = 0, s_axil_wready_next; reg s_axil_bvalid_reg = 0, s_axil_bvalid_next; reg s_axil_arready_reg = 0, s_axil_arready_next; reg [AXIL_DATA_WIDTH-1:0] s_axil_rdata_reg = 0, s_axil_rdata_next; reg s_axil_rvalid_reg = 0, s_axil_rvalid_next; (* ramstyle = "no_rw_check" *) reg [QUEUE_RAM_WIDTH-1:0] queue_ram[QUEUE_COUNT-1:0]; reg [QUEUE_INDEX_WIDTH-1:0] queue_ram_read_ptr; reg [QUEUE_INDEX_WIDTH-1:0] queue_ram_write_ptr; reg [QUEUE_RAM_WIDTH-1:0] queue_ram_write_data; reg queue_ram_wr_en; reg [QUEUE_RAM_BE_WIDTH-1:0] queue_ram_be; reg [QUEUE_RAM_WIDTH-1:0] queue_ram_read_data_reg = 0; reg [QUEUE_RAM_WIDTH-1:0] queue_ram_read_data_pipeline_reg[PIPELINE-1:1]; wire [QUEUE_PTR_WIDTH-1:0] queue_ram_read_data_prod_ptr = queue_ram_read_data_pipeline_reg[PIPELINE-1][15:0]; wire [QUEUE_PTR_WIDTH-1:0] queue_ram_read_data_cons_ptr = queue_ram_read_data_pipeline_reg[PIPELINE-1][31:16]; wire [CPL_INDEX_WIDTH-1:0] queue_ram_read_data_cpl_queue = queue_ram_read_data_pipeline_reg[PIPELINE-1][47:32]; wire [LOG_QUEUE_SIZE_WIDTH-1:0] queue_ram_read_data_log_queue_size = queue_ram_read_data_pipeline_reg[PIPELINE-1][51:48]; wire [LOG_BLOCK_SIZE_WIDTH-1:0] queue_ram_read_data_log_block_size = queue_ram_read_data_pipeline_reg[PIPELINE-1][53:52]; wire queue_ram_read_data_enable = queue_ram_read_data_pipeline_reg[PIPELINE-1][55]; wire [CL_OP_TABLE_SIZE-1:0] queue_ram_read_data_op_index = queue_ram_read_data_pipeline_reg[PIPELINE-1][63:56]; wire [ADDR_WIDTH-1:0] queue_ram_read_data_base_addr = {queue_ram_read_data_pipeline_reg[PIPELINE-1][127:76], 12'd0}; reg [OP_TABLE_SIZE-1:0] op_table_active = 0; reg [OP_TABLE_SIZE-1:0] op_table_commit = 0; (* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *) reg [QUEUE_INDEX_WIDTH-1:0] op_table_queue[OP_TABLE_SIZE-1:0]; (* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *) reg [QUEUE_PTR_WIDTH-1:0] op_table_queue_ptr[OP_TABLE_SIZE-1:0]; reg [CL_OP_TABLE_SIZE-1:0] op_table_start_ptr_reg = 0; reg [QUEUE_INDEX_WIDTH-1:0] op_table_start_queue; reg [QUEUE_PTR_WIDTH-1:0] op_table_start_queue_ptr; reg op_table_start_en; reg [CL_OP_TABLE_SIZE-1:0] op_table_commit_ptr; reg op_table_commit_en; reg [CL_OP_TABLE_SIZE-1:0] op_table_finish_ptr_reg = 0; reg op_table_finish_en; assign s_axis_dequeue_req_ready = s_axis_dequeue_req_ready_reg; assign m_axis_dequeue_resp_queue = m_axis_dequeue_resp_queue_reg; assign m_axis_dequeue_resp_ptr = m_axis_dequeue_resp_ptr_reg; assign m_axis_dequeue_resp_phase = m_axis_dequeue_resp_phase_reg; assign m_axis_dequeue_resp_addr = m_axis_dequeue_resp_addr_reg; assign m_axis_dequeue_resp_block_size = m_axis_dequeue_resp_block_size_reg; assign m_axis_dequeue_resp_cpl = m_axis_dequeue_resp_cpl_reg; assign m_axis_dequeue_resp_tag = m_axis_dequeue_resp_tag_reg; assign m_axis_dequeue_resp_op_tag = m_axis_dequeue_resp_op_tag_reg; assign m_axis_dequeue_resp_empty = m_axis_dequeue_resp_empty_reg; assign m_axis_dequeue_resp_error = m_axis_dequeue_resp_error_reg; assign m_axis_dequeue_resp_valid = m_axis_dequeue_resp_valid_reg; assign s_axis_dequeue_commit_ready = s_axis_dequeue_commit_ready_reg; assign m_axis_doorbell_queue = m_axis_doorbell_queue_reg; assign m_axis_doorbell_valid = m_axis_doorbell_valid_reg; assign s_axil_awready = s_axil_awready_reg; assign s_axil_wready = s_axil_wready_reg; assign s_axil_bresp = 2'b00; assign s_axil_bvalid = s_axil_bvalid_reg; assign s_axil_arready = s_axil_arready_reg; assign s_axil_rdata = s_axil_rdata_reg; assign s_axil_rresp = 2'b00; assign s_axil_rvalid = s_axil_rvalid_reg; wire [QUEUE_INDEX_WIDTH-1:0] s_axil_awaddr_queue = s_axil_awaddr >> 5; wire [2:0] s_axil_awaddr_reg = s_axil_awaddr >> 2; wire [QUEUE_INDEX_WIDTH-1:0] s_axil_araddr_queue = s_axil_araddr >> 5; wire [2:0] s_axil_araddr_reg = s_axil_araddr >> 2; wire queue_active = op_table_active[queue_ram_read_data_op_index] && op_table_queue[queue_ram_read_data_op_index] == queue_ram_addr_pipeline_reg[PIPELINE-1]; wire queue_empty_idle = queue_ram_read_data_prod_ptr == queue_ram_read_data_cons_ptr; wire queue_empty_active = queue_ram_read_data_prod_ptr == op_table_queue_ptr[queue_ram_read_data_op_index]; wire queue_empty = queue_active ? queue_empty_active : queue_empty_idle; wire [QUEUE_PTR_WIDTH-1:0] queue_ram_read_active_cons_ptr = queue_active ? op_table_queue_ptr[queue_ram_read_data_op_index] : queue_ram_read_data_cons_ptr; integer i, j; initial begin // break up loop to work around iteration termination for (i = 0; i < 2**QUEUE_INDEX_WIDTH; i = i + 2**(QUEUE_INDEX_WIDTH/2)) begin for (j = i; j < i + 2**(QUEUE_INDEX_WIDTH/2); j = j + 1) begin queue_ram[j] = 0; end end for (i = 0; i < PIPELINE; i = i + 1) begin queue_ram_addr_pipeline_reg[i] = 0; axil_reg_pipeline_reg[i] = 0; write_data_pipeline_reg[i] = 0; write_strobe_pipeline_reg[i] = 0; req_tag_pipeline_reg[i] = 0; end for (i = 0; i < OP_TABLE_SIZE; i = i + 1) begin op_table_queue[i] = 0; op_table_queue_ptr[i] = 0; end end always @* begin op_axil_write_pipe_next = {op_axil_write_pipe_reg, 1'b0}; op_axil_read_pipe_next = {op_axil_read_pipe_reg, 1'b0}; op_req_pipe_next = {op_req_pipe_reg, 1'b0}; op_commit_pipe_next = {op_commit_pipe_reg, 1'b0}; queue_ram_addr_pipeline_next[0] = 0; axil_reg_pipeline_next[0] = 0; write_data_pipeline_next[0] = 0; write_strobe_pipeline_next[0] = 0; req_tag_pipeline_next[0] = 0; for (j = 1; j < PIPELINE; j = j + 1) begin queue_ram_addr_pipeline_next[j] = queue_ram_addr_pipeline_reg[j-1]; axil_reg_pipeline_next[j] = axil_reg_pipeline_reg[j-1]; write_data_pipeline_next[j] = write_data_pipeline_reg[j-1]; write_strobe_pipeline_next[j] = write_strobe_pipeline_reg[j-1]; req_tag_pipeline_next[j] = req_tag_pipeline_reg[j-1]; end s_axis_dequeue_req_ready_next = 1'b0; m_axis_dequeue_resp_queue_next = m_axis_dequeue_resp_queue_reg; m_axis_dequeue_resp_ptr_next = m_axis_dequeue_resp_ptr_reg; m_axis_dequeue_resp_phase_next = m_axis_dequeue_resp_phase_reg; m_axis_dequeue_resp_addr_next = m_axis_dequeue_resp_addr_reg; m_axis_dequeue_resp_block_size_next = m_axis_dequeue_resp_block_size_reg; m_axis_dequeue_resp_cpl_next = m_axis_dequeue_resp_cpl_reg; m_axis_dequeue_resp_tag_next = m_axis_dequeue_resp_tag_reg; m_axis_dequeue_resp_op_tag_next = m_axis_dequeue_resp_op_tag_reg; m_axis_dequeue_resp_empty_next = m_axis_dequeue_resp_empty_reg; m_axis_dequeue_resp_error_next = m_axis_dequeue_resp_error_reg; m_axis_dequeue_resp_valid_next = m_axis_dequeue_resp_valid_reg && !m_axis_dequeue_resp_ready; s_axis_dequeue_commit_ready_next = 1'b0; m_axis_doorbell_queue_next = m_axis_doorbell_queue_reg; m_axis_doorbell_valid_next = 1'b0; s_axil_awready_next = 1'b0; s_axil_wready_next = 1'b0; s_axil_bvalid_next = s_axil_bvalid_reg && !s_axil_bready; s_axil_arready_next = 1'b0; s_axil_rdata_next = s_axil_rdata_reg; s_axil_rvalid_next = s_axil_rvalid_reg && !s_axil_rready; queue_ram_read_ptr = 0; queue_ram_write_ptr = queue_ram_addr_pipeline_reg[PIPELINE-1]; queue_ram_write_data = queue_ram_read_data_pipeline_reg[PIPELINE-1]; queue_ram_wr_en = 0; queue_ram_be = 0; op_table_start_queue = queue_ram_addr_pipeline_reg[PIPELINE-1]; op_table_start_queue_ptr = queue_ram_read_active_cons_ptr + 1; op_table_start_en = 1'b0; op_table_commit_ptr = s_axis_dequeue_commit_op_tag; op_table_commit_en = 1'b0; op_table_finish_en = 1'b0; op_axil_write_pipe_hazard = 1'b0; op_axil_read_pipe_hazard = 1'b0; op_req_pipe_hazard = 1'b0; op_commit_pipe_hazard = 1'b0; stage_active = 1'b0; for (j = 0; j < PIPELINE; j = j + 1) begin stage_active = op_axil_write_pipe_reg[j] || op_axil_read_pipe_reg[j] || op_req_pipe_reg[j] || op_commit_pipe_reg[j]; op_axil_write_pipe_hazard = op_axil_write_pipe_hazard || (stage_active && queue_ram_addr_pipeline_reg[j] == s_axil_awaddr_queue); op_axil_read_pipe_hazard = op_axil_read_pipe_hazard || (stage_active && queue_ram_addr_pipeline_reg[j] == s_axil_araddr_queue); op_req_pipe_hazard = op_req_pipe_hazard || (stage_active && queue_ram_addr_pipeline_reg[j] == s_axis_dequeue_req_queue); op_commit_pipe_hazard = op_commit_pipe_hazard || (stage_active && queue_ram_addr_pipeline_reg[j] == op_table_queue[op_table_finish_ptr_reg]); end // pipeline stage 0 - receive request if (s_axil_awvalid && s_axil_wvalid && (!s_axil_bvalid || s_axil_bready) && !op_axil_write_pipe_reg && !op_axil_write_pipe_hazard) begin // AXIL write op_axil_write_pipe_next[0] = 1'b1; s_axil_awready_next = 1'b1; s_axil_wready_next = 1'b1; write_data_pipeline_next[0] = s_axil_wdata; write_strobe_pipeline_next[0] = s_axil_wstrb; queue_ram_read_ptr = s_axil_awaddr_queue; queue_ram_addr_pipeline_next[0] = s_axil_awaddr_queue; axil_reg_pipeline_next[0] = s_axil_awaddr_reg; end else if (s_axil_arvalid && (!s_axil_rvalid || s_axil_rready) && !op_axil_read_pipe_reg && !op_axil_read_pipe_hazard) begin // AXIL read op_axil_read_pipe_next[0] = 1'b1; s_axil_arready_next = 1'b1; queue_ram_read_ptr = s_axil_araddr_queue; queue_ram_addr_pipeline_next[0] = s_axil_araddr_queue; axil_reg_pipeline_next[0] = s_axil_araddr_reg; end else if (op_table_active[op_table_finish_ptr_reg] && op_table_commit[op_table_finish_ptr_reg] && !op_commit_pipe_reg[0] && !op_commit_pipe_hazard) begin // dequeue commit finalize (update pointer) op_commit_pipe_next[0] = 1'b1; op_table_finish_en = 1'b1; write_data_pipeline_next[0] = op_table_queue_ptr[op_table_finish_ptr_reg]; queue_ram_read_ptr = op_table_queue[op_table_finish_ptr_reg]; queue_ram_addr_pipeline_next[0] = op_table_queue[op_table_finish_ptr_reg]; end else if (enable && !op_table_active[op_table_start_ptr_reg] && s_axis_dequeue_req_valid && (!m_axis_dequeue_resp_valid || m_axis_dequeue_resp_ready) && !op_req_pipe_reg && !op_req_pipe_hazard) begin // dequeue request op_req_pipe_next[0] = 1'b1; s_axis_dequeue_req_ready_next = 1'b1; req_tag_pipeline_next[0] = s_axis_dequeue_req_tag; queue_ram_read_ptr = s_axis_dequeue_req_queue; queue_ram_addr_pipeline_next[0] = s_axis_dequeue_req_queue; end // read complete, perform operation if (op_req_pipe_reg[PIPELINE-1]) begin // request m_axis_dequeue_resp_queue_next = queue_ram_addr_pipeline_reg[PIPELINE-1]; m_axis_dequeue_resp_ptr_next = queue_ram_read_active_cons_ptr; m_axis_dequeue_resp_phase_next = !queue_ram_read_active_cons_ptr[queue_ram_read_data_log_queue_size]; m_axis_dequeue_resp_addr_next = queue_ram_read_data_base_addr + ((queue_ram_read_active_cons_ptr & ({QUEUE_PTR_WIDTH{1'b1}} >> (QUEUE_PTR_WIDTH - queue_ram_read_data_log_queue_size))) << (CL_DESC_SIZE+queue_ram_read_data_log_block_size)); m_axis_dequeue_resp_block_size_next = queue_ram_read_data_log_block_size; m_axis_dequeue_resp_cpl_next = queue_ram_read_data_cpl_queue; m_axis_dequeue_resp_tag_next = req_tag_pipeline_reg[PIPELINE-1]; m_axis_dequeue_resp_op_tag_next = op_table_start_ptr_reg; m_axis_dequeue_resp_empty_next = 1'b0; m_axis_dequeue_resp_error_next = 1'b0; queue_ram_write_ptr = queue_ram_addr_pipeline_reg[PIPELINE-1]; queue_ram_write_data[63:56] = op_table_start_ptr_reg; queue_ram_wr_en = 1'b1; op_table_start_queue = queue_ram_addr_pipeline_reg[PIPELINE-1]; op_table_start_queue_ptr = queue_ram_read_active_cons_ptr + 1; if (!queue_ram_read_data_enable) begin // queue inactive m_axis_dequeue_resp_error_next = 1'b1; m_axis_dequeue_resp_valid_next = 1'b1; end else if (queue_empty) begin // queue empty m_axis_dequeue_resp_empty_next = 1'b1; m_axis_dequeue_resp_valid_next = 1'b1; end else begin // start dequeue m_axis_dequeue_resp_valid_next = 1'b1; queue_ram_be[7] = 1'b1; op_table_start_en = 1'b1; end end else if (op_commit_pipe_reg[PIPELINE-1]) begin // commit // update consumer pointer queue_ram_write_ptr = queue_ram_addr_pipeline_reg[PIPELINE-1]; queue_ram_write_data[31:16] = write_data_pipeline_reg[PIPELINE-1]; queue_ram_be[3:2] = 2'b11; queue_ram_wr_en = 1'b1; end else if (op_axil_write_pipe_reg[PIPELINE-1]) begin // AXIL write s_axil_bvalid_next = 1'b1; queue_ram_write_ptr = queue_ram_addr_pipeline_reg[PIPELINE-1]; queue_ram_wr_en = 1'b1; // TODO parametrize case (axil_reg_pipeline_reg[PIPELINE-1]) 3'd0: begin // base address lower 32 // base address is read-only when queue is active if (!queue_ram_read_data_enable) begin queue_ram_write_data[95:76] = write_data_pipeline_reg[PIPELINE-1][31:12]; queue_ram_be[11:9] = write_strobe_pipeline_reg[PIPELINE-1][3:1]; end end 3'd1: begin // base address upper 32 // base address is read-only when queue is active if (!queue_ram_read_data_enable) begin queue_ram_write_data[127:96] = write_data_pipeline_reg[PIPELINE-1]; queue_ram_be[15:12] = write_strobe_pipeline_reg[PIPELINE-1]; end end 3'd2, 3'd3, 4'd4: begin casez (write_data_pipeline_reg[PIPELINE-1]) 32'h8001zzzz: begin // set VF ID // TODO end 32'h8002zzzz: begin // set size if (!queue_ram_read_data_enable) begin // log queue size queue_ram_write_data[51:48] = write_data_pipeline_reg[PIPELINE-1][7:0]; // log desc block size queue_ram_write_data[53:52] = write_data_pipeline_reg[PIPELINE-1][15:8]; queue_ram_be[6] = 1'b1; end end 32'hC0zzzzzz: begin // set CQN if (!queue_ram_read_data_enable) begin queue_ram_write_data[47:32] = write_data_pipeline_reg[PIPELINE-1][23:0]; queue_ram_be[5:4] = 2'b11; end end 32'h8080zzzz: begin // set producer pointer queue_ram_write_data[15:0] = write_data_pipeline_reg[PIPELINE-1][15:0]; queue_ram_be[1:0] = 2'b11; // generate doorbell on queue producer pointer update m_axis_doorbell_queue_next = queue_ram_addr_pipeline_reg[PIPELINE-1]; if (queue_ram_read_data_enable) begin m_axis_doorbell_valid_next = 1'b1; end end 32'h8090zzzz: begin // set consumer pointer if (!queue_ram_read_data_enable) begin queue_ram_write_data[31:16] = write_data_pipeline_reg[PIPELINE-1][15:0]; queue_ram_be[3:2] = 2'b11; end end 32'h400001zz: begin // set enable queue_ram_write_data[55] = write_data_pipeline_reg[PIPELINE-1][0]; queue_ram_be[6] = 1'b1; end default: begin // invalid command $display("Error: Invalid command 0x%x for queue %d (instance %m)", write_data_pipeline_reg[PIPELINE-1], queue_ram_addr_pipeline_reg[PIPELINE-1]); end endcase end endcase end else if (op_axil_read_pipe_reg[PIPELINE-1]) begin // AXIL read s_axil_rvalid_next = 1'b1; s_axil_rdata_next = 0; // TODO parametrize case (axil_reg_pipeline_reg[PIPELINE-1]) 3'd0: begin // VF ID s_axil_rdata_next[11:0] = 0; // TODO // base address lower 32 s_axil_rdata_next[31:12] = queue_ram_read_data_base_addr[31:12]; end 3'd1: begin // base address upper 32 s_axil_rdata_next = queue_ram_read_data_base_addr[63:32]; end 3'd2: begin // control/status // enable s_axil_rdata_next[0] = queue_ram_read_data_enable; // active s_axil_rdata_next[3] = queue_active; end 3'd3: begin // config // CQN s_axil_rdata_next[23:0] = queue_ram_read_data_cpl_queue; // log queue size s_axil_rdata_next[27:24] = queue_ram_read_data_log_queue_size; // log desc block size s_axil_rdata_next[31:28] = queue_ram_read_data_log_block_size; end 3'd4: begin // producer pointer s_axil_rdata_next[15:0] = queue_ram_read_data_prod_ptr; // consumer pointer s_axil_rdata_next[31:16] = queue_ram_read_data_cons_ptr; end endcase end // dequeue commit (record in table) s_axis_dequeue_commit_ready_next = enable; if (s_axis_dequeue_commit_ready && s_axis_dequeue_commit_valid) begin op_table_commit_ptr = s_axis_dequeue_commit_op_tag; op_table_commit_en = 1'b1; end end always @(posedge clk) begin if (rst) begin op_axil_write_pipe_reg <= {PIPELINE{1'b0}}; op_axil_read_pipe_reg <= {PIPELINE{1'b0}}; op_req_pipe_reg <= {PIPELINE{1'b0}}; op_commit_pipe_reg <= {PIPELINE{1'b0}}; s_axis_dequeue_req_ready_reg <= 1'b0; m_axis_dequeue_resp_valid_reg <= 1'b0; s_axis_dequeue_commit_ready_reg <= 1'b0; m_axis_doorbell_valid_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; op_table_active <= 0; op_table_start_ptr_reg <= 0; op_table_finish_ptr_reg <= 0; end else begin op_axil_write_pipe_reg <= op_axil_write_pipe_next; op_axil_read_pipe_reg <= op_axil_read_pipe_next; op_req_pipe_reg <= op_req_pipe_next; op_commit_pipe_reg <= op_commit_pipe_next; s_axis_dequeue_req_ready_reg <= s_axis_dequeue_req_ready_next; m_axis_dequeue_resp_valid_reg <= m_axis_dequeue_resp_valid_next; s_axis_dequeue_commit_ready_reg <= s_axis_dequeue_commit_ready_next; m_axis_doorbell_valid_reg <= m_axis_doorbell_valid_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 (op_table_start_en) begin op_table_start_ptr_reg <= op_table_start_ptr_reg + 1; op_table_active[op_table_start_ptr_reg] <= 1'b1; end if (op_table_finish_en) begin op_table_finish_ptr_reg <= op_table_finish_ptr_reg + 1; op_table_active[op_table_finish_ptr_reg] <= 1'b0; end end for (i = 0; i < PIPELINE; i = i + 1) begin queue_ram_addr_pipeline_reg[i] <= queue_ram_addr_pipeline_next[i]; axil_reg_pipeline_reg[i] <= axil_reg_pipeline_next[i]; write_data_pipeline_reg[i] <= write_data_pipeline_next[i]; write_strobe_pipeline_reg[i] <= write_strobe_pipeline_next[i]; req_tag_pipeline_reg[i] <= req_tag_pipeline_next[i]; end m_axis_dequeue_resp_queue_reg <= m_axis_dequeue_resp_queue_next; m_axis_dequeue_resp_ptr_reg <= m_axis_dequeue_resp_ptr_next; m_axis_dequeue_resp_phase_reg <= m_axis_dequeue_resp_phase_next; m_axis_dequeue_resp_addr_reg <= m_axis_dequeue_resp_addr_next; m_axis_dequeue_resp_block_size_reg <= m_axis_dequeue_resp_block_size_next; m_axis_dequeue_resp_cpl_reg <= m_axis_dequeue_resp_cpl_next; m_axis_dequeue_resp_tag_reg <= m_axis_dequeue_resp_tag_next; m_axis_dequeue_resp_op_tag_reg <= m_axis_dequeue_resp_op_tag_next; m_axis_dequeue_resp_empty_reg <= m_axis_dequeue_resp_empty_next; m_axis_dequeue_resp_error_reg <= m_axis_dequeue_resp_error_next; m_axis_doorbell_queue_reg <= m_axis_doorbell_queue_next; s_axil_rdata_reg <= s_axil_rdata_next; if (queue_ram_wr_en) begin for (i = 0; i < QUEUE_RAM_BE_WIDTH; i = i + 1) begin if (queue_ram_be[i]) begin queue_ram[queue_ram_write_ptr][i*8 +: 8] <= queue_ram_write_data[i*8 +: 8]; end end end queue_ram_read_data_reg <= queue_ram[queue_ram_read_ptr]; queue_ram_read_data_pipeline_reg[1] <= queue_ram_read_data_reg; for (i = 2; i < PIPELINE; i = i + 1) begin queue_ram_read_data_pipeline_reg[i] <= queue_ram_read_data_pipeline_reg[i-1]; end if (op_table_start_en) begin op_table_commit[op_table_start_ptr_reg] <= 1'b0; op_table_queue[op_table_start_ptr_reg] <= op_table_start_queue; op_table_queue_ptr[op_table_start_ptr_reg] <= op_table_start_queue_ptr; end if (op_table_commit_en) begin op_table_commit[op_table_commit_ptr] <= 1'b1; end end endmodule `resetall