?? lcd_dual_port_fifo.v
字號:
// ================================================================================
// (c) 2004 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, agreed by you upon download or as a
// "click-through" agreement upon installation andor 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.
// ================================================================================
// ================================================================================
// This module uses altsyncram to implement a (possibly) asynchronous FIFO with.
// ================================================================================
`timescale 1ns/1ns
module lcd_dual_port_fifo
(
rst_n,
// Write side
clk_wr,
wr, // write strobe
wdata,
wr_almost_full,
wr_full,
reset_fifo_rd,
// Read side
clk_rd,
rd_en,
rdata,
rd_empty,
rd_available,
full_error,
empty_error
);
// defaults
parameter DEVICE = "Cyclone";
parameter WR_PTR_WIDTH = 7;
parameter RD_PTR_WIDTH = 8;
parameter WR_DATA_WIDTH = 32;
parameter RD_DATA_WIDTH = 16;
parameter WR_DEPTH = 128;
parameter RD_DEPTH = 256;
parameter WRITE_ALMOST_BIT = 4;
parameter DIFF_RD_WR = 1;
input rst_n;
// Write side
input clk_wr;
input wr;
input [WR_DATA_WIDTH-1:0] wdata;
output wr_almost_full;
output wr_full;
input reset_fifo_rd;
// Read side
input clk_rd;
input rd_en;
output [RD_DATA_WIDTH-1:0] rdata;
output rd_empty;
output [RD_PTR_WIDTH-1:0] rd_available;
output full_error;
output empty_error;
// pointers on write side
wire [WR_PTR_WIDTH-1:0] wr_ptr;
wire [WR_PTR_WIDTH-1:0] nxt_wr_ptr;
wire [WR_PTR_WIDTH-1:0] binary_wr_ptr;
reg [RD_PTR_WIDTH-1:0] rd_ptr_s;
wire [RD_PTR_WIDTH-1:0] synch_rd_ptr;
reg [RD_PTR_WIDTH-1:0] binary_synch_rd_ptr;
// pointers on read side
wire [RD_PTR_WIDTH-1:0] rd_ptr;
wire [RD_PTR_WIDTH-1:0] nxt_rd_ptr;
wire [RD_PTR_WIDTH-1:0] binary_rd_ptr;
reg [WR_PTR_WIDTH-1:0] wr_ptr_s;
wire [WR_PTR_WIDTH-1:0] synch_wr_ptr;
reg [WR_PTR_WIDTH-1:0] binary_synch_wr_ptr;
wire [RD_DATA_WIDTH-1:0] rdata;
reg reset_fifo_wr;
reg reset_fifo_rd_sync;
always @(posedge clk_wr or negedge rst_n)
if (~rst_n)
begin
reset_fifo_rd_sync <= 1'b0;
reset_fifo_wr <= 1'b0;
end
else
begin
reset_fifo_rd_sync <= reset_fifo_rd;
reset_fifo_wr <= reset_fifo_rd_sync;
end
//additional logic to generate lsb for dpram read address
//assumes read pointer width = write pointer width
//currently only valid for 32-bit write and 16-bit read - TODO fix
reg [DIFF_RD_WR -1:0] rd_lsb;
always @(posedge clk_rd or negedge rst_n)
if (~rst_n)
rd_lsb <= 'b0; //reset
else if (rd_en == 0)
rd_lsb <= rd_lsb; //only update if rd_en is true
else
rd_lsb <= rd_lsb + 1'b1; //increment
//---------------------------------------------------------------------------
// Write side
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Write pointer
//
// Write pointer is gray coded and increments on when wr is asserted.
//---------------------------------------------------------------------------
gray_count #(WR_PTR_WIDTH) u_gray_wr_ptr
(
.clk (clk_wr),
.reset_n (~reset_fifo_wr),
.en (wr),
.gray (wr_ptr),
.binary (binary_wr_ptr),
.next_gray (nxt_wr_ptr),
.next_binary ()
);
//---------------------------------------------------------------------------
// Synchronise read pointer to write side
//
// Pointers are gray coded so only one bit can be changing at the time a
// pointer is sampled in a different clock domain. Double clocking ensures no
// metastability on that bit. Uncertainty just means that a pointer
// incrementing may take an extra clock to sample.
//---------------------------------------------------------------------------
integer j;
always @(posedge clk_wr or negedge rst_n)
if (~rst_n)
begin
rd_ptr_s <= {RD_PTR_WIDTH{1'b0}};
binary_synch_rd_ptr <= {RD_PTR_WIDTH{1'b0}};
end
else
begin
rd_ptr_s <= rd_ptr;
binary_synch_rd_ptr[RD_PTR_WIDTH-1] = rd_ptr_s[RD_PTR_WIDTH-1];
for (j=RD_PTR_WIDTH-2; j>=0; j=j-1)
binary_synch_rd_ptr[j] = binary_synch_rd_ptr[j+1] ^ rd_ptr_s[j];
end
wire [WR_PTR_WIDTH-1:0] wr_used;
assign wr_used = binary_wr_ptr - binary_synch_rd_ptr[RD_PTR_WIDTH-1:(RD_PTR_WIDTH - WR_PTR_WIDTH)];
reg wr_almost_full;
always @(posedge clk_wr or negedge rst_n)
if (~rst_n)
wr_almost_full <= 1'b0;
else if (reset_fifo_wr)
wr_almost_full <= 1'b0;
else if (wr)
begin
// set full bit a bit early to allow for the fact that the master
// will sample it whilst data is still streaming back on Avalon
if (wr_used > ({WR_PTR_WIDTH{1'b1}} - 8) - (1 << (WRITE_ALMOST_BIT - 1)))
wr_almost_full <= 1'b1;
end
else if (wr_almost_full)
begin
if (wr_used > ({WR_PTR_WIDTH{1'b1}} - 8) - (1 << (WRITE_ALMOST_BIT - 1)))
wr_almost_full <= 1'b1;
else
wr_almost_full <= 1'b0;
end
reg wr_full;
always @(posedge clk_wr or negedge rst_n)
if (~rst_n)
wr_full <= 1'b0;
else if (reset_fifo_wr)
wr_full <= 1'b0;
else if (wr)
begin
if (wr_used == ({WR_PTR_WIDTH{1'b1}} - 1))
wr_full <= 1'b1;
end
else if (wr_full)
begin
if (wr_used == {WR_PTR_WIDTH{1'b1}})
wr_full <= 1'b1;
else
wr_full <= 1'b0;
end
//---------------------------------------------------------------------------
// Memory
//
// Dual port mem.
//---------------------------------------------------------------------------
altsyncram u_dp_ram (
.clock0 (clk_wr),
.wren_a (wr),
.address_a (wr_ptr),
.data_a (wdata),
.clock1 (clk_rd),
.address_b ({rd_ptr, rd_lsb}),
.q_b (rdata)
);
defparam
u_dp_ram.operation_mode = "DUAL_PORT",
u_dp_ram.width_a = WR_DATA_WIDTH,
u_dp_ram.widthad_a = WR_PTR_WIDTH,
u_dp_ram.numwords_a = WR_DEPTH,
u_dp_ram.width_b = RD_DATA_WIDTH,
u_dp_ram.widthad_b = (RD_PTR_WIDTH + DIFF_RD_WR),
u_dp_ram.numwords_b = RD_DEPTH,
u_dp_ram.lpm_type = "altsyncram",
u_dp_ram.width_byteena_a = 1,
u_dp_ram.outdata_reg_b = "UNREGISTERED",
u_dp_ram.indata_aclr_a = "NONE",
u_dp_ram.wrcontrol_aclr_a = "NONE",
u_dp_ram.address_aclr_a = "NONE",
u_dp_ram.address_reg_b = "CLOCK1",
u_dp_ram.address_aclr_b = "NONE",
u_dp_ram.outdata_aclr_b = "NONE",
u_dp_ram.ram_block_type = "AUTO",
u_dp_ram.intended_device_family = DEVICE;
//---------------------------------------------------------------------------
// Read side
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Read pointer
//---------------------------------------------------------------------------
gray_count #(RD_PTR_WIDTH) u_gray_rd_ptr
(
.clk (clk_rd),
.reset_n (~reset_fifo_rd),
.en (rd_en && (&rd_lsb)),
.gray (rd_ptr),
.binary (binary_rd_ptr),
.next_gray (nxt_rd_ptr),
.next_binary ()
);
//---------------------------------------------------------------------------
// Synchronise write pointer to read side and convert to binary
//---------------------------------------------------------------------------
integer m;
always @(posedge clk_rd or negedge rst_n)
if (~rst_n)
begin
wr_ptr_s <= {WR_PTR_WIDTH{1'b0}};
binary_synch_wr_ptr <= {WR_PTR_WIDTH{1'b0}};
end
else
begin
wr_ptr_s <= wr_ptr;
binary_synch_wr_ptr[WR_PTR_WIDTH-1] = wr_ptr_s[WR_PTR_WIDTH-1];
for (m=WR_PTR_WIDTH-2; m>=0; m=m-1)
binary_synch_wr_ptr[m] = binary_synch_wr_ptr[m+1] ^ wr_ptr_s[m];
end
wire [RD_PTR_WIDTH-1:0] rd_available;
assign rd_available = binary_synch_wr_ptr - binary_rd_ptr[RD_PTR_WIDTH-1:(RD_PTR_WIDTH - WR_PTR_WIDTH)];
reg rd_empty;
always @(posedge clk_rd or negedge rst_n)
if (~rst_n)
rd_empty <= 1'b1;
else if (reset_fifo_rd)
rd_empty <= 1'b1;
else if (rd_en)
begin
if (rd_available == 1)
rd_empty <= 1'b1;
end
else if (rd_empty)
begin
if (binary_synch_wr_ptr == binary_rd_ptr)
rd_empty <= 1'b1;
else
rd_empty <= 1'b0;
end
//---------------------------------------------------------------------------
// Not implemented
//---------------------------------------------------------------------------
wire full_error = 1'b0;
wire empty_error = 1'b0;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
endmodule // dual_port_fifo
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -