accumulator's changes for dma integration

This commit is contained in:
otroubi
2026-07-28 14:07:25 +03:00
parent 4acaea8d39
commit ea9a6ad1e6
4 changed files with 268 additions and 93 deletions
+172 -48
View File
@@ -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;
end
if (cnt_smp_num + window_size_reg >= smp_num_reg) begin
cnt_smp_num <= '0;
cnt_addr <= '0;
end
BEGIN_SEQ: begin
// start new acc seq
wea <= 0;
enb <= 0;
if (cnt_seq_num == seq_num_reg - 1) begin
if (seq_num_reg <= 16'd1) begin
cnt_seq_num <= '0;
cnt_smp_num <= '0;
cnt_addr <= '0;
wr_state <= READOUT_START;
addrb <= '0;
enb <= 0;
wr_state <= READOUT_START;
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;
// 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
// FIXME: unused
wea <= 0;
enb <= 0;
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,14 +378,14 @@ 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;
+47 -18
View File
@@ -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
+20 -3
View File
@@ -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,12 +32,24 @@ 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;
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-1) begin
if (cnt == window_size_reg - 1) begin
res <= accum + axis_data;
res_valid <= 1;
accum <= '0;
@@ -45,6 +61,7 @@ module adder
end
end
end
end
assign sum_valid = res_valid;
assign sum_data = res;
+18 -13
View File
@@ -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.