FiFo外部是没有地址的,外部端口只负责读写,内部RAM有地址
FIFO可以在一边读,一边写,两边读写速度可不一样,
RAM中的控件可以重复利用,某个数据位读走后,可再存入新的数据。
两边速度不同的情况下,RAM的空间和两边读写速度满足一定的公式就可随意读写
FIFO中的RAM设计
module dp_ram #(parameter DLY = 1,
RAM_WIDTH = 8,
RAM_DEPTH = 16,
ADDR_WIDTH= 4)
(input write_clock,
input read_clock,
input write_allow,
input read_allow,
input [ADDR_WIDTH-1:0] write_addr,
input [ADDR_WIDTH-1:0] read_addr,
input [RAM_WIDTH-1 :0] write_data,
output reg [RAM_WIDTH-1 :0] read_data);
reg [RAM_WIDTH-1:0] memory[RAM_DEPTH-1:0];
always @(posedge write_clock) begin
if(write_allow)
memory[write_addr] <= #DLY write_data;
end
always @(posedge read_clock) begin
if(read_allow)
read_data <= #DLY memory[read_addr];
end
endmodule
同步FIFO的设计
FIFO原则:先进先出
同步FIFO的设计
1. 通过计数判断fifo空满
`timescale 1ns/10ps
module SYNCFIFO#(parameter DATA_WIDTH = 8,
ADDR_WIDTH = 9)
(input wire fifo_rst, //复位信号
input wire clock, //读写的同步时钟
input wire read_enable,
input wire write_enable,
input reg [DATA_WIDTH-1:0] write_data,
output reg [DATA_WIDTH-1:0] read_data,
output reg full, //满信号
output reg empty, //空信号
output reg [ADDR_WIDTH-1:0] fcounter
);
wire read_allow = (read_enable && !empty); //读允许+不空
wire write_allow = (write_enable && !full); //写允许+不满
dp_ram fifo_ram(
.write_clock(clock),
.read_clock (clock),
.write_allow(write_allow),
.read_allow (read_allow),
.read_addr (read_addr),
.write_addr (write_addr),
.write_data (write_data),
.read_data (read_data)
);
/*
* 1. 判断fifo的空满
*/
always @(posedge clock or posedge fifo_rst)
if(fifo_rst)
empty <= 'b1;
else
empty <= (!write_enable && (fcounter[8:1] == 8'h0) &&
((fcounter[0] == 0)||read_enable));
always @(posedge clock or posedge fifo_rst)
if(fifo_rst)
full <= 'b1;
else
full <= (!read_enable && (fcounter[8:1] == 8'hFF) &&
((fcounter[0] == 1)||write_enable));
/*
* 2. 产生读写地址
*/
always @(posedge clock or posedge fifo_rst)
if(fifo_rst)
read_addr <= 'h0;
else if(read_allow)
read_addr <= read_addr + 'b1;
always @(posedge clock or posedge fifo_rst)
if(fifo_rst)
write_addr <= 'h0;
else if(write_allow)
write_addr <= write_addr + 'b1;
/*
* 3. 读写计数(写:计数器加1;读:计数器减1)
*/
always @(posedge clock or posedge fifo_rst)
if(fifo_rst)
fcounter <= 'h0;
else if((!read_allow && write_allow)||(read_allow && !write_allow))
begin
if(write_allow) fcounter <= fcounter + 'b1;
else fcounter <= fcounter - 'b1;
end
endmodule
2. 通过地址扩展位判断fifo空满
module sync_fifo(
input clk,
rst,
write_enable,
read_enable,
input [7:0] data_in,
output reg [7:0] data_out,
output empty,
full
);
/* 数据宽度为8bit,深度为16的RAM */
reg [7:0] mem[15:0];
/* 地址 */
wire[3:0] w_addr, w_addr;
reg [4:0] r_addr_a, w_addr_a;
assign r_addr = r_addr_a[3:0];
assign w_addr = w_addr_a[3:0];
/* 读 */
always@(posedge clk or negedge rst) begin
if(!rst)
r_addr_a <= 5'b0; //复位,读地址清零
else begin
if(rd_en == 1 && empty == 0) begin //当读允许,非空时执行
data_out <= mem[r_addr]; //读出数据
r_addr_a <= r_addr_a + 1; //读地址加1
end
end
end
/* 写 */
always@(posedge clk or negedge rst) begin
if(!rst)
w_addr_a <= 5'b0; //复位,写地址清零
else begin
if(wr_en == 1 && full == 0) begin //当写允许,非满时执行
mem[w_addr] <= data_in; //数据写入指定地址
w_addr_a <= w_addr_a + 1; //写地址加1
end
end
end
/* 判断空满 */
assign empty = (r_addr_a == w_addr_a) ? 1 : 0;
assign full = (r_addr_a[4] != w_addr_a[4] &&
r_addr_a[3:0] == w_addr_a[3:0]) ? 1 : 0;
endmodule