导读:作者有幸在中国电子信息领域的排头兵院校“电子科技大学”攻读研究生期间,接触到前沿的数字IC验证知识,旁听到诸如华为海思、清华紫光、联发科技等业界顶尖集成电路相关企业面授课程,对数字IC验证有了一些知识积累和学习心得。为帮助想入门前端IC验证的朋友,思忱一二后,特开此专栏,以期花最短的时间,走最少的弯路,学最多的IC验证技术知识。
FIFO,First In First Out,先入先出的队列。
学会了同步FIFO后,再学习异步FIFO学起来就容易了。
学习FIFO的要求,不要求要能够完全写出来,但是要懂得基本概念,FIFO是什么功能,设计FIFO基本要求等
设计实现一个16x8的双端口RAM

对应的代码
module dp_ram(//dp = dual port
input wire write_clock,
input wire read_clock,
input wire write_allow,
input wire read_allow,
input wire [ADDR_WIDTH-1:0] write_addr,
input wire [ADDR_WIDTH-1:0] read_addr,
input wire [RAM_WIDTH-1:0 ] write_data,
output reg [RAM_WIDTH-1:0 ] read_data
);
parameter DLY = 1;
parameter RAM_WIDTH = 8;
parameter RAM_EDPTH = 16;
parameter ADDR_WIDTH= 4;
reg [RAM_WIDTH-1:0 ] memory[RAM_EDPTH-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
module SYNCFIFO(
input wire Fifo_rst,
input wire Clock,
input wire Read_enable,
input wire Write_enable,
input wire [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
);
parameter DATA_WIDTH = 8;
parameter ADDR_WIDTH = 9;
reg [ADDR_WIDTH-1:0] Read_addr;
reg [ADDR_WIDTH-1:0] Write_addr;
wire Read_allow = (Read_enable && !Empty); //空不能读;最好不要这样写,容易出错,该写法等效于assign的那种!
wire Write_allow = (Write_enable && !Full); //满不能写
DUALRAM U_RAM(
.Write_clock (Clock),
.Read_clock (Clock ),
.Write_allow (Write_allow),
.Read_allow (Read_allow ),
.Write_addr (Write_addr ),
.Read_addr (Read_addr ),
.Write_data (Write_data ),
.Read_data (Read_data )
);
always@(posedge Clock or posedge Fifo_rst)
if(Fifo_rst)
Empty <= 'b1;
else
有点复杂化了,只要Fcounter[8:0]==9'h0,那么Empty就为1即可!
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
//同样复杂化了,只要Fcounter[8:0]==9'b1_1111_1111,那么Full就为1即可!
Full <= (!Read_enable && (Fcounter[8:1]==8'hFF) && ((Fcounter[0]==1) || Write_enable));
always@(posedge clock or posedge Fifo_rst)
if(Fifo_rst)
Read_addr <= 'h0;
else if(Read_allow)
Read_addr <= Read_addr + 'b1;//最好加个边界限制,eg:if(Read_addr >= Depth-1) Read_addr <= 'h0之类的!
always@(posedge clock or posedge Fifo_rst)
if(Fifo_rst)
Write_addr <= 'h0;
else if(Write_allow)
Write_addr <= Write_addr + 'b1;//同样最好加个边界限制
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
小知识:RTL代码不是程序,程序是编译成一条条指令和数据,放置到内存中,通过CPU取指令、译码、执行!RTL代码没有编译一说,综合映射成网表,体现实际硬件电路!

module sync_fifo(
input wire clk,
input wire rst,
input wire wr_en,
input wire rd_en,
input wire [7:0] data_in,
output wire empty,
output wire full,
output reg [7:0] data_out,
);
reg [7:0] mem[15:0];
wire [3:0] w_addr,r_addr;
reg [4:0] r_addr_a, w_addr_a; //16个地址深度,4位就够了即[3:0],此处[4:0]扩展了1位
assign r_addr = r_addr_a[3:0];
assign w_addr = w_addr_a[3:0];
always@(posedge clk or negedge rst)
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;
end
end
always@(posedge clk or negedge rst)
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;
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
对应的TestBench



格雷码转换模块对应的RTL代码




