1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-16 08:12:53 +08:00

merged changes in axis

This commit is contained in:
Alex Forencich 2023-07-27 01:45:14 -07:00
commit 6b00ff29c8
10 changed files with 207 additions and 128 deletions

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2014-2021 Alex Forencich
Copyright (c) 2014-2023 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -114,9 +114,13 @@ module axis_async_fifo #
/*
* Status
*/
output wire [$clog2(DEPTH):0] s_status_depth,
output wire [$clog2(DEPTH):0] s_status_depth_commit,
output wire s_status_overflow,
output wire s_status_bad_frame,
output wire s_status_good_frame,
output wire [$clog2(DEPTH):0] m_status_depth,
output wire [$clog2(DEPTH):0] m_status_depth_commit,
output wire m_status_overflow,
output wire m_status_bad_frame,
output wire m_status_good_frame
@ -161,13 +165,25 @@ localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0);
localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0);
localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0);
function [ADDR_WIDTH:0] bin2gray(input [ADDR_WIDTH:0] b);
bin2gray = b ^ (b >> 1);
endfunction
function [ADDR_WIDTH:0] gray2bin(input [ADDR_WIDTH:0] g);
integer i;
for (i = 0; i <= ADDR_WIDTH; i = i + 1) begin
gray2bin[i] = ^(g >> i);
end
endfunction
reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_commit_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_sync_gray_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_cur_gray_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_sync_commit_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_conv_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_conv_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_temp;
reg [ADDR_WIDTH:0] rd_ptr_temp;
@ -177,6 +193,8 @@ reg [ADDR_WIDTH:0] wr_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
(* SHREG_EXTRACT = "NO" *)
reg [ADDR_WIDTH:0] wr_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
(* SHREG_EXTRACT = "NO" *)
reg [ADDR_WIDTH:0] wr_ptr_commit_sync_reg = {ADDR_WIDTH+1{1'b0}};
(* SHREG_EXTRACT = "NO" *)
reg [ADDR_WIDTH:0] rd_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
(* SHREG_EXTRACT = "NO" *)
reg [ADDR_WIDTH:0] rd_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
@ -218,11 +236,10 @@ reg [RAM_PIPELINE+1-1:0] m_axis_tvalid_pipe_reg = 0;
// full when first TWO MSBs do NOT match, but rest matches
// (gray code equivalent of first MSB different but rest same)
wire full = wr_ptr_gray_reg == (rd_ptr_gray_sync2_reg ^ {2'b11, {ADDR_WIDTH-1{1'b0}}});
wire full_cur = wr_ptr_cur_gray_reg == (rd_ptr_gray_sync2_reg ^ {2'b11, {ADDR_WIDTH-1{1'b0}}});
// empty when pointers match exactly
wire empty = rd_ptr_gray_reg == (FRAME_FIFO ? wr_ptr_gray_sync1_reg : wr_ptr_gray_sync2_reg);
wire empty = FRAME_FIFO ? (rd_ptr_reg == wr_ptr_commit_sync_reg) : (rd_ptr_gray_reg == wr_ptr_gray_sync2_reg);
// overflow within packet
wire full_wr = wr_ptr_reg == (wr_ptr_cur_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}});
wire full_wr = wr_ptr_reg == (wr_ptr_commit_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}});
// control signals
reg write;
@ -241,6 +258,11 @@ reg good_frame_reg = 1'b0;
reg m_drop_frame_reg = 1'b0;
reg m_terminate_frame_reg = 1'b0;
reg [ADDR_WIDTH:0] s_depth_reg = 0;
reg [ADDR_WIDTH:0] s_depth_commit_reg = 0;
reg [ADDR_WIDTH:0] m_depth_reg = 0;
reg [ADDR_WIDTH:0] m_depth_commit_reg = 0;
reg overflow_sync1_reg = 1'b0;
reg overflow_sync2_reg = 1'b0;
reg overflow_sync3_reg = 1'b0;
@ -254,7 +276,7 @@ reg good_frame_sync2_reg = 1'b0;
reg good_frame_sync3_reg = 1'b0;
reg good_frame_sync4_reg = 1'b0;
assign s_axis_tready = (FRAME_FIFO ? (!full_cur || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : !full) && !s_rst_sync3_reg;
assign s_axis_tready = (FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : !full) && !s_rst_sync3_reg;
wire [WIDTH-1:0] s_axis;
@ -280,10 +302,14 @@ wire [USER_WIDTH-1:0] m_axis_tuser_pipe = USER_ENABLE ? (m_terminate_frame_reg
wire pipe_ready;
assign s_status_depth = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {s_depth_reg, {$clog2(KEEP_WIDTH){1'b0}}} : s_depth_reg;
assign s_status_depth_commit = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {s_depth_commit_reg, {$clog2(KEEP_WIDTH){1'b0}}} : s_depth_commit_reg;
assign s_status_overflow = overflow_reg;
assign s_status_bad_frame = bad_frame_reg;
assign s_status_good_frame = good_frame_reg;
assign m_status_depth = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {m_depth_reg, {$clog2(KEEP_WIDTH){1'b0}}} : m_depth_reg;
assign m_status_depth_commit = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {m_depth_commit_reg, {$clog2(KEEP_WIDTH){1'b0}}} : m_depth_commit_reg;
assign m_status_overflow = overflow_sync3_reg ^ overflow_sync4_reg;
assign m_status_bad_frame = bad_frame_sync3_reg ^ bad_frame_sync4_reg;
assign m_status_good_frame = good_frame_sync3_reg ^ good_frame_sync4_reg;
@ -326,7 +352,7 @@ always @(posedge s_clk) begin
if (wr_ptr_update_reg == wr_ptr_update_ack_sync2_reg) begin
// no sync in progress; sync update
wr_ptr_update_valid_reg <= 1'b0;
wr_ptr_sync_gray_reg <= wr_ptr_gray_reg;
wr_ptr_sync_commit_reg <= wr_ptr_commit_reg;
wr_ptr_update_reg <= !wr_ptr_update_ack_sync2_reg;
end
end
@ -362,44 +388,46 @@ always @(posedge s_clk) begin
// update pointers
wr_ptr_temp = wr_ptr_reg + 1;
wr_ptr_reg <= wr_ptr_temp;
wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1);
wr_ptr_commit_reg <= wr_ptr_temp;
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
end
end else if ((full_cur && DROP_WHEN_FULL) || (full_wr && DROP_OVERSIZE_FRAME) || drop_frame_reg) begin
end else if ((full && DROP_WHEN_FULL) || (full_wr && DROP_OVERSIZE_FRAME) || drop_frame_reg) begin
// full, packet overflow, or currently dropping frame
// drop frame
drop_frame_reg <= 1'b1;
if (s_axis_tlast) begin
// end of frame, reset write pointer
wr_ptr_temp = wr_ptr_reg;
wr_ptr_cur_reg <= wr_ptr_temp;
wr_ptr_cur_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1);
wr_ptr_temp = wr_ptr_commit_reg;
wr_ptr_reg <= wr_ptr_temp;
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
drop_frame_reg <= 1'b0;
overflow_reg <= 1'b1;
end
end else begin
mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= s_axis;
wr_ptr_temp = wr_ptr_cur_reg + 1;
wr_ptr_cur_reg <= wr_ptr_temp;
wr_ptr_cur_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1);
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
wr_ptr_temp = wr_ptr_reg + 1;
wr_ptr_reg <= wr_ptr_temp;
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
if (s_axis_tlast || (!DROP_OVERSIZE_FRAME && (full_wr || send_frame_reg))) begin
// end of frame or send frame
send_frame_reg <= !s_axis_tlast;
if (s_axis_tlast && DROP_BAD_FRAME && USER_BAD_FRAME_MASK & ~(s_axis_tuser ^ USER_BAD_FRAME_VALUE)) begin
// bad packet, reset write pointer
wr_ptr_temp = wr_ptr_reg;
wr_ptr_cur_reg <= wr_ptr_temp;
wr_ptr_cur_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1);
wr_ptr_temp = wr_ptr_commit_reg;
wr_ptr_reg <= wr_ptr_temp;
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
bad_frame_reg <= 1'b1;
end else begin
// good packet or packet overflow, update write pointer
wr_ptr_temp = wr_ptr_cur_reg + 1;
wr_ptr_temp = wr_ptr_reg + 1;
wr_ptr_reg <= wr_ptr_temp;
wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1);
wr_ptr_commit_reg <= wr_ptr_temp;
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
if (wr_ptr_update_reg == wr_ptr_update_ack_sync2_reg) begin
// no sync in progress; sync update
wr_ptr_update_valid_reg <= 1'b0;
wr_ptr_sync_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1);
wr_ptr_sync_commit_reg <= wr_ptr_temp;
wr_ptr_update_reg <= !wr_ptr_update_ack_sync2_reg;
end else begin
// sync in progress; flag it for later
@ -414,14 +442,15 @@ always @(posedge s_clk) begin
// data valid with packet overflow
// update write pointer
send_frame_reg <= 1'b1;
wr_ptr_temp = wr_ptr_cur_reg;
wr_ptr_temp = wr_ptr_reg;
wr_ptr_reg <= wr_ptr_temp;
wr_ptr_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1);
wr_ptr_commit_reg <= wr_ptr_temp;
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
if (wr_ptr_update_reg == wr_ptr_update_ack_sync2_reg) begin
// no sync in progress; sync update
wr_ptr_update_valid_reg <= 1'b0;
wr_ptr_sync_gray_reg <= wr_ptr_temp ^ (wr_ptr_temp >> 1);
wr_ptr_sync_commit_reg <= wr_ptr_temp;
wr_ptr_update_reg <= !wr_ptr_update_ack_sync2_reg;
end else begin
// sync in progress; flag it for later
@ -431,10 +460,9 @@ always @(posedge s_clk) begin
if (s_rst_sync3_reg) begin
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_commit_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_sync_gray_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_cur_gray_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_sync_commit_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_update_valid_reg <= 1'b0;
wr_ptr_update_reg <= 1'b0;
@ -442,10 +470,9 @@ always @(posedge s_clk) begin
if (s_rst) begin
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_commit_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_sync_gray_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_cur_gray_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_sync_commit_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_update_valid_reg <= 1'b0;
wr_ptr_update_reg <= 1'b0;
@ -460,6 +487,13 @@ always @(posedge s_clk) begin
end
end
// Write-side status
always @(posedge s_clk) begin
rd_ptr_conv_reg <= gray2bin(rd_ptr_gray_sync2_reg);
s_depth_reg <= wr_ptr_reg - rd_ptr_conv_reg;
s_depth_commit_reg <= wr_ptr_commit_reg - rd_ptr_conv_reg;
end
// pointer synchronization
always @(posedge s_clk) begin
rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg;
@ -476,12 +510,11 @@ always @(posedge s_clk) begin
end
always @(posedge m_clk) begin
if (!FRAME_FIFO) begin
wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg;
end else if (wr_ptr_update_sync2_reg ^ wr_ptr_update_sync3_reg) begin
wr_ptr_gray_sync1_reg <= wr_ptr_sync_gray_reg;
end
wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg;
wr_ptr_gray_sync2_reg <= wr_ptr_gray_sync1_reg;
if (FRAME_FIFO && wr_ptr_update_sync2_reg ^ wr_ptr_update_sync3_reg) begin
wr_ptr_commit_sync_reg <= wr_ptr_sync_commit_reg;
end
wr_ptr_update_sync1_reg <= wr_ptr_update_reg;
wr_ptr_update_sync2_reg <= wr_ptr_update_sync1_reg;
wr_ptr_update_sync3_reg <= wr_ptr_update_sync2_reg;
@ -493,6 +526,7 @@ always @(posedge m_clk) begin
if (m_rst) begin
wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_commit_sync_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_update_sync1_reg <= 1'b0;
wr_ptr_update_sync2_reg <= 1'b0;
wr_ptr_update_sync3_reg <= 1'b0;
@ -615,6 +649,13 @@ always @(posedge m_clk) begin
end
end
// Read-side status
always @(posedge m_clk) begin
wr_ptr_conv_reg <= gray2bin(wr_ptr_gray_sync2_reg);
m_depth_reg <= wr_ptr_conv_reg - rd_ptr_reg;
m_depth_commit_reg <= FRAME_FIFO ? wr_ptr_commit_sync_reg - rd_ptr_reg : wr_ptr_conv_reg - rd_ptr_reg;
end
generate
if (!OUTPUT_FIFO_ENABLE) begin

View File

@ -119,9 +119,13 @@ module axis_async_fifo_adapter #
/*
* Status
*/
output wire [$clog2(DEPTH):0] s_status_depth,
output wire [$clog2(DEPTH):0] s_status_depth_commit,
output wire s_status_overflow,
output wire s_status_bad_frame,
output wire s_status_good_frame,
output wire [$clog2(DEPTH):0] m_status_depth,
output wire [$clog2(DEPTH):0] m_status_depth_commit,
output wire m_status_overflow,
output wire m_status_bad_frame,
output wire m_status_good_frame
@ -350,9 +354,13 @@ fifo_inst (
.m_axis_tdest(post_fifo_axis_tdest),
.m_axis_tuser(post_fifo_axis_tuser),
// Status
.s_status_depth(s_status_depth),
.s_status_depth_commit(s_status_depth_commit),
.s_status_overflow(s_status_overflow),
.s_status_bad_frame(s_status_bad_frame),
.s_status_good_frame(s_status_good_frame),
.m_status_depth(m_status_depth),
.m_status_depth_commit(m_status_depth_commit),
.m_status_overflow(m_status_overflow),
.m_status_bad_frame(m_status_bad_frame),
.m_status_good_frame(m_status_good_frame)

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2013-2021 Alex Forencich
Copyright (c) 2013-2023 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -113,6 +113,8 @@ module axis_fifo #
/*
* Status
*/
output wire [$clog2(DEPTH):0] status_depth,
output wire [$clog2(DEPTH):0] status_depth_commit,
output wire status_overflow,
output wire status_bad_frame,
output wire status_good_frame
@ -158,7 +160,7 @@ localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0);
localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0);
reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_commit_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}};
(* ramstyle = "no_rw_check" *)
@ -171,19 +173,20 @@ reg [RAM_PIPELINE+1-1:0] m_axis_tvalid_pipe_reg = 0;
// full when first MSB different but rest same
wire full = wr_ptr_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}});
wire full_cur = wr_ptr_cur_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}});
// empty when pointers match exactly
wire empty = wr_ptr_reg == rd_ptr_reg;
wire empty = wr_ptr_commit_reg == rd_ptr_reg;
// overflow within packet
wire full_wr = wr_ptr_reg == (wr_ptr_cur_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}});
wire full_wr = wr_ptr_reg == (wr_ptr_commit_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}});
reg drop_frame_reg = 1'b0;
reg send_frame_reg = 1'b0;
reg [ADDR_WIDTH:0] depth_reg = 0;
reg [ADDR_WIDTH:0] depth_commit_reg = 0;
reg overflow_reg = 1'b0;
reg bad_frame_reg = 1'b0;
reg good_frame_reg = 1'b0;
assign s_axis_tready = FRAME_FIFO ? (!full_cur || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : !full;
assign s_axis_tready = FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : !full;
wire [WIDTH-1:0] s_axis;
@ -209,6 +212,8 @@ wire [USER_WIDTH-1:0] m_axis_tuser_pipe = USER_ENABLE ? m_axis[USER_OFFSET +:
wire pipe_ready;
assign status_depth = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {depth_reg, {$clog2(KEEP_WIDTH){1'b0}}} : depth_reg;
assign status_depth_commit = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {depth_commit_reg, {$clog2(KEEP_WIDTH){1'b0}}} : depth_commit_reg;
assign status_overflow = overflow_reg;
assign status_bad_frame = bad_frame_reg;
assign status_good_frame = good_frame_reg;
@ -225,30 +230,31 @@ always @(posedge clk) begin
// normal FIFO mode
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
wr_ptr_reg <= wr_ptr_reg + 1;
end else if ((full_cur && DROP_WHEN_FULL) || (full_wr && DROP_OVERSIZE_FRAME) || drop_frame_reg) begin
wr_ptr_commit_reg <= wr_ptr_reg + 1;
end else if ((full && DROP_WHEN_FULL) || (full_wr && DROP_OVERSIZE_FRAME) || drop_frame_reg) begin
// full, packet overflow, or currently dropping frame
// drop frame
drop_frame_reg <= 1'b1;
if (s_axis_tlast) begin
// end of frame, reset write pointer
wr_ptr_cur_reg <= wr_ptr_reg;
wr_ptr_reg <= wr_ptr_commit_reg;
drop_frame_reg <= 1'b0;
overflow_reg <= 1'b1;
end
end else begin
// store it
mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= s_axis;
wr_ptr_cur_reg <= wr_ptr_cur_reg + 1;
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
wr_ptr_reg <= wr_ptr_reg + 1;
if (s_axis_tlast || (!DROP_OVERSIZE_FRAME && (full_wr || send_frame_reg))) begin
// end of frame or send frame
send_frame_reg <= !s_axis_tlast;
if (s_axis_tlast && DROP_BAD_FRAME && USER_BAD_FRAME_MASK & ~(s_axis_tuser ^ USER_BAD_FRAME_VALUE)) begin
// bad packet, reset write pointer
wr_ptr_cur_reg <= wr_ptr_reg;
wr_ptr_reg <= wr_ptr_commit_reg;
bad_frame_reg <= 1'b1;
end else begin
// good packet or packet overflow, update write pointer
wr_ptr_reg <= wr_ptr_cur_reg + 1;
wr_ptr_commit_reg <= wr_ptr_reg + 1;
good_frame_reg <= s_axis_tlast;
end
end
@ -257,12 +263,12 @@ always @(posedge clk) begin
// data valid with packet overflow
// update write pointer
send_frame_reg <= 1'b1;
wr_ptr_reg <= wr_ptr_cur_reg;
wr_ptr_commit_reg <= wr_ptr_reg;
end
if (rst) begin
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_commit_reg <= {ADDR_WIDTH+1{1'b0}};
drop_frame_reg <= 1'b0;
send_frame_reg <= 1'b0;
@ -272,6 +278,12 @@ always @(posedge clk) begin
end
end
// Status
always @(posedge clk) begin
depth_reg <= wr_ptr_reg - rd_ptr_reg;
depth_commit_reg <= wr_ptr_commit_reg - rd_ptr_reg;
end
// Read logic
integer j;

View File

@ -118,6 +118,8 @@ module axis_fifo_adapter #
/*
* Status
*/
output wire [$clog2(DEPTH):0] status_depth,
output wire [$clog2(DEPTH):0] status_depth_commit,
output wire status_overflow,
output wire status_bad_frame,
output wire status_good_frame
@ -343,6 +345,8 @@ fifo_inst (
.m_axis_tdest(post_fifo_axis_tdest),
.m_axis_tuser(post_fifo_axis_tuser),
// Status
.status_depth(status_depth),
.status_depth_commit(status_depth_commit),
.status_overflow(status_overflow),
.status_bad_frame(status_bad_frame),
.status_good_frame(status_good_frame)

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2021 Alex Forencich
Copyright (c) 2021-2023 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -87,85 +87,89 @@ module axis_pipeline_fifo #
parameter FIFO_ADDR_WIDTH = LENGTH < 2 ? 3 : $clog2(LENGTH*4+1);
wire [DATA_WIDTH-1:0] axis_tdata_pipe[0:LENGTH];
wire [KEEP_WIDTH-1:0] axis_tkeep_pipe[0:LENGTH];
wire axis_tvalid_pipe[0:LENGTH];
wire axis_tready_pipe[0:LENGTH];
wire axis_tlast_pipe[0:LENGTH];
wire [ID_WIDTH-1:0] axis_tid_pipe[0:LENGTH];
wire [DEST_WIDTH-1:0] axis_tdest_pipe[0:LENGTH];
wire [USER_WIDTH-1:0] axis_tuser_pipe[0:LENGTH];
generate
if (LENGTH > 0) begin
genvar n;
// pipeline
(* shreg_extract = "no" *)
reg [DATA_WIDTH-1:0] axis_tdata_reg[0:LENGTH-1];
(* shreg_extract = "no" *)
reg [KEEP_WIDTH-1:0] axis_tkeep_reg[0:LENGTH-1];
(* shreg_extract = "no" *)
reg axis_tvalid_reg[0:LENGTH-1];
(* shreg_extract = "no" *)
reg axis_tready_reg[0:LENGTH-1];
(* shreg_extract = "no" *)
reg axis_tlast_reg[0:LENGTH-1];
(* shreg_extract = "no" *)
reg [ID_WIDTH-1:0] axis_tid_reg[0:LENGTH-1];
(* shreg_extract = "no" *)
reg [DEST_WIDTH-1:0] axis_tdest_reg[0:LENGTH-1];
(* shreg_extract = "no" *)
reg [USER_WIDTH-1:0] axis_tuser_reg[0:LENGTH-1];
for (n = 0; n < LENGTH; n = n + 1) begin : stage
wire [DATA_WIDTH-1:0] m_axis_tdata_int = axis_tdata_reg[LENGTH-1];
wire [KEEP_WIDTH-1:0] m_axis_tkeep_int = axis_tkeep_reg[LENGTH-1];
wire m_axis_tvalid_int = axis_tvalid_reg[LENGTH-1];
wire m_axis_tready_int;
wire m_axis_tlast_int = axis_tlast_reg[LENGTH-1];
wire [ID_WIDTH-1:0] m_axis_tid_int = axis_tid_reg[LENGTH-1];
wire [DEST_WIDTH-1:0] m_axis_tdest_int = axis_tdest_reg[LENGTH-1];
wire [USER_WIDTH-1:0] m_axis_tuser_int = axis_tuser_reg[LENGTH-1];
(* shreg_extract = "no" *)
reg [DATA_WIDTH-1:0] axis_tdata_reg = 0;
(* shreg_extract = "no" *)
reg [KEEP_WIDTH-1:0] axis_tkeep_reg = 0;
(* shreg_extract = "no" *)
reg axis_tvalid_reg = 0;
(* shreg_extract = "no" *)
reg axis_tready_reg = 0;
(* shreg_extract = "no" *)
reg axis_tlast_reg = 0;
(* shreg_extract = "no" *)
reg [ID_WIDTH-1:0] axis_tid_reg = 0;
(* shreg_extract = "no" *)
reg [DEST_WIDTH-1:0] axis_tdest_reg = 0;
(* shreg_extract = "no" *)
reg [USER_WIDTH-1:0] axis_tuser_reg = 0;
assign s_axis_tready = axis_tready_reg[0];
assign axis_tdata_pipe[n+1] = axis_tdata_reg;
assign axis_tkeep_pipe[n+1] = axis_tkeep_reg;
assign axis_tvalid_pipe[n+1] = axis_tvalid_reg;
assign axis_tlast_pipe[n+1] = axis_tlast_reg;
assign axis_tid_pipe[n+1] = axis_tid_reg;
assign axis_tdest_pipe[n+1] = axis_tdest_reg;
assign axis_tuser_pipe[n+1] = axis_tuser_reg;
integer i;
initial begin
for (i = 0; i < LENGTH; i = i + 1) begin
axis_tdata_reg[i] = {DATA_WIDTH{1'b0}};
axis_tkeep_reg[i] = {KEEP_WIDTH{1'b0}};
axis_tvalid_reg[i] = 1'b0;
axis_tready_reg[i] = 1'b0;
axis_tlast_reg[i] = 1'b0;
axis_tid_reg[i] = {ID_WIDTH{1'b0}};
axis_tdest_reg[i] = {DEST_WIDTH{1'b0}};
axis_tuser_reg[i] = {USER_WIDTH{1'b0}};
end
end
assign axis_tready_pipe[n] = axis_tready_reg;
always @(posedge clk) begin
axis_tdata_reg[0] <= s_axis_tdata;
axis_tkeep_reg[0] <= s_axis_tkeep;
axis_tvalid_reg[0] <= s_axis_tvalid && s_axis_tready;
axis_tlast_reg[0] <= s_axis_tlast;
axis_tid_reg[0] <= s_axis_tid;
axis_tdest_reg[0] <= s_axis_tdest;
axis_tuser_reg[0] <= s_axis_tuser;
axis_tdata_reg <= axis_tdata_pipe[n];
axis_tkeep_reg <= axis_tkeep_pipe[n];
axis_tvalid_reg <= axis_tvalid_pipe[n];
axis_tlast_reg <= axis_tlast_pipe[n];
axis_tid_reg <= axis_tid_pipe[n];
axis_tdest_reg <= axis_tdest_pipe[n];
axis_tuser_reg <= axis_tuser_pipe[n];
axis_tready_reg[LENGTH-1] <= m_axis_tready_int;
for (i = 0; i < LENGTH-1; i = i + 1) begin
axis_tdata_reg[i+1] <= axis_tdata_reg[i];
axis_tkeep_reg[i+1] <= axis_tkeep_reg[i];
axis_tvalid_reg[i+1] <= axis_tvalid_reg[i];
axis_tlast_reg[i+1] <= axis_tlast_reg[i];
axis_tid_reg[i+1] <= axis_tid_reg[i];
axis_tdest_reg[i+1] <= axis_tdest_reg[i];
axis_tuser_reg[i+1] <= axis_tuser_reg[i];
axis_tready_reg[i] <= axis_tready_reg[i+1];
end
axis_tready_reg <= axis_tready_pipe[n+1];
if (rst) begin
for (i = 0; i < LENGTH; i = i + 1) begin
axis_tvalid_reg[i] <= 1'b0;
axis_tready_reg[i] <= 1'b0;
end
axis_tvalid_reg <= 1'b0;
axis_tready_reg <= 1'b0;
end
end
end
if (LENGTH > 0) begin : fifo
assign axis_tdata_pipe[0] = s_axis_tdata;
assign axis_tkeep_pipe[0] = s_axis_tkeep;
assign axis_tvalid_pipe[0] = s_axis_tvalid & s_axis_tready;
assign axis_tlast_pipe[0] = s_axis_tlast;
assign axis_tid_pipe[0] = s_axis_tid;
assign axis_tdest_pipe[0] = s_axis_tdest;
assign axis_tuser_pipe[0] = s_axis_tuser;
assign s_axis_tready = axis_tready_pipe[0];
wire [DATA_WIDTH-1:0] m_axis_tdata_int = axis_tdata_pipe[LENGTH];
wire [KEEP_WIDTH-1:0] m_axis_tkeep_int = axis_tkeep_pipe[LENGTH];
wire m_axis_tvalid_int = axis_tvalid_pipe[LENGTH];
wire m_axis_tready_int;
wire m_axis_tlast_int = axis_tlast_pipe[LENGTH];
wire [ID_WIDTH-1:0] m_axis_tid_int = axis_tid_pipe[LENGTH];
wire [DEST_WIDTH-1:0] m_axis_tdest_int = axis_tdest_pipe[LENGTH];
wire [USER_WIDTH-1:0] m_axis_tuser_int = axis_tuser_pipe[LENGTH];
assign axis_tready_pipe[LENGTH] = m_axis_tready_int;
// output datapath logic
reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};

View File

@ -1,4 +1,4 @@
# Copyright (c) 2020 Alex Forencich
# Copyright (c) 2020-2023 Alex Forencich
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@ -36,7 +36,8 @@ proc constrain_axis_async_fifo_inst { inst } {
# pointer synchronization
set_max_delay -from [get_registers "$inst|rd_ptr_reg[*] $inst|rd_ptr_gray_reg[*]"] -to [get_registers "$inst|rd_ptr_gray_sync1_reg[*]"] 8.000
set_max_delay -from [get_registers "$inst|wr_ptr_reg[*] $inst|wr_ptr_gray_reg[*] $inst|wr_ptr_sync_gray_reg[*]"] -to [get_registers "$inst|wr_ptr_gray_sync1_reg[*]"] 8.000
set_max_delay -from [get_registers "$inst|wr_ptr_reg[*] $inst|wr_ptr_gray_reg[*]"] -to [get_registers "$inst|wr_ptr_gray_sync1_reg[*]"] 8.000
set_max_delay -from [get_registers "$inst|wr_ptr_sync_commit_reg[*]"] -to [get_registers "$inst|wr_ptr_commit_sync_reg[*]"] 8.000
# frame FIFO pointer update synchronization
set_max_delay -from [get_registers "$inst|wr_ptr_update_reg"] -to [get_registers "$inst|wr_ptr_update_sync1_reg"] 8.000

View File

@ -1,4 +1,4 @@
# Copyright (c) 2021 Alex Forencich
# Copyright (c) 2021-2023 Alex Forencich
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@ -37,8 +37,10 @@ proc constrain_axis_async_fifo_inst { inst } {
# pointer synchronization
set_data_delay -from [get_registers "$inst|rd_ptr_reg[*] $inst|rd_ptr_gray_reg[*]"] -to [get_registers "$inst|rd_ptr_gray_sync1_reg[*]"] -override -get_value_from_clock_period dst_clock_period -value_multiplier 0.8
set_max_skew -from [get_keepers "$inst|rd_ptr_reg[*] $inst|rd_ptr_gray_reg[*]"] -to [get_keepers "$inst|rd_ptr_gray_sync1_reg[*]"] -get_skew_value_from_clock_period min_clock_period -skew_value_multiplier 0.8
set_data_delay -from [get_registers "$inst|wr_ptr_reg[*] $inst|wr_ptr_gray_reg[*] $inst|wr_ptr_sync_gray_reg[*]"] -to [get_registers "$inst|wr_ptr_gray_sync1_reg[*]"] -override -get_value_from_clock_period dst_clock_period -value_multiplier 0.8
set_max_skew -from [get_keepers "$inst|wr_ptr_reg[*] $inst|wr_ptr_gray_reg[*] $inst|wr_ptr_sync_gray_reg[*]"] -to [get_keepers "$inst|wr_ptr_gray_sync1_reg[*]"] -get_skew_value_from_clock_period min_clock_period -skew_value_multiplier 0.8
set_data_delay -from [get_registers "$inst|wr_ptr_reg[*] $inst|wr_ptr_gray_reg[*]"] -to [get_registers "$inst|wr_ptr_gray_sync1_reg[*]"] -override -get_value_from_clock_period dst_clock_period -value_multiplier 0.8
set_max_skew -from [get_keepers "$inst|wr_ptr_reg[*] $inst|wr_ptr_gray_reg[*]"] -to [get_keepers "$inst|wr_ptr_gray_sync1_reg[*]"] -get_skew_value_from_clock_period min_clock_period -skew_value_multiplier 0.8
set_data_delay -from [get_registers "$inst|wr_ptr_sync_commit_reg[*]"] -to [get_registers "$inst|wr_ptr_commit_sync_reg[*]"] -override -get_value_from_clock_period dst_clock_period -value_multiplier 0.8
set_max_skew -from [get_keepers "$inst|wr_ptr_sync_commit_reg[*]"] -to [get_keepers "$inst|wr_ptr_commit_sync_reg[*]"] -get_skew_value_from_clock_period min_clock_period -skew_value_multiplier 0.8
# frame FIFO pointer update synchronization
set_data_delay -from [get_registers "$inst|wr_ptr_update_reg"] -to [get_registers "$inst|wr_ptr_update_sync1_reg"] -override -get_value_from_clock_period dst_clock_period -value_multiplier 0.8

View File

@ -1,4 +1,4 @@
# Copyright (c) 2019 Alex Forencich
# Copyright (c) 2019-2023 Alex Forencich
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@ -78,8 +78,17 @@ foreach fifo_inst [get_cells -hier -filter {(ORIG_REF_NAME == axis_async_fifo ||
if {[llength $sync_ffs]} {
set_property ASYNC_REG TRUE $sync_ffs
set_max_delay -from [get_cells -quiet "$fifo_inst/wr_ptr_reg_reg[*] $fifo_inst/wr_ptr_gray_reg_reg[*] $fifo_inst/wr_ptr_sync_gray_reg_reg[*]"] -to [get_cells "$fifo_inst/wr_ptr_gray_sync1_reg_reg[*]"] -datapath_only $write_clk_period
set_bus_skew -from [get_cells -quiet "$fifo_inst/wr_ptr_reg_reg[*] $fifo_inst/wr_ptr_gray_reg_reg[*] $fifo_inst/wr_ptr_sync_gray_reg_reg[*]"] -to [get_cells "$fifo_inst/wr_ptr_gray_sync1_reg_reg[*]"] $read_clk_period
set_max_delay -from [get_cells -quiet "$fifo_inst/wr_ptr_reg_reg[*] $fifo_inst/wr_ptr_gray_reg_reg[*]"] -to [get_cells "$fifo_inst/wr_ptr_gray_sync1_reg_reg[*]"] -datapath_only $write_clk_period
set_bus_skew -from [get_cells -quiet "$fifo_inst/wr_ptr_reg_reg[*] $fifo_inst/wr_ptr_gray_reg_reg[*]"] -to [get_cells "$fifo_inst/wr_ptr_gray_sync1_reg_reg[*]"] $read_clk_period
}
set sync_ffs [get_cells -quiet -hier -regexp ".*/wr_ptr_commit_sync_reg_reg\\\[\\d+\\\]" -filter "PARENT == $fifo_inst"]
if {[llength $sync_ffs]} {
set_property ASYNC_REG TRUE $sync_ffs
set_max_delay -from [get_cells -quiet "$fifo_inst/wr_ptr_sync_commit_reg_reg[*]"] -to [get_cells "$fifo_inst/wr_ptr_commit_sync_reg_reg[*]"] -datapath_only $write_clk_period
set_bus_skew -from [get_cells -quiet "$fifo_inst/wr_ptr_sync_commit_reg_reg[*]"] -to [get_cells "$fifo_inst/wr_ptr_commit_sync_reg_reg[*]"] $read_clk_period
}
# output register (needed for distributed RAM sync write/async read)

View File

@ -41,7 +41,6 @@ export PARAM_S_KEEP_WIDTH := $(shell expr \( $(PARAM_S_DATA_WIDTH) + 7 \) / 8 )
export PARAM_M_DATA_WIDTH := 8
export PARAM_M_KEEP_ENABLE := $(shell expr $(PARAM_M_DATA_WIDTH) \> 8 )
export PARAM_M_KEEP_WIDTH := $(shell expr \( $(PARAM_M_DATA_WIDTH) + 7 \) / 8 )
export PARAM_LAST_ENABLE := 1
export PARAM_ID_ENABLE := 1
export PARAM_ID_WIDTH := 8
export PARAM_DEST_ENABLE := 1

View File

@ -41,7 +41,6 @@ export PARAM_S_KEEP_WIDTH := $(shell expr \( $(PARAM_S_DATA_WIDTH) + 7 \) / 8 )
export PARAM_M_DATA_WIDTH := 8
export PARAM_M_KEEP_ENABLE := $(shell expr $(PARAM_M_DATA_WIDTH) \> 8 )
export PARAM_M_KEEP_WIDTH := $(shell expr \( $(PARAM_M_DATA_WIDTH) + 7 \) / 8 )
export PARAM_LAST_ENABLE := 1
export PARAM_ID_ENABLE := 1
export PARAM_ID_WIDTH := 8
export PARAM_DEST_ENABLE := 1