ALTERA提供了LPM_FIFO参数宏模块,可以在代码中例化使用。
FIFO有两种工作模式:(1)SCFIFO,(2)DCFIFO
其中SCFIFO指读写用一个时钟进行同步,可以支持同时读写的功能。
其中DCFIFO指读写使用不同的时钟进行同步,这在设计多时钟系统中相当有用,可用于不同时钟同步信号之间的同步调整。
首先看看DCFIFO模式下的几个比较重要的信号:
[A]在写端,主要有以下几个信号:
(1) data[n-1:0]:写入数据信号总线;
(2) wrreq:写入请求信号,高有效
(2) wrclk:写入同步时钟;
(3) wrfull, wrempty:用于指示写端FIFO为空或者满的状态;
(4) wrusedw[log2(SIZE_FIFO)-1:0] :写入的数据个数,按写入个数递增;
上述信号都与写入时钟srclk同步;
[B]在读端,主要有以下几个信号:
(1) q[n-1:0]:读取数据信号总线;
(2) rdreq:读取请求/确认信号,高有效
(2) rdclk:读取同步时钟;
(3) rdfull, rdempty:用于指示读端FIFO为空或者满的状态;
(4) rdusedw[log2(SIZE_FIFO)-1:0] :读取的数据个数,按读取顺序递减;
FIFO主要有两种工作模式:
(1) Legacy mode(Legacy synchronous FIFO mode )
(2) Show-ahead mode(Show-ahead synchronous FIFO mode)
其中:
在Legacy mode,读端的rdreq信号作为读取FIFO的请求信号(REQ),读取数据在rdreq置位后的第二个时钟周期有效。
在Show-ahead mode,读端的rdreq信号作为读取FIFO的确认信号(ACK),读取数据在rdreq置位后立即有效,不要额外的读取周期。
下面分别给出Legacy mode和Show-ahead mode的读写时序:
[A] Legacy mode
[B] Show-ahead mode
由上述时序可以看出两种模式的区别。
值得注意的是:
读端在读取数据的时候,必须等待写端数据准备好,即rdempty为低之后开始读取数据,为高期间表明FIFO状态为空,写端写入数据未有效。
相应的在写端如果wrfull为高,则表明FIFO状态以满,不能再写入数据,此时写入的数据无效。
下面给出一个FIFO操作的具体实例:完成将10MHz同步输入的总线同步缓冲到72MHz+6MHz的同步组合输出。
// ----------------------------------------------------------------------------------
// Copyright (c) 2007 by College of Communication Engineering,Chongqing University.
// ----------------------------------------------------------------------------------
// Project:
//
// ----------------------------------------------------------------------------------
// File Name:CNGI_PLCP2TxPHY_SyncProc.v
// Module:
//
// Top Module:
//
// ----------------------------------------------------------------------------------
//
// Major Functions:
//
// ----------------------------------------------------------------------------------
//
// Revision History :
// ----------------------------------------------------------------------------------
// Ver :| Author :| Mod. Date :| Changes Made: :| E-mail
// V1.0 :| ZHANG-xuying :| 01/08/07 :| Initial Revision :| zh_xuying@126.com
// ----------------------------------------------------------------------------------
`define PLME_RESET_IND (4'b1001)
`define CCA_RESET_IND (4'b1010)
`define TxSTARTreq_IND (4'b1011)
`define TxMPDU_IND (4'b1100)
module CNGI_PLCP2TxPHY_SyncProc(
reset, //poewer on reset
PLCP2TxPHY_clk,
PLCP2TxPHY_ind,
PLCP2TxPHY_msg,
//
clk, //Tx PHY Local(此处不区分原语和MPDU直接采用数据的基带时钟读取)
clk_ena,
//
LENGTH,
syncPLCP2TxPHY_ind,
syncPLCP2TxPHY_msg
);
//
input wire reset;
input wire PLCP2TxPHY_clk;
input wire [3:0] PLCP2TxPHY_ind;
input wire [7:0] PLCP2TxPHY_msg;
//
input wire clk,clk_ena;
input wire [11:0] LENGTH;
//
output wire [3:0] syncPLCP2TxPHY_ind;
output wire [7:0] syncPLCP2TxPHY_msg;
//Generate wrreq
reg fifo_wrreq;
reg [11:0] fifo_wrdata;
always @(posedge PLCP2TxPHY_clk or posedge reset)begin
if(reset) fifo_wrreq<=1'b0;
else fifo_wrreq<=PLCP2TxPHY_ind[3];
end
//
always @(posedge PLCP2TxPHY_clk or posedge reset)begin
if(reset) fifo_wrdata<=12'd0;
else fifo_wrdata<={PLCP2TxPHY_ind,PLCP2TxPHY_msg};
end
//
reg [3:0] BUS_IND_TYPE;
always @(posedge PLCP2TxPHY_clk or posedge reset)begin
if(reset) BUS_IND_TYPE<=4'h0;
else begin
case(PLCP2TxPHY_ind)
`PLME_RESET_IND: BUS_IND_TYPE<=`PLME_RESET_IND;
`CCA_RESET_IND: BUS_IND_TYPE<=`CCA_RESET_IND;
`TxSTARTreq_IND: BUS_IND_TYPE<=`TxSTARTreq_IND;
`TxMPDU_IND: BUS_IND_TYPE<=`TxMPDU_IND;
default: BUS_IND_TYPE<=BUS_IND_TYPE;
endcase
end
end
//
wire fifo_rdempty;
reg fifo_rdack;
reg [2:0] cnt_a,cnt_b;
reg [2:0] cnt_c;
reg [11:0] cnt_d;
always @(posedge clk or posedge reset)begin
if(reset)begin
cnt_a<=3'd0;
cnt_b<=3'd0;
cnt_c<=3'd0;
cnt_d<=12'd0;
fifo_rdack<=1'b0;
end
else if(clk_ena)begin
if(BUS_IND_TYPE==`PLME_RESET_IND || BUS_IND_TYPE==`CCA_RESET_IND) begin
if(!fifo_rdempty)begin
if(cnt_a==0)begin
fifo_rdack<=1'b1;
cnt_a<=cnt_a+1;
end
else if(cnt_a==1)begin
fifo_rdack<=1'b0;
cnt_a<=cnt_a;
end
end
end
else if(BUS_IND_TYPE==`TxSTARTreq_IND)begin
if(!fifo_rdempty)begin
if(cnt_b<=5)begin
fifo_rdack<=1'b1;
cnt_b<=cnt_b+1;
end
else if(cnt_b==6)begin
fifo_rdack<=1'b0;
cnt_b<=cnt_b;
end
end
end
else if(BUS_IND_TYPE==`TxMPDU_IND)begin
if(!fifo_rdempty)begin
if(cnt_c>=7)begin
if(cnt_d<LENGTH)begin
fifo_rdack<=1'b1;
cnt_d<=cnt_d+1;
cnt_c<=3'd0;
end
else if(cnt_d==LENGTH)begin
fifo_rdack<=1'b0;
cnt_d<=cnt_d;
cnt_c<=cnt_c;
end
end
else cnt_c<=cnt_c+1;
end
end
end
else fifo_rdack<=1'b0;
end
wire [11:0] fifo_Q;
PLCP2TxPHY_FIFO u1(
.aclr(reset),
.data(fifo_wrdata),
.rdclk(clk),
.rdreq(fifo_rdack),
.wrclk(PLCP2TxPHY_clk),
.wrreq(fifo_wrreq),
.q(fifo_Q),
.rdempty(fifo_rdempty)
);
//
assign syncPLCP2TxPHY_ind=fifo_Q[11:8];
assign syncPLCP2TxPHY_msg=fifo_Q[7:0];
endmodule