mirror of
https://github.com/pConst/basic_verilog.git
synced 2025-01-28 07:02:55 +08:00
235 lines
6.6 KiB
Verilog
235 lines
6.6 KiB
Verilog
// Copyright 2008 Altera Corporation. All rights reserved.
|
|
// Altera products are protected under numerous U.S. and foreign patents,
|
|
// maskwork rights, copyrights and other intellectual property laws.
|
|
//
|
|
// This reference design file, and your use thereof, is subject to and governed
|
|
// by the terms and conditions of the applicable Altera Reference Design
|
|
// License Agreement (either as signed by you or found at www.altera.com). By
|
|
// using this reference design file, you indicate your acceptance of such terms
|
|
// and conditions between you and Altera Corporation. In the event that you do
|
|
// not agree with such terms and conditions, you may not use the reference
|
|
// design file and please promptly destroy any copies you have made.
|
|
//
|
|
// This reference design file is being provided on an "as-is" basis and as an
|
|
// accommodation and therefore all warranties, representations or guarantees of
|
|
// any kind (whether express, implied or statutory) including, without
|
|
// limitation, warranties of merchantability, non-infringement, or fitness for
|
|
// a particular purpose, are specifically disclaimed. By making this reference
|
|
// design file available, Altera expressly does not recommend, suggest or
|
|
// require that this reference design file be used in combination with any
|
|
// other product not provided by Altera.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// baeckler - 11-12-2008
|
|
// 8 word FIFO
|
|
module tx_buffer_fifo_8word #(
|
|
parameter WIDTH = 20*20
|
|
)
|
|
(
|
|
input clk, arst,
|
|
|
|
input [WIDTH-1:0] din,
|
|
input din_valid,
|
|
output reg din_ready,
|
|
|
|
output [WIDTH-1:0] dout,
|
|
input dout_ready,
|
|
|
|
output reg hungry,
|
|
output reg underflow
|
|
);
|
|
|
|
reg [WIDTH-1:0] store_a, store_b, store_c, store_d,
|
|
store_e, store_f, store_g, store_h;
|
|
|
|
/* synthesis translate off */
|
|
initial begin
|
|
store_a = 0;
|
|
store_b = 0;
|
|
store_c = 0;
|
|
store_d = 0;
|
|
store_e = 0;
|
|
store_f = 0;
|
|
store_g = 0;
|
|
store_h = 0;
|
|
end
|
|
/* synthesis translate on */
|
|
|
|
wire [WIDTH-1:0] store_aw, store_bw, store_cw, store_dw,
|
|
store_ew, store_fw, store_gw, store_hw /* synthesis keep */;
|
|
|
|
reg [3:0] wr_ptr, rd_ptr /* synthesis preserve */
|
|
/* synthesis ALTERA_ATTRIBUTE = "ALLOW_SYNCH_CTRL_USAGE=OFF ; AUTO_CLOCK_ENABLE_RECOGNITION = OFF" */;
|
|
|
|
//////////////////////////////////////////
|
|
// when DIN is valid accept it into appro
|
|
// storage slot
|
|
//////////////////////////////////////////
|
|
wire write_now = din_valid & din_ready;
|
|
|
|
reg [7:0] wr_ptr_dec /* synthesis keep */;
|
|
always @(*) begin
|
|
wr_ptr_dec = 0;
|
|
wr_ptr_dec[wr_ptr[2:0]] = write_now;
|
|
end
|
|
|
|
assign store_aw = wr_ptr_dec[0] ? din : store_a;
|
|
assign store_bw = wr_ptr_dec[1] ? din : store_b;
|
|
assign store_cw = wr_ptr_dec[2] ? din : store_c;
|
|
assign store_dw = wr_ptr_dec[3] ? din : store_d;
|
|
assign store_ew = wr_ptr_dec[4] ? din : store_e;
|
|
assign store_fw = wr_ptr_dec[5] ? din : store_f;
|
|
assign store_gw = wr_ptr_dec[6] ? din : store_g;
|
|
assign store_hw = wr_ptr_dec[7] ? din : store_h;
|
|
|
|
always @(posedge clk or posedge arst) begin
|
|
if (arst) begin
|
|
wr_ptr <= 4'b0;
|
|
store_a <= 0;
|
|
store_b <= 0;
|
|
store_c <= 0;
|
|
store_d <= 0;
|
|
store_e <= 0;
|
|
store_f <= 0;
|
|
store_g <= 0;
|
|
store_h <= 0;
|
|
end
|
|
else begin
|
|
if (write_now) begin
|
|
|
|
// make it clear that these are not intended to be a carry chain
|
|
case (wr_ptr)
|
|
4'b0000 : wr_ptr <= 4'b0001;
|
|
4'b0001 : wr_ptr <= 4'b0010;
|
|
4'b0010 : wr_ptr <= 4'b0011;
|
|
4'b0011 : wr_ptr <= 4'b0100;
|
|
4'b0100 : wr_ptr <= 4'b0101;
|
|
4'b0101 : wr_ptr <= 4'b0110;
|
|
4'b0110 : wr_ptr <= 4'b0111;
|
|
4'b0111 : wr_ptr <= 4'b1000;
|
|
4'b1000 : wr_ptr <= 4'b1001;
|
|
4'b1001 : wr_ptr <= 4'b1010;
|
|
4'b1010 : wr_ptr <= 4'b1011;
|
|
4'b1011 : wr_ptr <= 4'b1100;
|
|
4'b1100 : wr_ptr <= 4'b1101;
|
|
4'b1101 : wr_ptr <= 4'b1110;
|
|
4'b1110 : wr_ptr <= 4'b1111;
|
|
4'b1111 : wr_ptr <= 4'b0000;
|
|
endcase
|
|
end
|
|
|
|
store_a <= store_aw;
|
|
store_b <= store_bw;
|
|
store_c <= store_cw;
|
|
store_d <= store_dw;
|
|
store_e <= store_ew;
|
|
store_f <= store_fw;
|
|
store_g <= store_gw;
|
|
store_h <= store_hw;
|
|
|
|
end
|
|
end
|
|
|
|
//////////////////////////////////////////
|
|
// Read ptr and data out...
|
|
//////////////////////////////////////////
|
|
|
|
reg [WIDTH-1:0] rdmux /* synthesis preserve */
|
|
/* synthesis ALTERA_ATTRIBUTE = "ALLOW_SYNCH_CTRL_USAGE=OFF ; AUTO_CLOCK_ENABLE_RECOGNITION = OFF" */;
|
|
|
|
reg read_now;
|
|
reg last_read_now /* synthesis preserve */;
|
|
reg [WIDTH-1:0] last_dout /* synthesis preserve */ ;
|
|
|
|
always @(posedge clk or posedge arst) begin
|
|
if (arst) begin
|
|
rdmux <= 0;
|
|
last_read_now <= 0;
|
|
last_dout <= 0;
|
|
end
|
|
else begin
|
|
case (rd_ptr[2:0])
|
|
3'b000 : rdmux <= store_a;
|
|
3'b001 : rdmux <= store_b;
|
|
3'b010 : rdmux <= store_c;
|
|
3'b011 : rdmux <= store_d;
|
|
3'b100 : rdmux <= store_e;
|
|
3'b101 : rdmux <= store_f;
|
|
3'b110 : rdmux <= store_g;
|
|
3'b111 : rdmux <= store_h;
|
|
endcase
|
|
last_read_now <= read_now;
|
|
last_dout <= dout;
|
|
end
|
|
end
|
|
|
|
assign dout = last_read_now ? rdmux : last_dout;
|
|
|
|
always @(posedge clk or posedge arst) begin
|
|
if (arst) begin
|
|
rd_ptr <= 4'b0000;
|
|
end
|
|
else begin
|
|
if (read_now) begin
|
|
|
|
case (rd_ptr)
|
|
4'b0000 : rd_ptr <= 4'b0001;
|
|
4'b0001 : rd_ptr <= 4'b0010;
|
|
4'b0010 : rd_ptr <= 4'b0011;
|
|
4'b0011 : rd_ptr <= 4'b0100;
|
|
4'b0100 : rd_ptr <= 4'b0101;
|
|
4'b0101 : rd_ptr <= 4'b0110;
|
|
4'b0110 : rd_ptr <= 4'b0111;
|
|
4'b0111 : rd_ptr <= 4'b1000;
|
|
4'b1000 : rd_ptr <= 4'b1001;
|
|
4'b1001 : rd_ptr <= 4'b1010;
|
|
4'b1010 : rd_ptr <= 4'b1011;
|
|
4'b1011 : rd_ptr <= 4'b1100;
|
|
4'b1100 : rd_ptr <= 4'b1101;
|
|
4'b1101 : rd_ptr <= 4'b1110;
|
|
4'b1110 : rd_ptr <= 4'b1111;
|
|
4'b1111 : rd_ptr <= 4'b0000;
|
|
endcase
|
|
end
|
|
end
|
|
end
|
|
|
|
//////////////////////////////////////////
|
|
// Decide when to read
|
|
//////////////////////////////////////////
|
|
assign full = (wr_ptr[3] ^ rd_ptr[3]) && (wr_ptr[2:0] == rd_ptr[2:0]);
|
|
wire empty = (wr_ptr[3] ~^ rd_ptr[3]) && (wr_ptr[2:0] == rd_ptr[2:0]);
|
|
|
|
always @(*) begin
|
|
read_now = 1'b0;
|
|
|
|
// read if caller wants a read and data is available
|
|
if (dout_ready & !empty) read_now = 1'b1;
|
|
|
|
// read when you are overflowing to stay semi consistent
|
|
if (write_now & full) read_now = 1'b1;
|
|
end
|
|
|
|
//////////////////////////////////////////
|
|
// Backpressure / error detect
|
|
//////////////////////////////////////////
|
|
wire [3:0] words_used = wr_ptr-rd_ptr;
|
|
wire almost_full = words_used[3] | (&words_used[2:0]);
|
|
|
|
always @(posedge clk or posedge arst) begin
|
|
if (arst) begin
|
|
underflow <= 1'b0;
|
|
hungry <= 1'b1;
|
|
din_ready <= 1'b1;
|
|
end
|
|
else begin
|
|
// oops. No data to back read request means underflow
|
|
underflow <= 1'b0;
|
|
if (dout_ready & empty) underflow <= 1'b1;
|
|
|
|
hungry <= ~|words_used[3:2];
|
|
din_ready <= ~almost_full;
|
|
end
|
|
end
|
|
|
|
endmodule |