设为首页 加入收藏

TOP

异步fifo的设计(FPGA)(三)
2017-10-10 12:20:14 】 浏览:10023
Tags:异步 fifo 设计 FPGA
.rrst_n(rrst_n) );
//this module is completely synchronous to the write-clock domain and contains the FIFO write pointer and full-flag logic wptr_full #(ASIZE) wptr_full ( .wfull(wfull), .waddr(waddr), .wptr(wptr), .wq2_rptr(wq2_rptr), .winc(winc), .wclk(wclk), .wrst_n(wrst_n) ); endmodule View Code

2、fifomem.v  生成存储实体,FIFO 的本质是RAM,因此在设计存储实体的时候有两种方法:用数组存储数据或者调用RAM的IP核 

module fifomem
#(
    parameter  DATASIZE = 8, // Memory data word width               
    parameter  ADDRSIZE = 4  // 深度为8即地址为3位即可,这里多定义一位的原因是用来判断是空还是满,详细在后文讲到
) // 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 RAM   //可以调用一个RAM IP核
// instantiation of a vendor's dual-port RAM 
my_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;   // 左移相当于乘法,2^4
reg [DATASIZE-1:0] mem [0:DEPTH-1]; //生成2^4个位宽位8的数组
assign rdata = mem[raddr];
always @(posedge wclk)  //当写使能有效且还未写满的时候将数据写入存储实体中,注意这里是与wclk同步的
    if (wclken && !wfull)
        mem[waddr] <= wdata;
 `endif
 endmodule
View Code

3、sync_r2w.v 将 rclk 时钟域的格雷码形式的读指针同步到 wclk 时钟域,简单来讲就是用两级寄存器同步,即打两拍 

module sync_r2w
#(
    parameter ADDRSIZE = 4
)
(
    output reg [ADDRSIZE:0] wq2_rptr,   //读指针同步到写时钟域
    input      [ADDRSIZE:0] rptr,       // 格雷码形式的读指针,格雷码的好处后面会细说 
    input                   wclk, wrst_n
);
 
reg [ADDRSIZE:0] wq1_rptr;
 
  always @(posedge wclk or negedge wrst_n)   
      if (!wrst_n) begin
          wq1_rptr <= 0;          
          wq2_rptr <= 0;
      end           
      else begin        
          wq1_rptr<= rptr;
          wq2_rptr<=wq1_rptr;
      end          
  endmodule
View Code

4、sync_w2r.v 将 wclk 时钟域的格雷码形式的写指针同步到 rclk 时钟域

module sync_w2r
#(parameter ADDRSIZE = 4)
(
    output reg [ADDRSIZE:0] rq2_wptr, //写指针同步到读时钟域
    input      [ADDRSIZE:0] wptr,     //格雷码形式的写指针
    input                   rclk, rrst_n
);
 
reg [ADDRSIZE:0] rq1_wptr;
 
  always @(posedge rclk or negedge rrst_n)   
      if (!rrst_n)begin
          rq1_wptr <= 0;
          rq2_wptr <= 0;
      end 
      else begin
          rq1_wpt <= wptr;
          rq2_wptr <= rq1_wptr;
      end
        
endmodule
View Code

5、rptr_empty.v 将 sync_w2r.v 同步后的写指针与 rclk 时钟域的读指针进行比较生成都空信号

module rptr_empty
#(
    parameter ADDRSIZE = 4
)
(
    output reg                rempty, 
    output     [ADDRSIZE-1:0] raddr,  //二进制形式的读指针
    output reg [ADDRSIZE  :0] rptr,  //格雷码形式的读指针
    input      [ADDRSIZE  :0] rq2_wptr, //同步后的写指针
    input                     rinc, rclk, rrst_n
);
  reg  [ADDRSIZE:0] rbin;
  wire [ADDRSIZE:0] rgraynext, rbinnext;
 // GRAYSTYLE2 pointer
 //将二进制的读指针与格雷码进制的读指针同步
  always @(posedge rclk or negedge rrst_n) 
      if (!rrst_n) begin
          rbin <= 0;
          rptr <= 0;
      end  
      else begin        
          rbin<=rbinnext; //直接作为存储实体的地址
          rptr<=rgraynext;//输出到 sync_r2w.v模块,被同步到 wrclk 时钟域
      end
  // Memory read-address pointer (okay to use binary to address memory)
  assign raddr     = rbin[ADDRSIZE-1:0]; //直接作为存储实体的地址,比如连接到RAM存储实体的读地址端。
  assign rbinnext  = rbin + (rinc & ~rempty); //不空且有读请求的时候读指针加1
  assign rgraynext = (rbinnext>>1) ^ rbinnext; //将二进制的读指针转为格雷码
  // FIFO empty when the next rptr == synchronized wptr or on reset 
  assign rempty_val = (rgraynext == rq2_wptr); //当读指针等于同步后的写指针,则为空。
  always @(posedge rclk or negedge rrst_n) 
      if (!rrst_n)
          rempty <= 1'b1; 
      else     
          rempty <= rempty_val;
 
endmodule
View Code

6、wptr_full.v 将  sync_r2w.v 同步后的读指针与wclk 时钟域的写指针进行比较生成写满信号

module wptr_full
#
首页 上一页 1 2 3 4 下一页 尾页 3/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇IC系统组成概论 下一篇Verilog学习笔记简单功能实现(六..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目