设计实现一个512x8的双端口RAM:
RAM宽度为8bit
RAM深度为512
ADDR位宽2^9 = 512
//双口RAM
module DUALRAM(Read_clock,Write_clock,Read_allow,Write_allow,Read_addr,Write_addr,Write_data,Read_data);
parameter DLY = 1;
parameter RAM_WIDTH = 8;
parameter RAM_DEPTH = 512;
parameter ADDR_WIDTH = 9;
input Read_clock ,Write_clock;
input [RAM_WIDTH-1:0]Write_data;
input [ADDR_WIDTH-1:0]Read_addr;
input [ADDR_WIDTH-1:0]Write_addr;
input Read_allow,Write_allow;
output [RAM_WIDTH-1:0]Read_data;
reg [RAM_WIDTH-1:0]Read_data;
reg [RAM_WIDTH-1:0] Mem[RAM_DEPTH-1:0]; //前面为内存宽度,后面为内存深度。reg类型的数组
always@(posedge Write_clock) begin
if(Wirte_allow)
Mem[Write_addr] <= #DLY Write_data;
end
always@(posedge Read_clock) begin
if(Read_allow)
Read_data <= #DLY Mem[Read_addr];
end
endmodule
// fifo 设计,full不能写,empty不能读。关键在于full和empty的产生
方法1: 用长度计数器factor,执行写操作,长度加1,执行读操作,factor减1。
方法2:地址位扩展一位,用最高位来判断空满,低位地址为R_ADDR = W_ADDR。用10位地址信号,最高位判断空满。
高位相等,则为空。不相等则为满。
// 产生full empty信号,根据Read_enable,Write_enable产生 Read_allow和Write_allow。
// 产生Read_addr和Write_addr。 通过这两个信号,通过双口ram完成read_data 和 write_data。
//fifo控制
1 fifo 对双口ram通过read_allow 和wirte_allow,实现数据的存储和读取。
2 而read_allow 和wirte_allow是通过full和empty,read_enable,write_enable来实现的,所以full和empty的生成很重要。空满信号又是根据Fcount计数器间接控制,Fcount的生成也很关键。
3 Fcount 的更新。
module SYNCFIFO(Fifo_rst,Clock,Read_enable,Write_enable,Write_data,Read_data,Full,Empty,Fcounter);
parameter DATA_WIDTH = 8;
parameter ADDR_WIDTH = 9;
input Fifo_rst;
input Clock;
input Read_enable;
input Write_enable;
input [DATA_WIDTH-1:0] Write_data;
output [DATA_WIDTH-1:0] Read_data;
output Full;
output Empty;
output [ADDR_WIDTH-1:0] Fcounter;
reg [DATA_WIDTH-1:0] Read_data;
reg Full;
reg Empty;
reg [ADDR_WIDTH-1:0] Fcounter;
reg [ADDR_WIDTH-1:0] Read_addr;
reg [ADDR_WIDTH-1:0] Write_addr;
wire Read_allow = (Read_enable && !empty); // 空不能读
wire Write_allow = (Write_enable && !Full); //满不能写
DUALRAM U_RAM(
.Read_clock(Clock),
.Write_clock(Clock),
.Read_allow(Read_allow),
.Write_allow(Write_allow),
.Read_addr(Read_addr),
.Write_addr(Write_addr),
.Write_data(Write_data),
.Read_data(Read_data)
);
// 空满信号的产生
always@(posedge Clock or posedge Fifo_rst)
if(Fifo_rst)
Empty <= 1'b1;
else
Empty <= (!Write_enable && (Fcount[8:1] == 8'b0) && ((Fcount[0] == 1'b0) || Read_enable));
always@(posedge Clock or posedge Fifo_rst)
if(Fifo_rst)
Full <= 1'b1;
else
Full <= (!Read_enable && (Fcount[8:1] == 8'hFF) && ((Fcount[0] == 1'b1) || Write_enable));
// 计数器
always@(posedge Clock or posedge Fifo_rst)
if(Fifo_rst)
Fcount <= 1'b0;
else if(read_enable && write_enable)
Fcount <= Fcount;
else if(Read_allow)
Fcount <= Fcount - 1'b1;
else if(Write_allow)
Fcount <= Fcount + 1'b1;
else
Fcount <= Fcount;
// 写数据 读数据控制。 通过Read_allow和Write_allow和双口ram联系起来
always@(posedge Clock or posedge Fifo_rst)
if(Fifo_rst)
Read_addr <= 1'b0;
else if(Read_allow)
Read_addr <= Read_addr + 1'b1;
always@(posedge Clock or posedge Fifo_rst)
if(Fifo_rst)
Write_addr <= 1'b0;
else if(Write_allow)
Write_addr <= Write_addr + 1'b1;
endmodule