//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
// Srdy/Drdy FIFO Tail "B"
|
// Srdy/Drdy FIFO Tail "B"
|
//
|
//
|
// Building block for FIFOs. The "B" (big) FIFO is design for larger FIFOs
|
// Building block for FIFOs. The "B" (big) FIFO is design for larger FIFOs
|
// based around memories, with sizes that may not be a power of 2.
|
// based around memories, with sizes that may not be a power of 2.
|
//
|
//
|
// The bound inputs allow multiple FIFO controllers to share a single
|
// The bound inputs allow multiple FIFO controllers to share a single
|
// memory. The enable input is for arbitration between multiple FIFO
|
// memory. The enable input is for arbitration between multiple FIFO
|
// controllers, or between the fifo head and tail controllers on a
|
// controllers, or between the fifo head and tail controllers on a
|
// single port memory.
|
// single port memory.
|
//
|
//
|
// The commit parameter enables read/commit behavior. This creates
|
// The commit parameter enables read/commit behavior. This creates
|
// two read pointers, one which is used for reading from memory and
|
// two read pointers, one which is used for reading from memory and
|
// a commit pointer which is sent to the head block. The abort behavior
|
// a commit pointer which is sent to the head block. The abort behavior
|
// has a 3-cycle performance penalty due to pipeline flush.
|
// has a 3-cycle performance penalty due to pipeline flush.
|
//
|
//
|
// The FIFO tail assumes a memory with one-cycle read latency, and
|
// The FIFO tail assumes a memory with one-cycle read latency, and
|
// has output buffering to compensate for this.
|
// has output buffering to compensate for this.
|
//
|
//
|
// Naming convention: c = consumer, p = producer, i = internal interface
|
// Naming convention: c = consumer, p = producer, i = internal interface
|
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
// Author: Guy Hutchison
|
// Author: Guy Hutchison
|
//
|
//
|
// This block is uncopyrighted and released into the public domain.
|
// This block is uncopyrighted and released into the public domain.
|
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
|
|
// Clocking statement for synchronous blocks. Default is for
|
// Clocking statement for synchronous blocks. Default is for
|
// posedge clocking and positive async reset
|
// posedge clocking and positive async reset
|
`ifndef SDLIB_CLOCKING
|
`ifndef SDLIB_CLOCKING
|
`define SDLIB_CLOCKING posedge clk or posedge reset
|
`define SDLIB_CLOCKING posedge clk or posedge reset
|
`endif
|
`endif
|
|
|
// delay unit for nonblocking assigns, default is to #1
|
// delay unit for nonblocking assigns, default is to #1
|
`ifndef SDLIB_DELAY
|
`ifndef SDLIB_DELAY
|
`define SDLIB_DELAY #1
|
`define SDLIB_DELAY #1
|
`endif
|
`endif
|
|
|
|
|
module sd_fifo_tail_b
|
module sd_fifo_tail_b
|
#(parameter width=8,
|
#(parameter width=8,
|
parameter depth=16,
|
parameter depth=16,
|
parameter commit=0,
|
parameter commit=0,
|
parameter asz=$clog2(depth))
|
parameter asz=$clog2(depth))
|
(
|
(
|
input clk,
|
input clk,
|
input reset,
|
input reset,
|
input enable,
|
input enable,
|
|
|
input [asz-1:0] bound_low,
|
input [asz-1:0] bound_low,
|
input [asz-1:0] bound_high,
|
input [asz-1:0] bound_high,
|
|
|
output reg [asz-1:0] cur_rdptr,
|
output reg [asz-1:0] cur_rdptr,
|
output reg [asz-1:0] com_rdptr,
|
output reg [asz-1:0] com_rdptr,
|
input [asz-1:0] wrptr,
|
input [asz-1:0] wrptr,
|
output reg mem_re,
|
output reg mem_re,
|
|
input mem_we,
|
|
|
output reg [asz:0] usage,
|
output reg [asz:0] usage,
|
|
|
output p_srdy,
|
output p_srdy,
|
input p_drdy,
|
input p_drdy,
|
input p_commit,
|
input p_commit,
|
input p_abort,
|
input p_abort,
|
input [width-1:0] mem_rd_data,
|
input [width-1:0] mem_rd_data,
|
output [width-1:0] p_data
|
output [width-1:0] p_data
|
);
|
);
|
|
|
reg [asz-1:0] nxt_cur_rdptr;
|
reg [asz-1:0] nxt_cur_rdptr;
|
reg [asz-1:0] cur_rdptr_p1;
|
reg [asz-1:0] cur_rdptr_p1;
|
reg empty, full;
|
reg empty, full;
|
|
|
reg nxt_irdy;
|
reg nxt_irdy;
|
|
|
reg [width-1:0] hold_a, hold_b;
|
reg [width-1:0] hold_a, hold_b;
|
reg valid_a, valid_b;
|
reg valid_a, valid_b;
|
reg prev_re;
|
reg prev_re;
|
reg [asz:0] tmp_usage;
|
reg [asz:0] tmp_usage;
|
reg [asz:0] fifo_size;
|
reg [asz:0] fifo_size;
|
wire rbuf1_drdy;
|
wire rbuf1_drdy;
|
wire ip_srdy, ip_drdy;
|
wire ip_srdy, ip_drdy;
|
wire [width-1:0] ip_data;
|
wire [width-1:0] ip_data;
|
|
|
// Stage 1 -- Read pipeline
|
// Stage 1 -- Read pipeline
|
// issue a read if:
|
// issue a read if:
|
// 1) we are enabled
|
// 1) we are enabled
|
// 2) valid_a is 0, OR
|
// 2) valid_a is 0, OR
|
// 3) valid_b is 0, OR
|
// 3) valid_b is 0, OR
|
// 4) valid_a && valid_b && trdy
|
// 4) valid_a && valid_b && trdy
|
always @*
|
always @*
|
begin
|
begin
|
|
|
if (cur_rdptr[asz-1:0] == (bound_high))
|
if (cur_rdptr[asz-1:0] == (bound_high))
|
begin
|
begin
|
cur_rdptr_p1[asz-1:0] = bound_low;
|
cur_rdptr_p1[asz-1:0] = bound_low;
|
end
|
end
|
else
|
else
|
cur_rdptr_p1 = cur_rdptr + 1;
|
cur_rdptr_p1 = cur_rdptr + 1;
|
|
|
empty = (wrptr == cur_rdptr);
|
empty = (wrptr == cur_rdptr);
|
|
|
if (commit && p_abort)
|
if (commit && p_abort)
|
begin
|
begin
|
nxt_cur_rdptr = com_rdptr;
|
nxt_cur_rdptr = com_rdptr;
|
mem_re = 0;
|
mem_re = 0;
|
end
|
end
|
// else if (enable & !empty & (!valid_a | (!prev_re & !valid_b) |
|
// else if (enable & !empty & (!valid_a | (!prev_re & !valid_b) |
|
// (valid_a & valid_b & p_drdy)))
|
// (valid_a & valid_b & p_drdy)))
|
else if (enable & !empty & ip_drdy)
|
else if (enable & !empty & ip_drdy)
|
begin
|
begin
|
nxt_cur_rdptr = cur_rdptr_p1;
|
nxt_cur_rdptr = cur_rdptr_p1;
|
mem_re = 1;
|
mem_re = 1;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
nxt_cur_rdptr = cur_rdptr;
|
nxt_cur_rdptr = cur_rdptr;
|
mem_re = 0;
|
mem_re = 0;
|
end // else: !if(enable & !empty & (!valid_a | !valid_b |...
|
end // else: !if(enable & !empty & (!valid_a | !valid_b |...
|
|
|
fifo_size = (bound_high - bound_low + 1);
|
fifo_size = (bound_high - bound_low + 1);
|
tmp_usage = wrptr[asz-1:0] - cur_rdptr[asz-1:0];
|
tmp_usage = wrptr[asz-1:0] - cur_rdptr[asz-1:0];
|
if (~tmp_usage[asz])
|
if (~tmp_usage[asz])
|
usage = tmp_usage[asz-1:0];
|
usage = tmp_usage[asz-1:0];
|
else
|
else
|
usage = fifo_size - (cur_rdptr[asz-1:0] - wrptr[asz-1:0]);
|
usage = fifo_size - (cur_rdptr[asz-1:0] - wrptr[asz-1:0]);
|
end
|
end // always @ *
|
|
|
|
/* -----\/----- EXCLUDED -----\/-----
|
|
// alternate usage calc
|
|
reg [asz-1:0] prev_wr;
|
|
reg [asz:0] usage2, nxt_usage2;
|
|
wire lcl_wr_en;
|
|
//assign lcl_wr_en = (prev_wr0 != wrptr[0]);
|
|
|
|
always @(posedge clk)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
/-*AUTORESET*-/
|
|
// Beginning of autoreset for uninitialized flops
|
|
usage2 <= {(1+(asz)){1'b0}};
|
|
// End of automatics
|
|
end
|
|
else
|
|
begin
|
|
usage2 <= #1 nxt_usage2;
|
|
end
|
|
end
|
|
|
|
always @*
|
|
begin
|
|
if (mem_re & !mem_we)
|
|
nxt_usage2 = usage2 - 1;
|
|
else if (!mem_re & mem_we)
|
|
nxt_usage2 = usage2 + 1;
|
|
else
|
|
nxt_usage2 = usage2;
|
|
end
|
|
-----/\----- EXCLUDED -----/\----- */
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
begin
|
begin
|
if (reset)
|
if (reset)
|
cur_rdptr <= `SDLIB_DELAY bound_low;
|
cur_rdptr <= `SDLIB_DELAY bound_low;
|
else
|
else
|
cur_rdptr <= `SDLIB_DELAY nxt_cur_rdptr;
|
cur_rdptr <= `SDLIB_DELAY nxt_cur_rdptr;
|
end
|
end
|
|
|
reg [asz-1:0] rdaddr_s0, rdaddr_a, rdaddr_b;
|
reg [asz-1:0] rdaddr_s0, rdaddr_a, rdaddr_b;
|
reg [asz-1:0] nxt_com_rdptr;
|
reg [asz-1:0] nxt_com_rdptr;
|
generate
|
generate
|
if (commit == 1)
|
if (commit == 1)
|
begin : gen_s0
|
begin : gen_s0
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
begin
|
begin
|
if (reset)
|
if (reset)
|
com_rdptr <= `SDLIB_DELAY bound_low;
|
com_rdptr <= `SDLIB_DELAY bound_low;
|
else
|
else
|
com_rdptr <= `SDLIB_DELAY nxt_com_rdptr;
|
com_rdptr <= `SDLIB_DELAY nxt_com_rdptr;
|
|
|
if (mem_re)
|
if (mem_re)
|
rdaddr_s0 <= `SDLIB_DELAY cur_rdptr;
|
rdaddr_s0 <= `SDLIB_DELAY cur_rdptr;
|
end
|
end
|
end
|
end
|
else
|
else
|
begin : gen_ns0
|
begin : gen_ns0
|
always @*
|
always @*
|
com_rdptr = cur_rdptr;
|
com_rdptr = cur_rdptr;
|
end
|
end
|
endgenerate
|
endgenerate
|
|
|
// Stage 2 -- read buffering
|
// Stage 2 -- read buffering
|
always @(`SDLIB_CLOCKING)
|
always @(`SDLIB_CLOCKING)
|
begin
|
begin
|
if (reset)
|
if (reset)
|
begin
|
begin
|
prev_re <= `SDLIB_DELAY 0;
|
prev_re <= `SDLIB_DELAY 0;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
if (commit && p_abort)
|
if (commit && p_abort)
|
prev_re <= `SDLIB_DELAY 0;
|
prev_re <= `SDLIB_DELAY 0;
|
else
|
else
|
prev_re <= `SDLIB_DELAY mem_re;
|
prev_re <= `SDLIB_DELAY mem_re;
|
end // else: !if(reset)
|
end // else: !if(reset)
|
end // always @ (`SDLIB_CLOCKING)
|
end // always @ (`SDLIB_CLOCKING)
|
|
|
generate
|
generate
|
if (commit == 1)
|
if (commit == 1)
|
begin : gen_s2
|
begin : gen_s2
|
wire [asz-1:0] ip_rdaddr, p_rdaddr;
|
wire [asz-1:0] ip_rdaddr, p_rdaddr;
|
|
|
sd_input #(asz+width) rbuf1
|
sd_input #(asz+width) rbuf1
|
(.clk (clk), .reset (p_abort | reset),
|
(.clk (clk), .reset (p_abort | reset),
|
.c_srdy (prev_re),
|
.c_srdy (prev_re),
|
.c_drdy (rbuf1_drdy),
|
.c_drdy (rbuf1_drdy),
|
.c_data ({rdaddr_s0,mem_rd_data}),
|
.c_data ({rdaddr_s0,mem_rd_data}),
|
.ip_srdy (ip_srdy), .ip_drdy (ip_drdy),
|
.ip_srdy (ip_srdy), .ip_drdy (ip_drdy),
|
.ip_data ({ip_rdaddr,ip_data}));
|
.ip_data ({ip_rdaddr,ip_data}));
|
|
|
sd_output #(asz+width) rbuf2
|
sd_output #(asz+width) rbuf2
|
(.clk (clk), .reset (p_abort | reset),
|
(.clk (clk), .reset (p_abort | reset),
|
.ic_srdy (ip_srdy),
|
.ic_srdy (ip_srdy),
|
.ic_drdy (ip_drdy),
|
.ic_drdy (ip_drdy),
|
.ic_data ({ip_rdaddr,ip_data}),
|
.ic_data ({ip_rdaddr,ip_data}),
|
.p_srdy (p_srdy), .p_drdy (p_drdy),
|
.p_srdy (p_srdy), .p_drdy (p_drdy),
|
.p_data ({p_rdaddr,p_data}));
|
.p_data ({p_rdaddr,p_data}));
|
|
|
always @*
|
always @*
|
begin
|
begin
|
if (p_commit)
|
if (p_commit)
|
nxt_com_rdptr = p_rdaddr;
|
nxt_com_rdptr = p_rdaddr;
|
else
|
else
|
nxt_com_rdptr = com_rdptr;
|
nxt_com_rdptr = com_rdptr;
|
end
|
end
|
end // if (commit == 1)
|
end // if (commit == 1)
|
else
|
else
|
begin : gen_ns2
|
begin : gen_ns2
|
sd_input #(width) rbuf1
|
sd_input #(width) rbuf1
|
(.clk (clk), .reset (p_abort | reset),
|
(.clk (clk), .reset (p_abort | reset),
|
.c_srdy (prev_re),
|
.c_srdy (prev_re),
|
.c_drdy (rbuf1_drdy),
|
.c_drdy (rbuf1_drdy),
|
.c_data (mem_rd_data),
|
.c_data (mem_rd_data),
|
.ip_srdy (ip_srdy), .ip_drdy (ip_drdy),
|
.ip_srdy (ip_srdy), .ip_drdy (ip_drdy),
|
.ip_data (ip_data));
|
.ip_data (ip_data));
|
|
|
sd_output #(width) rbuf2
|
sd_output #(width) rbuf2
|
(.clk (clk), .reset (p_abort | reset),
|
(.clk (clk), .reset (p_abort | reset),
|
.ic_srdy (ip_srdy),
|
.ic_srdy (ip_srdy),
|
.ic_drdy (ip_drdy),
|
.ic_drdy (ip_drdy),
|
.ic_data (ip_data),
|
.ic_data (ip_data),
|
.p_srdy (p_srdy), .p_drdy (p_drdy),
|
.p_srdy (p_srdy), .p_drdy (p_drdy),
|
.p_data (p_data));
|
.p_data (p_data));
|
end // else: !if(commit == 1)
|
end // else: !if(commit == 1)
|
endgenerate
|
endgenerate
|
|
|
endmodule // it_fifo
|
endmodule // it_fifo
|
|
|