rtl: send part of out_axis_fifo

This commit is contained in:
Phil
2026-04-21 17:26:02 +03:00
parent 8e46f965df
commit 21785aaac7

View File

@ -13,6 +13,10 @@ module out_axis_fifo #(
output logic s_axis_tvalid, output logic s_axis_tvalid,
input logic s_axis_tready, input logic s_axis_tready,
output logic s_axis_tlast, 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 // data from acc
input logic [ACCUM_WIDTH-1:0] acc_din, input logic [ACCUM_WIDTH-1:0] acc_din,
@ -25,6 +29,32 @@ module out_axis_fifo #(
output logic batch_req, output logic batch_req,
output logic finish 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 // fifo params calc
// round up to be enough for 2xPACKET_SIZE storage // 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 FIFO_RDEPTH = FIFO_WDEPTH * ACCUM_WIDTH / 8;
localparam int RDEPTH_BITS = $clog2(FIFO_RDEPTH) + 1; localparam int RDEPTH_BITS = $clog2(FIFO_RDEPTH) + 1;
wire rd_unavail;
wire wr_unavail; wire wr_unavail;
wire wr_rst_busy;
reg rd_en; 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_batch_tgt; // next 'target' that should be written from batch
reg [31:0] wr_total; // total BITS to be sent! reg [31:0] wr_total; // total BITS to be sent!
wire [WDEPTH_BITS:0] wr_data_count;
// NOTE: // NOTE:
// each written "acc_din" ACCUM_WIDTH word // each written "acc_din" ACCUM_WIDTH word
// is counted as WINDOWS_SIZE samples actually // is counted as WINDOWS_SIZE samples actually
// because hw division for counters is painful // because hw division for counters is painful
// so we just increased the counter sizes // so we just increased the counter sizes
always_ff @(posedge acc_clk_in or posedge rst) begin always_ff @(posedge acc_clk_in) begin
if (rst) begin if (rst_acc) begin
wr_state <= WR_IDLE; wr_state <= WR_IDLE;
wr_cnt <= 32'b0; wr_cnt <= 32'b0;
wr_batch_tgt <= 32'b0; wr_batch_tgt <= 32'b0;
@ -82,13 +113,15 @@ module out_axis_fifo #(
wr_state <= WR_CHECK; wr_state <= WR_CHECK;
wr_total <= smp_num * ACCUM_WIDTH; wr_total <= smp_num * ACCUM_WIDTH;
wr_batch_tgt <= 32'b0; wr_batch_tgt <= 32'b0;
batch_req <= 0;
finish <= 0;
end end
end end
// wait until we can request a word // wait until we can request a word
// depends on prog_full signal // depends on prog_full signal
WR_CHECK: begin WR_CHECK: begin
if (~wr_unavail) begin if (~wr_unavail && ~wr_rst_busy) begin
batch_req <= 1; batch_req <= 1;
// should give us exactly PACKET_SIZE * 8 bits // should give us exactly PACKET_SIZE * 8 bits
// multiplied by WINDOW_SIZE, because we count // multiplied by WINDOW_SIZE, because we count
@ -103,11 +136,7 @@ module out_axis_fifo #(
// wait until all requested packet is written // wait until all requested packet is written
WR_RUN: begin WR_RUN: begin
batch_req <= 0; batch_req <= 0;
if (din_valid) begin if (wr_cnt == wr_batch_tgt) 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
// got enough words // got enough words
wr_state <= WR_END; wr_state <= WR_END;
end else if (wr_cnt > wr_batch_tgt) begin 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_cnt <= 32'hffffffff; // sort of signal for sim/ila
wr_state <= WR_END; wr_state <= WR_END;
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 end
// check if this was last data batch // check if this was last data batch
@ -123,8 +158,11 @@ module out_axis_fifo #(
// here we check that we sent enough data // here we check that we sent enough data
// wr_cnt should be by design PACKET_SIZE-aligned // wr_cnt should be by design PACKET_SIZE-aligned
if (wr_cnt >= wr_total) begin if (wr_cnt >= wr_total) begin
finish <= 1; // wait until all data is sent
wr_state <= WR_IDLE; if (wr_data_count == 0) begin
finish <= 1;
wr_state <= WR_IDLE;
end
end else begin end else begin
// next word // next word
wr_state <= WR_CHECK; wr_state <= WR_CHECK;
@ -134,60 +172,130 @@ module out_axis_fifo #(
end end
end end
// xpm_fifo_async: Asynchronous FIFO // Readout FSM with ethernet request
// Xilinx Parameterized Macro, version 2025.1
xpm_fifo_async #( assign udp_data_length = PACKET_SIZE; // fixed packet size
.DOUT_RESET_VALUE("0"), // String reg [15:0] sent_cnt;
.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 (
.data_valid(s_axis_tvalid), // 1-bit output: Read Data Valid: When asserted, this signal indicates that valid data is available on the typedef enum logic [2:0] {
// output bus (dout). RD_IDLE = 3'd0,
RD_CHECK = 3'd1,
RD_SEND = 3'd2
} rd_state_t;
.dout(s_axis_tdata), (* MARK_DEBUG="true" *) rd_state_t rd_state;
.empty( ),
.full( ), wire rd_valid;
wire [RDEPTH_BITS-1:0] rd_data_count;
.prog_empty(rd_unavail), // 1-bit output: Programmable Empty: This signal is asserted when the number of words in the FIFO is less than always_ff @(posedge eth_clk_in) begin
// or equal to the programmable empty threshold value. It is de-asserted when the number of words in the FIFO if (rst_eth) begin
// exceeds the programmable empty threshold value. 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;
.prog_full(wr_unavail), // 1-bit output: Programmable Full: This signal is asserted when the number of words in the FIFO is greater than end else begin
// 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. 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
.wr_data_count( ), // WR_DATA_COUNT_WIDTH-bit output: Write Data Count: This bus indicates the number of words written into the // await udp ready
// FIFO. 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( ),
.full( ),
.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), // 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), // 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_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 .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. // from the FIFO. Must be held active-low when rd_rst_busy is active high.
.rst(rst), .rst(rst),
.din(acc_din), // WRITE_DATA_WIDTH-bit input: Write Data: The input data bus used when writing the FIFO. .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_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_en(din_valid),
); .wr_rst_busy(wr_rst_busy)
);
endmodule endmodule