From ea9a6ad1e6b3451565d6ae93878b910082395ceb Mon Sep 17 00:00:00 2001 From: otroubi Date: Tue, 28 Jul 2026 14:07:25 +0300 Subject: [PATCH] accumulator's changes for dma integration --- rtl/accum/src/accum.sv | 220 ++++++++++++++++++++++++++------- rtl/accum/src/accum_top.sv | 65 +++++++--- rtl/accum/src/adder.sv | 45 ++++--- rtl/accum/src/out_axis_fifo.sv | 31 +++-- 4 files changed, 268 insertions(+), 93 deletions(-) diff --git a/rtl/accum/src/accum.sv b/rtl/accum/src/accum.sv index 121acdc..a1d5af1 100644 --- a/rtl/accum/src/accum.sv +++ b/rtl/accum/src/accum.sv @@ -5,7 +5,6 @@ module accumulator parameter DATA_WIDTH = 12, parameter ACCUM_WIDTH = 32, parameter N_MAX = 4096, - parameter WINDOW_SIZE = 4, parameter PACKET_SIZE = 8, parameter READ_BATCH_SIZE =(PACKET_SIZE*8)/(ACCUM_WIDTH) ) @@ -17,15 +16,19 @@ module accumulator input start, input [31:0] smp_num, input [15:0] seq_num, + input [31:0] window_size, output [ACCUM_WIDTH-1:0] out_data, output out_valid, output readout_begin, input batch_req, - input finish + input finish, + + output logic accum_done ); logic [31:0] smp_num_reg, cnt_smp_num; + logic [31:0] window_size_reg; logic [15:0] seq_num_reg, cnt_seq_num; logic [15:0] cnt_addr, addra, addrb; @@ -39,10 +42,6 @@ module accumulator logic out_valid_reg; logic finish_reg, finish_buf; - // registers for port b data request - reg req_data_b; - reg [15:0] req_addr_b; - typedef enum logic [3:0] { IDLE, INIT_MEM, @@ -58,18 +57,84 @@ module accumulator } wr_state_t; (* MARK_DEBUG="true" *) wr_state_t wr_state; + // One word per clock accumulation pipeline + // On every sum_valid in ACCUM we launch a BRAM read for cnt_addr + // On the next clock the saved sum_data is added to doutb and written back + logic accum_pipe_valid; + logic [15:0] accum_pipe_addr; + logic [ACCUM_WIDTH-1:0] accum_pipe_data; + + // case smp_num // window_size == 1 + // Then the next sequence can read the same address it is written + logic accum_pipe_bypass_valid; + logic [ACCUM_WIDTH-1:0] accum_pipe_bypass_data; + + logic accum_accept_last; + logic accum_accept_last_all; + logic [ACCUM_WIDTH-1:0] accum_write_base; + logic [ACCUM_WIDTH-1:0] accum_write_value; + + wire [31:0] window_size_safe = (window_size == 32'd0) ? 32'd1 : window_size; + wire start_accept = start && (wr_state == IDLE); + + assign accum_accept_last = (cnt_smp_num + window_size_reg >= smp_num_reg); + assign accum_accept_last_all = accum_accept_last && (cnt_seq_num == seq_num_reg - 1); + assign accum_write_base = accum_pipe_bypass_valid ? accum_pipe_bypass_data : data_bram_out; + assign accum_write_value = accum_pipe_data + accum_write_base; + + // Memory controls to XPM + // In accumulation/init states they are driven directly from the current + // state and pipeline registers. That avoids an extra register stage + logic mem_wea; + logic mem_enb; + logic [15:0] mem_addra; + logic [15:0] mem_addrb; + logic [ACCUM_WIDTH-1:0] mem_dina; + + assign mem_wea = (wr_state == INIT_MEM) ? valid_data : + (wr_state == ACCUM) ? accum_pipe_valid : + 1'b0; + + assign mem_addra = (wr_state == INIT_MEM) ? cnt_addr : + (wr_state == ACCUM) ? accum_pipe_addr : + addra; + + assign mem_dina = (wr_state == INIT_MEM) ? data : + (wr_state == ACCUM) ? accum_write_value : + data_bram_in; + + assign mem_enb = (wr_state == ACCUM) ? valid_data : enb; + assign mem_addrb = (wr_state == ACCUM) ? cnt_addr : addrb; + + // registers for port b data request + reg req_data_b; + reg [15:0] req_addr_b; + always @(posedge clk_in) begin if (rst) begin smp_num_reg <= '0; cnt_smp_num <= '0; + window_size_reg <= 32'd1; seq_num_reg <= '0; cnt_seq_num <= '0; cnt_addr <= '0; + addra <= '0; + addrb <= '0; + data_bram_in <= '0; wea <= 0; enb <= 0; wr_state <= IDLE; finish_reg <= 0; + finish_buf <= 0; + readout_begin_reg <= 0; + out_data_reg <= '0; out_valid_reg <= 0; + accum_pipe_valid <= 0; + accum_pipe_addr <= '0; + accum_pipe_data <= '0; + accum_pipe_bypass_valid <= 0; + accum_pipe_bypass_data <= '0; + accum_done <= 0; end else begin finish_buf <= finish; @@ -83,83 +148,137 @@ module accumulator readout_begin_reg <= 0; finish_reg <= 0; out_valid_reg <= 0; + accum_pipe_valid <= 0; + accum_pipe_bypass_valid <= 0; + accum_done <= 0; + cnt_smp_num <= '0; + cnt_seq_num <= '0; + cnt_addr <= '0; + addrb <= '0; if (start) begin smp_num_reg <= smp_num; seq_num_reg <= seq_num; + window_size_reg <= window_size_safe; wr_state <= INIT_MEM; end end + INIT_MEM: begin - // first run to initialize memory with first batch of values + // First sequence wea <= 0; + enb <= 0; + out_valid_reg <= 0; + accum_pipe_valid <= 0; + accum_pipe_bypass_valid <= 0; + accum_done <= 0; + if (valid_data) begin + // mem_wea/mem_addra/mem_dina do the actual write in this clock data_bram_in <= data; addra <= cnt_addr; wea <= 1; - cnt_addr <= cnt_addr + 1; - cnt_smp_num <= cnt_smp_num + WINDOW_SIZE; - end - if (cnt_smp_num >= smp_num_reg) begin - wr_state <= BEGIN_SEQ; + if (cnt_smp_num + window_size_reg >= smp_num_reg) begin + cnt_smp_num <= '0; + cnt_addr <= '0; + + if (seq_num_reg <= 16'd1) begin + cnt_seq_num <= '0; + addrb <= '0; + wr_state <= READOUT_START; + end else begin + // start further accumulation + cnt_seq_num <= 16'd1; + wr_state <= ACCUM; + end + end else begin + cnt_smp_num <= cnt_smp_num + window_size_reg; + cnt_addr <= cnt_addr + 1; + end end end + BEGIN_SEQ: begin - // start new acc seq + // FIXME: unused wea <= 0; enb <= 0; - if (cnt_seq_num == seq_num_reg - 1) begin - cnt_seq_num <= '0; - cnt_smp_num <= '0; - cnt_addr <= '0; - wr_state <= READOUT_START; - addrb <= '0; - enb <= 0; - end else begin - // beginning of new data sequence - cnt_seq_num <= cnt_seq_num + 1; - cnt_smp_num <= '0; - cnt_addr <= '0; - wea <= 0; - addrb <= 0; - wr_state <= REQ_WORD_B; - end + wr_state <= ACCUM; end REQ_WORD_B: begin - // pre-request data for port b + // FIXME: depr wea <= 0; - enb <= 1; - addrb <= cnt_addr; + enb <= 0; wr_state <= ACCUM; end ACCUM: begin - // sum mem+input + // accum pipeline + wea <= 0; enb <= 0; - if (valid_data) begin - addra <= cnt_addr; + out_valid_reg <= 0; + + if (accum_pipe_valid) begin + // mem_wea/mem_addra/mem_dina do the actual write this clock + addra <= accum_pipe_addr; + data_bram_in <= accum_write_value; wea <= 1; - data_bram_in <= data + data_bram_out; - cnt_smp_num <= cnt_smp_num + WINDOW_SIZE; - if (cnt_smp_num + WINDOW_SIZE >= smp_num_reg) begin - wr_state <= BEGIN_SEQ; + end + + if (accum_done) begin + // Last input word was accepted on the previous clk + accum_pipe_valid <= 0; + accum_pipe_bypass_valid <= 0; + cnt_smp_num <= '0; + cnt_seq_num <= '0; + cnt_addr <= '0; + addrb <= '0; + enb <= 0; + wr_state <= READOUT_START; + end else if (valid_data) begin + // mem_enb/mem_addrb launch the actual read this clock + enb <= 1; + addrb <= cnt_addr; + + accum_pipe_valid <= 1; + accum_pipe_addr <= cnt_addr; + accum_pipe_data <= data; + + // case window_size=1 && smp_num is small + accum_pipe_bypass_valid <= accum_pipe_valid && (accum_pipe_addr == cnt_addr); + accum_pipe_bypass_data <= accum_write_value; + + if (accum_accept_last) begin + cnt_smp_num <= '0; + cnt_addr <= '0; + + if (cnt_seq_num == seq_num_reg - 1) begin + accum_done <= 1; + end else begin + cnt_seq_num <= cnt_seq_num + 1; + end end else begin + cnt_smp_num <= cnt_smp_num + window_size_reg; cnt_addr <= cnt_addr + 1; - wr_state <= REQ_WORD_B; end + end else begin + accum_pipe_valid <= 0; + accum_pipe_bypass_valid <= 0; end end + READOUT_START: begin readout_begin_reg <= 1'b1; wr_state <= READOUT_AWAIT; enb <= 0; + wea <= 0; end READOUT_AWAIT: begin - // req await + delay for every-clock readout. + // req await + delay for every-clock readout + wea <= 0; if (batch_req) begin enb <= 1; wr_state <= READOUT_DELAY; @@ -173,12 +292,14 @@ module accumulator READOUT_DELAY: begin // wait for mem latency + wea <= 0; addrb <= addrb + 1; wr_state <= READOUT_PUT; end READOUT_PUT: begin // main data output + wea <= 0; if ((addrb % READ_BATCH_SIZE) == 0) begin wr_state <= READOUT_LAST; enb <= 0; @@ -190,6 +311,7 @@ module accumulator READOUT_LAST: begin // last word of packet + wea <= 0; out_valid_reg <= 0; out_data_reg <= data_bram_out; wr_state <= READOUT_START; @@ -198,6 +320,7 @@ module accumulator FINISH: begin out_valid_reg <= 0; enb <= 0; + wea <= 0; wr_state <= IDLE; end @@ -210,12 +333,13 @@ module accumulator adder #( .DATA_WIDTH(DATA_WIDTH), - .WINDOW_SIZE(WINDOW_SIZE), .ACCUM_WIDTH(ACCUM_WIDTH) ) adder_dut ( .clk_in(clk_in), .rst(rst), + .start(start_accept), + .window_size(window_size), .s_axis_tdata(s_axis_tdata), .s_axis_tvalid(s_axis_tvalid), .sum_data(data), @@ -254,18 +378,18 @@ module accumulator .doutb(data_bram_out), - .addra(addra), - .addrb(addrb), + .addra(mem_addra), + .addrb(mem_addrb), .clka(clk_in), .clkb(clk_in), - .dina(data_bram_in), + .dina(mem_dina), .ena(1'b1), - .enb(enb), - .wea(wea) + .enb(mem_enb), + .wea(mem_wea) ); assign readout_begin = readout_begin_reg; assign out_data = out_data_reg; assign out_valid = out_valid_reg; -endmodule +endmodule \ No newline at end of file diff --git a/rtl/accum/src/accum_top.sv b/rtl/accum/src/accum_top.sv index 3ae2f62..7f4a6af 100644 --- a/rtl/accum/src/accum_top.sv +++ b/rtl/accum/src/accum_top.sv @@ -5,7 +5,6 @@ module accumulator_top parameter DATA_WIDTH = 12, parameter ACCUM_WIDTH = 32, parameter N_MAX = 4096, - parameter WINDOW_SIZE = 65, parameter PACKET_SIZE = 1024, parameter READ_BATCH_SIZE =(PACKET_SIZE*8)/(ACCUM_WIDTH) ) @@ -22,19 +21,17 @@ module accumulator_top input start, input [31:0] smp_num, input [15:0] seq_num, + input [31:0] window_size, // eth signals - input eth_clk_in, + input dma_clk_in, input req_ready, output send_req, // output axis - output logic [7:0] m_axis_tdata, - output logic m_axis_tvalid, - input logic m_axis_tready, - output logic m_axis_tlast, - - output logic finish + axis_if.master m_axis_accum, + output logic finish, + output logic accum_done ); wire [ACCUM_WIDTH-1:0] out_data; @@ -42,41 +39,73 @@ module accumulator_top wire readout_begin; wire batch_req; + logic finish_int; + logic finish_int_d; + logic finish_pulse; + logic calc_active; + logic start_accept; + logic [31:0] window_size_reg; + + wire [31:0] window_size_safe = (window_size == 32'd0) ? 32'd1 : window_size; + + assign finish_pulse = finish_int && !finish_int_d; + assign start_accept = start && !calc_active; + assign finish = finish_int; + + // Keep the top copy stable for blocks that start later than the accum itself + always_ff @(posedge clk_in) begin + if (rst) begin + calc_active <= 1'b0; + finish_int_d <= 1'b0; + window_size_reg <= 32'd1; + end else begin + finish_int_d <= finish_int; + + if (start_accept) begin + calc_active <= 1'b1; + window_size_reg <= window_size_safe; + end else if (finish_pulse) begin + calc_active <= 1'b0; + end + end + end + accumulator #( .DATA_WIDTH(DATA_WIDTH), .ACCUM_WIDTH(ACCUM_WIDTH), .N_MAX(N_MAX), - .WINDOW_SIZE(WINDOW_SIZE), .PACKET_SIZE(PACKET_SIZE) ) accum_main ( .clk_in(clk_in), .rst(rst), .s_axis_tdata(s_axis_tdata), .s_axis_tvalid(s_axis_tvalid), - .start(start), + .start(start_accept), .smp_num(smp_num), .seq_num(seq_num), + .window_size(window_size), .out_data(out_data), .out_valid(out_valid), .readout_begin(readout_begin), .batch_req(batch_req), - .finish(finish) + .finish(finish_int), + .accum_done(accum_done) ); out_axis_fifo #( .ACCUM_WIDTH(ACCUM_WIDTH), - .WINDOW_SIZE(WINDOW_SIZE), .PACKET_SIZE(PACKET_SIZE) ) output_async_fifo ( - .eth_clk_in (eth_clk_in), + .dma_clk_in (dma_clk_in), .acc_clk_in (clk_in), .rst (rst), .smp_num (smp_num), + .window_size (window_size_reg), - .m_axis_tdata (m_axis_tdata), - .m_axis_tvalid (m_axis_tvalid), - .m_axis_tready (m_axis_tready), - .m_axis_tlast (m_axis_tlast), + .m_axis_tdata (m_axis_accum.req.t.data), + .m_axis_tvalid (m_axis_accum.req.t.valid), + .m_axis_tready (m_axis_accum.resp.ready), + .m_axis_tlast (m_axis_accum.req.t.last), .acc_din (out_data), .din_valid (out_valid), @@ -87,6 +116,6 @@ module accumulator_top .send_req (send_req), .batch_req (batch_req), - .finish (finish) + .finish (finish_int) ); endmodule \ No newline at end of file diff --git a/rtl/accum/src/adder.sv b/rtl/accum/src/adder.sv index dd1c3c9..10f953b 100644 --- a/rtl/accum/src/adder.sv +++ b/rtl/accum/src/adder.sv @@ -4,12 +4,13 @@ module adder #( parameter DATA_WIDTH = 12, - parameter WINDOW_SIZE = 4, parameter ACCUM_WIDTH = 32 ) ( input clk_in, input rst, + input start, + input [31:0] window_size, input [DATA_WIDTH-1:0] s_axis_tdata, input s_axis_tvalid, @@ -20,7 +21,10 @@ module adder logic [ACCUM_WIDTH-1:0] accum, res; logic [DATA_WIDTH-1:0] axis_data; logic res_valid, axis_valid; - (* MARK_DEBUG = "TRUE" *) logic [15:0] cnt; + (* MARK_DEBUG = "TRUE" *) logic [31:0] cnt; + logic [31:0] window_size_reg; + + wire [31:0] window_size_safe = (window_size == 32'd0) ? 32'd1 : window_size; always @(posedge clk_in) begin if (rst) begin @@ -28,19 +32,32 @@ module adder cnt <= '0; res <= '0; res_valid <= 0; + axis_data <= '0; + axis_valid <= 0; + window_size_reg <= 32'd1; end else begin res_valid <= 0; - axis_data <= s_axis_tdata; - axis_valid <= s_axis_tvalid; - if ( axis_valid) begin - if (cnt == WINDOW_SIZE-1) begin - res <= accum + axis_data; - res_valid <= 1; - accum <= '0; - cnt <= '0; - end else begin - accum <= accum + axis_data; - cnt <= cnt + 1; + + if (start) begin + accum <= '0; + cnt <= '0; + res <= '0; + axis_data <= '0; + axis_valid <= 0; + window_size_reg <= window_size_safe; + end else begin + axis_data <= s_axis_tdata; + axis_valid <= s_axis_tvalid; + if (axis_valid) begin + if (cnt == window_size_reg - 1) begin + res <= accum + axis_data; + res_valid <= 1; + accum <= '0; + cnt <= '0; + end else begin + accum <= accum + axis_data; + cnt <= cnt + 1; + end end end end @@ -49,4 +66,4 @@ module adder assign sum_valid = res_valid; assign sum_data = res; -endmodule +endmodule \ No newline at end of file diff --git a/rtl/accum/src/out_axis_fifo.sv b/rtl/accum/src/out_axis_fifo.sv index 0deb4f5..ce9d2e1 100644 --- a/rtl/accum/src/out_axis_fifo.sv +++ b/rtl/accum/src/out_axis_fifo.sv @@ -1,15 +1,16 @@ module out_axis_fifo #( parameter ACCUM_WIDTH = 32, - parameter WINDOW_SIZE = 65, + parameter RW_WIDTH = 32, parameter PACKET_SIZE = 1024 ) ( - input logic eth_clk_in, + input logic dma_clk_in, input logic acc_clk_in, input logic rst, input logic [31:0] smp_num, + input logic [31:0] window_size, - // AXI stream master for output, eth_clk_in domain - output logic [7:0] m_axis_tdata, + // AXI stream master for output, dma_clk_in domain + output logic [RW_WIDTH:0] m_axis_tdata, output logic m_axis_tvalid, input logic m_axis_tready, output logic m_axis_tlast, @@ -64,7 +65,7 @@ module out_axis_fifo #( localparam int WDEPTH_BITS = $clog2(MIN_WR_WORDS); localparam int FIFO_WDEPTH = 1 << WDEPTH_BITS; - localparam int FIFO_RDEPTH = FIFO_WDEPTH * ACCUM_WIDTH / 8; + localparam int FIFO_RDEPTH = FIFO_WDEPTH * ACCUM_WIDTH / RW_WIDTH; localparam int RDEPTH_BITS = $clog2(FIFO_RDEPTH) + 1; wire wr_unavail; @@ -85,6 +86,8 @@ module out_axis_fifo #( reg [31:0] wr_cnt; // current BIT mem ptr reg [31:0] wr_batch_tgt; // next 'target' that should be written from batch reg [31:0] wr_total; // total BITS to be sent! + logic [31:0] window_size_reg; + wire [31:0] window_size_safe = (window_size == 32'd0) ? 32'd1 : window_size; wire empty; @@ -92,7 +95,7 @@ module out_axis_fifo #( // NOTE: // each written "acc_din" ACCUM_WIDTH word - // is counted as WINDOWS_SIZE samples actually + // is counted as window_size samples actually // because hw division for counters is painful // so we just increased the counter sizes @@ -102,6 +105,7 @@ module out_axis_fifo #( wr_cnt <= 32'b0; wr_batch_tgt <= 32'b0; wr_total <= 32'b0; + window_size_reg <= 32'd1; batch_req <= 0; finish <= 0; @@ -115,6 +119,7 @@ module out_axis_fifo #( wr_state <= WR_CHECK; wr_total <= smp_num * ACCUM_WIDTH; wr_batch_tgt <= 32'b0; + window_size_reg <= window_size_safe; batch_req <= 0; finish <= 0; end @@ -126,9 +131,9 @@ module out_axis_fifo #( if ((wr_data_count < (FIFO_WDEPTH - (PACKET_SIZE / (ACCUM_WIDTH / 8)))) && ~wr_rst_busy) begin batch_req <= 1; // should give us exactly PACKET_SIZE * 8 bits - // multiplied by WINDOW_SIZE, because we count - // each given ACCUM_WIDTH word as WINDOWS_SIZE samples !!! - wr_batch_tgt <= wr_batch_tgt + (8 * WINDOW_SIZE * PACKET_SIZE); + // multiplied by window_size, because we count + // each given ACCUM_WIDTH word as window_size samples !!! + wr_batch_tgt <= wr_batch_tgt + (8 * window_size_reg * PACKET_SIZE); wr_state <= WR_RUN; end else begin batch_req <= 0; @@ -150,8 +155,8 @@ module out_axis_fifo #( if (din_valid) begin // data supplied - // count as we got WINDOW_SIZE samples - wr_cnt <= wr_cnt + ACCUM_WIDTH * WINDOW_SIZE; + // count as we got window_size samples + wr_cnt <= wr_cnt + ACCUM_WIDTH * window_size_reg; end end @@ -190,7 +195,7 @@ module out_axis_fifo #( wire rd_valid; wire [RDEPTH_BITS-1:0] rd_data_count; - always_ff @(posedge eth_clk_in) begin + always_ff @(posedge dma_clk_in) begin if (rst_eth) begin rd_state <= RD_IDLE; send_req <= 1'b0; @@ -307,7 +312,7 @@ module out_axis_fifo #( - .rd_clk(eth_clk_in), // 1-bit input: Read clock: Used for read operation. rd_clk must be a free running clock. + .rd_clk(dma_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.