- 基于真双口RAM。可以实现同时在一端写,另一端读的功能,两端的时钟可以不同。
- 什么时候读/写?-使能+空满标志的判断
- 空满如何判断?
读地址to格雷码-同步到写时钟域,与写地址比较-产生写满标志 - 如何在二进制下比较地址指针,得到空满信号?
读写指针均增加一位标志信号,当读写指针相等,FIFO为空;写指针领先读指针一圈,此时两者MSB不同,其余各位相同,FIFO为满 - 如何在格雷码下比较地址指针,得到空满信号?
空不变。最高位和次高位不同,其余位相同,代表满
注意看0-8,1-9,2-10
框架图
module asyn_fifo(
input clkw,clkr,rst_n,
input w_en,r_en,
input [7:0] data_in,
output w_full,r_empty,
output reg [7:0] data_out
);
reg [7:0] mem[15:0]; //16x8 RAM
reg [4:0] w_addr,r_addr,w_addr_g,r_addr_g;
reg [4:0] w_addr_gr[1:0];
reg [4:0] r_addr_gw[1:0];
always@(posedge clkw or negedge rst_n) begin
if(!rst_n) begin
w_addr <= 0;
end
if(w_en==1 && w_full==0) begin
mem[w_addr[3:0]] <= data_in;
w_addr <= w_addr + 1;
end
end
always@(posedge clkr or negedge rst_n) begin
if(!rst_n) begin
r_addr <= 0;
end
if(r_en==1 && r_empty==0) begin
data_out <= mem[r_addr[3:0]]
r_addr <= r_addr + 1;
end
end
assign w_addr_g = w_addr ^ (w_addr>>1);
assign r_addr_g = r_addr ^ (r_addr>>1);
always@(posedge clkw or negedge rst_n) begin
if(!rst_n) begin r_addr_gw[0]<=0; r_addr_gw[1]<=0; end
else begin r_addr_gw[0]<=r_addr_g; r_addr_gw[1]<=r_addr_gw[0]; end
end
always@(posedge clkr or negedge rst_n) begin
if(!rst_n) begin w_addr_gr[0]<=0; w_addr_gr[1]<=0; end
else begin w_addr_gr[0]<=w_addr_g; w_addr_gr[1]<=w_addr_gr[0]; end
end
assign r_empty = r_addr_g == w_addr_gr[1];
assign w_full = w_addr_g == {~r_addr_gw[1][4:3],r_addr_gw[1][2:0]};
endmodule