1
0
mirror of https://github.com/pConst/basic_verilog.git synced 2025-01-28 07:02:55 +08:00
Konstantin Pavlov (pt) 40533743d7 Added altera cookbook
2015-12-15 22:44:58 +03:00

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