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

278 lines
7.1 KiB
Verilog

// Copyright 2007 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 - 04-15-2007
module fifo (
aclr,
rd_dat,
rd_clk,
rd_req,
rd_empty,
rd_used,
wr_dat,
wr_clk,
wr_req,
wr_full,
wr_used
);
parameter DAT_WIDTH = 8;
parameter ADDR_WIDTH = 8; // ram address width, internal width is 1 bit more
parameter SIMULATION = 1'b0;
input aclr;
output [DAT_WIDTH-1:0] rd_dat;
input rd_clk, rd_req;
output rd_empty;
output [ADDR_WIDTH:0] rd_used;
input [DAT_WIDTH-1:0] wr_dat;
input wr_clk,wr_req;
output wr_full;
output [ADDR_WIDTH:0] wr_used;
function [ADDR_WIDTH:0] gray_to_bin;
input [ADDR_WIDTH:0] gray;
integer i;
begin
gray_to_bin[ADDR_WIDTH] = gray[ADDR_WIDTH];
for (i=ADDR_WIDTH-1; i>=0; i=i-1)
begin: gry_to_bin
gray_to_bin[i] = gray_to_bin[i+1] ^ gray[i];
end
end
endfunction
reg [ADDR_WIDTH:0] rd_ptr, gray_rd_ptr, wr_side_gray_rd_ptr, wr_side_rd_ptr;
reg [ADDR_WIDTH:0] wr_ptr, gray_wr_ptr, rd_side_gray_wr_ptr, rd_side_wr_ptr;
reg rd_sclr,wr_sclr;
wire rd_ok, wr_ok;
// read address pointer - bin and gray
always @(posedge rd_clk) begin
if (rd_sclr) begin
rd_ptr <= 0;
gray_rd_ptr <= 0;
end
else begin
gray_rd_ptr <= rd_ptr ^ (rd_ptr >> 1'b1);
if (rd_req & rd_ok) rd_ptr <= rd_ptr + 1'b1;
end
end
// write address pointer - bin and gray
always @(posedge wr_clk) begin
if (wr_sclr) begin
wr_ptr <= 0;
gray_wr_ptr <= 0;
end
else begin
gray_wr_ptr <= wr_ptr ^ (wr_ptr >> 1'b1);
if (wr_req & wr_ok) wr_ptr <= wr_ptr + 1'b1;
end
end
// read pointer crossing to write side
always @(posedge wr_clk) begin
if (wr_sclr) begin
wr_side_gray_rd_ptr <= 0;
wr_side_rd_ptr <= 0;
end
else begin
wr_side_gray_rd_ptr <= gray_rd_ptr;
wr_side_rd_ptr <= gray_to_bin (wr_side_gray_rd_ptr);
end
end
// write pointer crossing to read side
always @(posedge rd_clk) begin
if (rd_sclr) begin
rd_side_gray_wr_ptr <= 0;
rd_side_wr_ptr <= 0;
end
else begin
rd_side_gray_wr_ptr <= gray_wr_ptr;
rd_side_wr_ptr <= gray_to_bin (rd_side_gray_wr_ptr);
end
end
// Full / Empty / Overflow controls
// note used words can be 1 bit wider than address
reg [ADDR_WIDTH:0] rd_used, wr_used;
assign rd_ok = rd_side_wr_ptr != rd_ptr;
always @(posedge rd_clk) begin
if (rd_sclr) begin
rd_used <= 0;
end
else begin
rd_used <= rd_side_wr_ptr - rd_ptr;
end
end
assign wr_ok = ((wr_side_rd_ptr[ADDR_WIDTH-1:0] != wr_ptr[ADDR_WIDTH-1:0]) ||
(wr_side_rd_ptr[ADDR_WIDTH] == wr_ptr[ADDR_WIDTH]))
& !wr_sclr;
always @(posedge wr_clk) begin
if (wr_sclr) begin
wr_used <= 0;
end
else begin
wr_used <= wr_ptr - wr_side_rd_ptr;
end
end
assign wr_full = !wr_ok;
assign rd_empty = !rd_ok;
// reset sync
reg [3:0] wr_aclr, rd_aclr;
always @(posedge wr_clk) begin
wr_aclr <= (wr_aclr << 1'b1) | aclr;
wr_sclr <= |wr_aclr;
end
always @(posedge rd_clk) begin
rd_aclr <= (rd_aclr << 1'b1) | aclr;
rd_sclr <= |rd_aclr;
end
// RAM storage
wire wr_ena = 1'b1;
wire rd_ena = (rd_req & rd_ok) | rd_sclr;
generate
if (!SIMULATION) begin
wire [DAT_WIDTH-1:0] unreg_rd_dat;
altsyncram altsyncram_component (
.wren_a (wr_req & wr_ok),
.clock0 (wr_clk),
.clock1 (rd_clk),
.address_a (wr_ptr[ADDR_WIDTH-1:0]),
.address_b (rd_ptr[ADDR_WIDTH-1:0] + (rd_sclr ? 1'b0 : 1'b1)),
.data_a (wr_dat),
.q_b (unreg_rd_dat),
.aclr0 (1'b0),
.aclr1 (1'b0),
.addressstall_a (1'b0),
.addressstall_b (!rd_ena),
.byteena_a (1'b1),
.byteena_b (1'b1),
.clocken0 (wr_ena),
.clocken1 (1'b1),
.clocken2 (1'b1),
.clocken3 (1'b1),
.data_b ({DAT_WIDTH{1'b1}}),
.eccstatus (),
.q_a (),
.rden_a (1'b1),
.rden_b (1'b1),
.wren_b (1'b0));
defparam
altsyncram_component.address_reg_b = "CLOCK1",
altsyncram_component.clock_enable_input_a = "NORMAL",
altsyncram_component.clock_enable_input_b = "NORMAL",
altsyncram_component.clock_enable_output_a = "BYPASS",
altsyncram_component.clock_enable_output_b = "BYPASS",
altsyncram_component.intended_device_family = "Stratix II",
altsyncram_component.lpm_type = "altsyncram",
altsyncram_component.numwords_a = 1'b1 << ADDR_WIDTH,
altsyncram_component.numwords_b = 1'b1 << ADDR_WIDTH,
altsyncram_component.operation_mode = "DUAL_PORT",
altsyncram_component.outdata_aclr_b = "NONE",
altsyncram_component.outdata_reg_b = "UNREGISTERED",
altsyncram_component.power_up_uninitialized = "FALSE",
altsyncram_component.read_during_write_mode_mixed_ports = "OLD_DATA",
altsyncram_component.widthad_a = ADDR_WIDTH,
altsyncram_component.widthad_b = ADDR_WIDTH,
altsyncram_component.width_a = DAT_WIDTH,
altsyncram_component.width_b = DAT_WIDTH,
altsyncram_component.width_byteena_a = 1;
// Note : The actual memory read occurs shortly
// after the read address registers are loaded. It
// is latched internally and NOT refreshed.
// Therefore read from X, wait, write to X, wait, finish read
// yields the OLD value of X. This is using external
// output registers and address stall to get at the refreshed
// data.
reg [DAT_WIDTH-1:0] q;
always @(posedge rd_clk) begin
if (rd_ena) begin
q <= unreg_rd_dat;
end
end
assign rd_dat = q;
end
else begin
// simulation RAM model
reg [DAT_WIDTH-1:0] store [0:(1<<ADDR_WIDTH)-1];
reg [ADDR_WIDTH-1:0] rdaddr,wraddr;
reg [DAT_WIDTH-1:0] q,wrdata;
reg wr;
initial begin
rdaddr <= 0;
wraddr <= 0;
q <= 0;
wr <= 0;
end
always @(posedge wr_clk) begin
wraddr <= wr_ptr[ADDR_WIDTH-1:0];
wrdata <= wr_dat;
if (wr_req & wr_ok) begin
wr <= 1'b1;
end
else wr <= 1'b0;
end
always @(negedge wr_clk) begin
if (wr) begin
store[wraddr] <= wrdata;
end
end
always @(posedge rd_clk) begin
if (rd_ena) begin
rdaddr <= rd_ptr[ADDR_WIDTH-1:0] + (rd_sclr ? 1'b0 : 1'b1);
q <= store [rdaddr];
end
end
assign rd_dat = q;
end
endgenerate
endmodule