读数据是直接从mem中读,不需要时钟。读地址A指示的是下一次要读的地址——此时FIFO不为空,读A地址是有效的。当前rdata信号上保存的是下一次要读的数据。如果外部读时钟域打算读数据,那么给一个读有效rinc,在rclk上升沿就可以直接把rdata取走,在rinc上升沿FIFO内部会根据A+1地址判断是否empty。(可以参考3.2节)。
写数据winc有效时,下一个写时钟沿wclk要写入数据。满标志表示如果在下一个时钟沿写数据,就写到读地址处(读写地址相同)。如果满,则下一个时钟沿不能写。所以在下一个写时钟沿到来时要判断满标志,如果满了,则不能写。
同样,读地址表示下一个读时钟沿要读的数据,空表示下一个时钟沿是否可以读。对于读数据的设备,它需要在读的时候判断是否空了,至于FIFO的rdata输出端则不需要进行empty判断,FIFO将下一次要读的数据放在rdata处,如果读数据的设备要读,就在rclk时钟沿读就行了。
module fifomem #(parameter DATASIZE = 8, // Memory data word widthparameter ADDRSIZE = 4) // Number of mem address bits
(output [DATASIZE-1:0] rdata,
input [DATASIZE-1:0] wdata,
input [ADDRSIZE-1:0] waddr, raddr,
input wclken, wfull, wclk);
`ifdef VENDORRAM
// instantiation of a vendor's dual-port RAM
vendor_ram mem (.dout(rdata), .din(wdata), //这一块不用管
.waddr(waddr), .raddr(raddr),
.wclken(wclken),
.wclken_n(wfull), .clk(wclk));
`else
// RTL Verilog memory model
localparam DEPTH = 1<<ADDRSIZE; //将地址位数转化成FIFO深度
reg [DATASIZE-1:0] mem [0:DEPTH-1];
assign rdata = mem[raddr]; //直接读,empty标志位影响raddr的累加
always @(posedge wclk)
if (wclken && !wfull) mem[waddr] <= wdata;//写需要判断full,并且在时钟沿处写
`endif
endmodule 6.3 读地址到写时钟域同步