⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 asyncfifoxpx.v

📁 任意时钟配比的异步fifo.含有synplify ip库中的双端口ram。用于处理多时钟域问题。
💻 V
字号:
//written by xpx in 2008-11-27, modified from the asyncfifo from limiao.
module ASYNCFIFO
                #(parameter
                  DSIZE = 32,//width=16,指明读写数据的宽度
                  ASIZE =  2 //depth=4//指明地址总线的宽度,是fifo单元数的幂函数
                )( //input signals
                  input              wrst_n,  //write resett
                  input              wclk,    //write clock
                  output             wenable,   //fifo full flag
                  input              wta,     //write enable,有效时表明输入端口数据有效
                  input  [DSIZE-1:0] wdata,   //write data

                  input              rrst_n,  //read reset
                  input              rclk,    //read clock
                  output             renable,  //fifo empty flag
                  input              rreq,     //read enable,有效时要求读取下一个数据
                  output [DSIZE-1:0] rdata  //read data
                  );

parameter depth=2**ASIZE;

//internal variables
reg   [ASIZE:0]     wptr,rptr;
wire  [ASIZE-1:0]   waddr,raddr;
reg   [ASIZE:0]     wbin,rbin;
reg   [ASIZE:0]     wbin_next,rbin_next;
reg   [ASIZE:0]     wgnext,rgnext;

//---------write------------------------------------------
wire wring=wta&&wenable;

always @ (posedge wclk or negedge wrst_n)
  if (!wrst_n)wptr<=0;
  else wptr<=wptr+wring;//use binary code to keep data

reg[ASIZE:0]wptrg;
always@(posedge wclk)wptrg<={1'b0,wptr[ASIZE:1]}/*(wptr>>1)*/^wptr;//change binary to gray to transport
//----------read-------------------------------------------
wire rding=renable&&rreq;
wire[ASIZE-1:0]rptrram=rptr[ASIZE-1:0]+rding;

always @ (posedge rclk or negedge rrst_n)
  if (!rrst_n)
    rptr <= 0;
  else
    rptr <=rptr+rding;

reg[ASIZE:0]rptrg;
always@(posedge rclk)rptrg<={1'B0,rptr[ASIZE:1]}/*(rptr>>1)*/^rptr;

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//本例中换成sysnplify生成的双端口ram,此处的ram必须换成确保可以使用的双端口ram才行。
fifowrclkram #(DSIZE,ASIZE)ram
(
	 .PortAClk        (wclk)//used to write
	,.PortAAddr       (wptr[ASIZE-1:0])//waddr
	,.PortADataIn     (wdata)
	,.PortAWriteEnable(wta)
	,.PortBClk        (rclk)//used to read
	,.PortBAddr       (rptrram)//rbin_next)//raddr)
	,.PortBDataOut    (rdata)//注意:读数据是经过寄存的,所以要延时1拍。
);

//-------------compare-------------------------------------
reg[ASIZE:0] wrptr2,rwptr2;//2位数据同步

reg[ASIZE:0]rtow;
always @ (posedge wclk or negedge wrst_n)
  if(!wrst_n)
    {wrptr2,rtow} <= 0;
  else
    {wrptr2,rtow} <= {rtow,rptrg};

reg[ASIZE:0]wtor;
always @ (posedge rclk or negedge rrst_n)
  if(!rrst_n)
    {rwptr2,wtor} <= 0;
  else
    {rwptr2,wtor} <= {wtor,wptrg};

wire [ASIZE:0] cmprptr,cmpwptr;
assign cmprptr = wrptr2 ^ {1'b0,wrptr2[ASIZE:1]};//[2:1]};//gray_to_bin,wclk下的rptr 2进制
assign cmpwptr = rwptr2 ^ {1'b0,rwptr2[ASIZE:1]};//2:1]};//gray_to_bin,rclk下的wptr 2进制

wire [ASIZE:0] wdata_count,rdata_count;

assign wdata_count = {cmprptr[ASIZE]^wptr[ASIZE],wptr[ASIZE-1:0]} - {1'b0,cmprptr[ASIZE-1:0]}; //wclk下求解count
assign rdata_count = {rptr[ASIZE]^cmpwptr[ASIZE],cmpwptr[ASIZE-1:0]} - {1'b0,rptr[ASIZE-1:0]};//rclk下求解count

//上面的异或是为了生成四个象限,由于只有4个单元,指针只需2位就可表示,而最高位[2]
//实际上就是指示翻转次数

assign wenable  = (wdata_count != depth);//3'd4);
assign renable = (rdata_count != 3'd0);

endmodule

//always @ (posedge wclk or negedge wrst_n)
//  if (!wrst_n)
//    wptr <= 0;
//  else
//    wptr <= wgnext; //采用格雷码计数,保存数据

//always @ (*)
//begin
//  for(i=0;i<ASIZE+1;i=i+1)//将用格雷码表示的wptr转换为2进制数
//    wbin[i] = ^(wptr>>i);
//
//  if(wenable)//将wptr的2进制形式加wta(wta)
//    wbin_next = wbin+ wta;
//  else
//    wbin_next = wbin;
//
//  wgnext = (wbin_next>>1) ^ wbin_next;    //重新转换为格雷码
//end

//assign  waddr =  wbin[ASIZE-1:0]; //ram的写地址仍采用2进制形式

//always @ (posedge rclk or negedge rrst_n)
//  if (~rrst_n)
//    rptr <= 0;
//  else
//    rptr <= rgnext;
//
//always @ (*)
//begin
//  for(k=0;k<ASIZE+1;k=k+1)
//    rbin[k] = ^(rptr>>k);
//
//  if(renable)
//    rbin_next = rbin + rreq;
//  else
//    rbin_next = rbin;
//
//  rgnext = (rbin_next>>1) ^ rbin_next;
//end

//assign  raddr =  rbin[ASIZE-1:0];

//-------------ram-----------------------------------------
//  ram_16x4 ram_16x4
//    (
//     .QA  (rdata),
//     .AA  (raddr),
//     .CLKA(rclk),
//     .CENA(rreq),
//     .AB  (waddr),
//     .DB  (wdata),
//     .CLKB(wclk),
//     .CENB(wta)
//    );
//=============================================================实例化ram
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//错误,这个例子不能使用,此处的ram必须换成确保可以使用的双端口ram才行。
//reg[DSIZE-1:0]fifo[depth-1:0];
//
//always @ (posedge wclk)
//begin
//	if(wta)
//	  fifo[waddr] <= wdata;
//end
//
//assign rdata=fifo[raddr];
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//本例中换成sysnplify生成的双端口ram
//fifowrclkram #(DSIZE,ASIZE)ram
//(
//	 .PortAClk        (wclk)//used to write
//	,.PortAAddr       (wptr)//waddr
//	,.PortADataIn     (wdata)
//	,.PortAWriteEnable(wta)
//	,.PortBClk        (rclk)//used to read
//	,.PortBAddr       (rptrram)//rbin_next)//raddr)
//	,.PortBDataOut    (rdata)//注意:读数据是经过寄存的,所以要延时1拍。
//);

//-------------compare-------------------------------------
//   wire [ASIZE:0] wrptr2,rwptr2;//2位数据同步
//reg[ASIZE:0] wrptr2,rwptr2;//2位数据同步
  //read-domain to write-domain synchronizer
//  sync_multi_bit #(ASIZE+1) sync_rptr
//    (
//     .i_data(rptr),
//     .o_rst_n(wrst_n),
//     .o_clk(wclk),
//     .o_data(wrptr2)
//    );
//reg[ASIZE:0]rtow;
//always @ (posedge wclk or negedge wrst_n)
//  if(!wrst_n)
//    {wrptr2,rtow} <= 0;
//  else
//    {wrptr2,rtow} <= {rtow,rptrg};

  //write-domain to read-domain synchronizer
//  sync_multi_bit #(ASIZE+1) sync_wptr
//    (
//     .i_data(wptr),
//     .o_rst_n(rrst_n),
//     .o_clk(rclk),
//     .o_data(rwptr2)
//     );

//always @ (posedge rclk or negedge rrst_n)
//  if(~rrst_n)
//    {rwptr2,wtor} <= 0;
//  else
//    {rwptr2,wtor} <= {wtor,wptr};
//reg[ASIZE:0]wtor;
//always @ (posedge rclk or negedge rrst_n)
//  if(!rrst_n)
//    {rwptr2,wtor} <= 0;
//  else
//    {rwptr2,wtor} <= {wtor,wptrg};
//
//wire [ASIZE:0] cmprptr,cmpwptr;
//assign cmprptr = wrptr2 ^ {1'b0,wrptr2[ASIZE:1]};//[2:1]};//gray_to_bin,wclk下的rptr 2进制
//assign cmpwptr = rwptr2 ^ {1'b0,rwptr2[ASIZE:1]};//2:1]};//gray_to_bin,rclk下的wptr 2进制
//
//wire [ASIZE:0] wdata_count,rdata_count;
//  assign wdata_count = {cmprptr[2]^wbin[2],wbin[1:0]} - {1'b0,cmprptr[1:0]}; //wclk下求解count
//  assign rdata_count = {rbin[2]^cmpwptr[2],cmpwptr[1:0]} - {1'b0,rbin[1:0]};//rclk下求解count
//assign wdata_count = {cmprptr[ASIZE]^wptr[ASIZE],wptr[ASIZE-1:0]} - {1'b0,cmprptr[ASIZE-1:0]}; //wclk下求解count
//assign rdata_count = {rptr[ASIZE]^cmpwptr[ASIZE],cmpwptr[ASIZE-1:0]} - {1'b0,rptr[ASIZE-1:0]};//rclk下求解count

//上面的异或是为了生成四个象限,由于只有4个单元,指针只需2位就可表示,而最高位[2]
//实际上就是指示翻转次数
//  assign wfull  = (wdata_count == 3'd4);
//  assign rempty = (rdata_count == 3'd0);
//assign wenable  = (wdata_count != depth);//3'd4);
//assign renable = (rdata_count != 3'd0);
//
//
//endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -