From 21785aaac713615bb67cb01e116216ae1fd1829d Mon Sep 17 00:00:00 2001 From: Phil Date: Tue, 21 Apr 2026 17:26:02 +0300 Subject: [PATCH] rtl: send part of out_axis_fifo --- rtl/accum/src/out_axis_fifo.sv | 224 ++++++++++++++++++++++++--------- 1 file changed, 166 insertions(+), 58 deletions(-) diff --git a/rtl/accum/src/out_axis_fifo.sv b/rtl/accum/src/out_axis_fifo.sv index c73fa59..1bfc079 100644 --- a/rtl/accum/src/out_axis_fifo.sv +++ b/rtl/accum/src/out_axis_fifo.sv @@ -13,6 +13,10 @@ module out_axis_fifo #( output logic s_axis_tvalid, input logic s_axis_tready, output logic s_axis_tlast, + // eth handshake + input logic req_ready, + output logic send_req, + output logic [15:0] udp_data_length, // data from acc input logic [ACCUM_WIDTH-1:0] acc_din, @@ -25,6 +29,32 @@ module out_axis_fifo #( output logic batch_req, output logic finish ); + // sync reset + reg [1:0] rst_sync_ff; + reg rst_eth; + + always @(posedge acc_clk_in or posedge rst) begin + if (rst) begin + rst_sync_ff <= 2'b11; + end else begin + rst_sync_ff <= {rst_sync_ff[0], 1'b0}; + end + end + + assign rst_eth = rst_sync_ff[1]; + + logic [1:0] rst_acc_ff; + logic rst_acc; + + always_ff @(posedge acc_clk_in or posedge rst) begin + if (rst) + rst_acc_ff <= 2'b11; + else + rst_acc_ff <= {rst_acc_ff[0], 1'b0}; + end + + assign rst_acc = rst_acc_ff[1]; + // fifo params calc // round up to be enough for 2xPACKET_SIZE storage @@ -37,9 +67,8 @@ module out_axis_fifo #( localparam int FIFO_RDEPTH = FIFO_WDEPTH * ACCUM_WIDTH / 8; localparam int RDEPTH_BITS = $clog2(FIFO_RDEPTH) + 1; - - wire rd_unavail; wire wr_unavail; + wire wr_rst_busy; reg rd_en; @@ -57,14 +86,16 @@ module out_axis_fifo #( reg [31:0] wr_batch_tgt; // next 'target' that should be written from batch reg [31:0] wr_total; // total BITS to be sent! + wire [WDEPTH_BITS:0] wr_data_count; + // NOTE: // each written "acc_din" ACCUM_WIDTH word // is counted as WINDOWS_SIZE samples actually // because hw division for counters is painful // so we just increased the counter sizes - always_ff @(posedge acc_clk_in or posedge rst) begin - if (rst) begin + always_ff @(posedge acc_clk_in) begin + if (rst_acc) begin wr_state <= WR_IDLE; wr_cnt <= 32'b0; wr_batch_tgt <= 32'b0; @@ -82,13 +113,15 @@ module out_axis_fifo #( wr_state <= WR_CHECK; wr_total <= smp_num * ACCUM_WIDTH; wr_batch_tgt <= 32'b0; + batch_req <= 0; + finish <= 0; end end // wait until we can request a word // depends on prog_full signal WR_CHECK: begin - if (~wr_unavail) begin + if (~wr_unavail && ~wr_rst_busy) begin batch_req <= 1; // should give us exactly PACKET_SIZE * 8 bits // multiplied by WINDOW_SIZE, because we count @@ -103,11 +136,7 @@ module out_axis_fifo #( // wait until all requested packet is written WR_RUN: begin batch_req <= 0; - if (din_valid) begin - // data supplied - // count as we got WINDOW_SIZE samples - wr_cnt <= wr_cnt + ACCUM_WIDTH * WINDOW_SIZE; - end else if (wr_cnt == wr_batch_tgt) begin + if (wr_cnt == wr_batch_tgt) begin // got enough words wr_state <= WR_END; end else if (wr_cnt > wr_batch_tgt) begin @@ -116,6 +145,12 @@ module out_axis_fifo #( wr_cnt <= 32'hffffffff; // sort of signal for sim/ila wr_state <= WR_END; end + + if (din_valid) begin + // data supplied + // count as we got WINDOW_SIZE samples + wr_cnt <= wr_cnt + ACCUM_WIDTH * WINDOW_SIZE; + end end // check if this was last data batch @@ -123,8 +158,11 @@ module out_axis_fifo #( // here we check that we sent enough data // wr_cnt should be by design PACKET_SIZE-aligned if (wr_cnt >= wr_total) begin - finish <= 1; - wr_state <= WR_IDLE; + // wait until all data is sent + if (wr_data_count == 0) begin + finish <= 1; + wr_state <= WR_IDLE; + end end else begin // next word wr_state <= WR_CHECK; @@ -133,61 +171,131 @@ module out_axis_fifo #( endcase end end + + // Readout FSM with ethernet request + + assign udp_data_length = PACKET_SIZE; // fixed packet size + reg [15:0] sent_cnt; + + typedef enum logic [2:0] { + RD_IDLE = 3'd0, + RD_CHECK = 3'd1, + RD_SEND = 3'd2 + } rd_state_t; + + (* MARK_DEBUG="true" *) rd_state_t rd_state; + + wire rd_valid; + wire [RDEPTH_BITS-1:0] rd_data_count; + + always_ff @(posedge eth_clk_in) begin + if (rst_eth) begin + rd_state <= RD_IDLE; + send_req <= 1'b0; + sent_cnt <= 16'd0; + s_axis_tlast <= 1'b0; + s_axis_tvalid <= 1'b0; + rd_en <= 1'b0; + + end else begin + + case (rd_state) + // wait until fifo has enough data to send + RD_IDLE: begin + if (rd_data_count == PACKET_SIZE) begin + // enough data to send packet, begin + rd_state <= RD_CHECK; + end + send_req <= 1'b0; + sent_cnt <= 16'd0; + rd_en <= 1'b0; + s_axis_tlast <= 1'b0; + s_axis_tvalid <= 1'b0; + end + + // await udp ready + RD_CHECK: begin + if (req_ready) begin + send_req <= 1'b1; + rd_state <= RD_SEND; + end + end + + // send data + RD_SEND: begin + // udp is ready and fifo is ready = sent + send_req <= 1'b0; + if (s_axis_tready && rd_valid) begin + rd_en <= 1'b1; + s_axis_tvalid <= 1'b1; + sent_cnt <= sent_cnt + 1; + // final packet of the batch + if (sent_cnt == PACKET_SIZE - 1) begin + rd_state <= RD_IDLE; + s_axis_tlast <= 1'b1; + end + end else begin + rd_en <= 1'b0; + s_axis_tvalid <= 1'b0; + end + end + endcase + end + end + + + // xpm_fifo_async: Asynchronous FIFO + // Xilinx Parameterized Macro, version 2025.1 + + xpm_fifo_async #( + .DOUT_RESET_VALUE("0"), // String + .FIFO_READ_LATENCY(1), // DECIMAL + .FIFO_WRITE_DEPTH(FIFO_WDEPTH), + .FULL_RESET_VALUE(0), + .PROG_EMPTY_THRESH(PACKET_SIZE), + .PROG_FULL_THRESH(PACKET_SIZE / (ACCUM_WIDTH / 8)), + .RD_DATA_COUNT_WIDTH(RDEPTH_BITS), + .READ_DATA_WIDTH(8), // always 8 bit for eth + .READ_MODE("fwft"), + .SIM_ASSERT_CHK(1), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages + .USE_ADV_FEATURES("1616"), // String + .WRITE_DATA_WIDTH(ACCUM_WIDTH), + .WR_DATA_COUNT_WIDTH(WDEPTH_BITS+1) + ) + xpm_fifo_async_inst ( + + .data_valid(rd_valid), // 1-bit output: Read Data Valid: When asserted, this signal indicates that valid data is available on the + // output bus (dout). + + .dout(s_axis_tdata), + .empty( ), - // xpm_fifo_async: Asynchronous FIFO - // Xilinx Parameterized Macro, version 2025.1 + .full( ), - xpm_fifo_async #( - .DOUT_RESET_VALUE("0"), // String - .FIFO_READ_LATENCY(1), // DECIMAL - .FIFO_WRITE_DEPTH(FIFO_WDEPTH), - .FULL_RESET_VALUE(0), - .PROG_EMPTY_THRESH(PACKET_SIZE), - .PROG_FULL_THRESH(PACKET_SIZE / (ACCUM_WIDTH / 8)), - .RD_DATA_COUNT_WIDTH(RDEPTH_BITS), - .READ_DATA_WIDTH(8), // always 8 bit for eth - .READ_MODE("fwft"), - .SIM_ASSERT_CHK(1), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages - .USE_ADV_FEATURES("1606"), // String - .WRITE_DATA_WIDTH(ACCUM_WIDTH), - .WR_DATA_COUNT_WIDTH(WDEPTH_BITS) - ) - xpm_fifo_async_inst ( + .prog_full(wr_unavail), // 1-bit output: Programmable Full: This signal is asserted when the number of words in the FIFO is greater than + // or equal to the programmable full threshold value. It is de-asserted when the number of words in the FIFO is + // less than the programmable full threshold value. - .data_valid(s_axis_tvalid), // 1-bit output: Read Data Valid: When asserted, this signal indicates that valid data is available on the - // output bus (dout). + .rd_data_count(rd_data_count), // RD_DATA_COUNT_WIDTH-bit output: Read Data Count: This bus indicates the number of words read from the FIFO. - .dout(s_axis_tdata), - .empty( ), - - .full( ), - - .prog_empty(rd_unavail), // 1-bit output: Programmable Empty: This signal is asserted when the number of words in the FIFO is less than - // or equal to the programmable empty threshold value. It is de-asserted when the number of words in the FIFO - // exceeds the programmable empty threshold value. - - .prog_full(wr_unavail), // 1-bit output: Programmable Full: This signal is asserted when the number of words in the FIFO is greater than - // or equal to the programmable full threshold value. It is de-asserted when the number of words in the FIFO is - // less than the programmable full threshold value. - - .rd_data_count( ), // RD_DATA_COUNT_WIDTH-bit output: Read Data Count: This bus indicates the number of words read from the FIFO. - - .wr_data_count( ), // WR_DATA_COUNT_WIDTH-bit output: Write Data Count: This bus indicates the number of words written into the - // FIFO. + .wr_data_count(wr_data_count), // WR_DATA_COUNT_WIDTH-bit output: Write Data Count: This bus indicates the number of words written into the + // FIFO. - .rd_clk(eth_clk_in), // 1-bit input: Read clock: Used for read operation. rd_clk must be a free running clock. - .rd_en(rd_en), // 1-bit input: Read Enable: If the FIFO is not empty, asserting this signal causes data (on dout) to be read - // from the FIFO. Must be held active-low when rd_rst_busy is active high. + .rd_clk(eth_clk_in), // 1-bit input: Read clock: Used for read operation. rd_clk must be a free running clock. + .rd_en(rd_en), // 1-bit input: Read Enable: If the FIFO is not empty, asserting this signal causes data (on dout) to be read + // from the FIFO. Must be held active-low when rd_rst_busy is active high. - .rst(rst), - - .din(acc_din), // WRITE_DATA_WIDTH-bit input: Write Data: The input data bus used when writing the FIFO. - .wr_clk(acc_clk_in), // 1-bit input: Write clock: Used for write operation. wr_clk must be a free running clock. - .wr_en(din_valid) + .rst(rst), + + .din(acc_din), // WRITE_DATA_WIDTH-bit input: Write Data: The input data bus used when writing the FIFO. + .wr_clk(acc_clk_in), // 1-bit input: Write clock: Used for write operation. wr_clk must be a free running clock. + .wr_en(din_valid), - ); + .wr_rst_busy(wr_rst_busy) + + ); endmodule \ No newline at end of file