zoukankan      html  css  js  c++  java
  • 异步FIFO代码

    module asyn_fifo#(
    parameter DATA_WIDTH=8,
    parameter ADDR_WIDTH=3,  //地址位宽为log2(deepth)
    parameter DATA_DEPTH=1<<ADDR_WIDTH
    )
    (
    input rst_n,   //复位信号输入(应该对复位进行处理同步,个人认为,参考xilinx fifo IP同步stage)
    input rd_clk,  //读取时钟
    input wr_clk, //写时钟
    input rd_en,  //读取使能
    input wr_en,  //写使能
    input [DATA_WIDTH-1:0] data_w, //写入数据
    output reg [DATA_WIDTH-1:0]data_r,  //读出数据
    output reg full,    //满标志
    output reg empty    //空标志
    ); 
    //定义DATA_DEPTH个数据宽度为DATA_WIDTH的数据
    reg [DATA_WIDTH-1:0]mem[DATA_DEPTH-1:0];
    //二进制格式下的写地址,二进制的地址宽度为3 写地址指针
    reg [ADDR_WIDTH:0]wr_addr_bin;  
    //二进制格式下的读地址,二进制的地址宽度为3(深度以2为底的对数)
    reg [ADDR_WIDTH:0]rd_addr_bin;
    
    //gray code 表示的地址
    reg [ADDR_WIDTH:0]syn_wr_addr0_gray;  //格雷码写地址0
    reg [ADDR_WIDTH:0]syn_wr_addr1_gray;  //格雷码写地址1
    reg [ADDR_WIDTH:0]syn_wr_addr2_gray;  //格雷码写地址2
    
    reg [ADDR_WIDTH:0]syn_rd_addr0_gray;  //格雷码读地址0
    reg [ADDR_WIDTH:0]syn_rd_addr1_gray;  //格雷码读地址1
    reg [ADDR_WIDTH:0]syn_rd_addr2_gray;  //格雷码读地址2
    
    wire [ADDR_WIDTH-1:0] fifo_enter_addr;  //fifo传入的地址
    
    wire [ADDR_WIDTH-1:0]fifo_exit_addr;    //fifo输出的地址
    /*
    关于为什么binary下的地址宽度大一位,是因为要转化为格雷码,作用是为了空满比较
    */
    wire [ADDR_WIDTH:0] wr_nextaddr_bin;
    wire [ADDR_WIDTH:0] rd_nextaddr_bin;
    wire [ADDR_WIDTH:0] wr_nextaddr_gray;
    wire [ADDR_WIDTH:0] rd_nextaddr_gray;
    
    wire asyn_full;   //满标志信号,由于写入数据导致,属于写时钟域
    wire asyn_empty;  //空标志信号,由于读取数据导致,属于读时钟域
    
    //fifo数据的写入和读出地址,格雷码的最高位表示第二轮
    assign fifo_enter_addr = wr_addr_bin[ADDR_WIDTH-1:0];  //写入数据到fifo的写指针指向的地址
    assign fifo_exit_addr  = rd_addr_bin[ADDR_WIDTH-1:0];  //从fifo中读取数据指针指向的地址
    
    //写入数据
    always@(posedge wr_clk or negedge rst_n)
    if(~rst_n)
    begin   //复位将fifo清零
     integer i;
     for(i=0;i<DATA_DEPTH;i=i+1)
      mem[i]<={DATA_DEPTH{1'b0}}; 
    end 
    else if(wr_en&(~full))  //写使能且fifo未满
     mem[fifo_enter_addr]<=data_w;   //将数据写入到mem
    else  
     mem[fifo_enter_addr]<=mem[fifo_enter_addr];
     
    //数据读取
    always@(posedge rd_clk or negedge rst_n)
    if(~rst_n)
     data_r<={DATA_DEPTH{1'b0}};
    else 
     data_r<=mem[fifo_exit_addr]; 
     
    //fifo读写地址生成器,二进制转格雷码,
    //在fifo未满且写请求时,将写地址自动加一(binary)
    assign wr_nextaddr_bin= (wr_en&(~full))  ?  fifo_enter_addr+1'b1: fifo_enter_addr;
    assign rd_nextaddr_bin= (rd_en&(~empty)) ?  fifo_exit_addr+1'b1 : fifo_exit_addr ;
    //convert binary to gray code 就是二进制地址右移一位之后与原地址异或
    assign wr_nextaddr_gray=(wr_nextaddr_bin>>1)^wr_nextaddr_bin;
    assign rd_nextaddr_gray=(rd_nextaddr_bin>>1)^rd_nextaddr_bin;
    
    always@(posedge wr_clk or negedge rst_n)
    if(~rst_n)
    begin
      wr_addr_bin<=0;
      syn_wr_addr0_gray<=0;
    end 
    else 
    begin
     wr_addr_bin<=wr_nextaddr_bin;  //下一个地址赋值给写数据地址
     syn_wr_addr0_gray<=wr_nextaddr_gray;  //将下一个地址的格雷码赋值给syn_wr_addr0_gray进行同步寄存
    end 
    
    always@(posedge rd_clk or negedge rst_n)
    if(~rst_n)
    begin
     rd_addr_bin<=0;
     syn_rd_addr0_gray<=0;
    end 
    else begin
     rd_addr_bin<=rd_nextaddr_bin;
     syn_rd_addr0_gray<=rd_nextaddr_gray;
    end 
    
    /*
    对格雷码进行同步:
     1、将格雷码写地址同步到读时钟域,用于空判断
     2、将格雷码读地址同步到写时钟域,用于满判断
    */
    always@(posedge rd_clk or negedge rst_n)
    if(~rst_n)
    begin
     syn_wr_addr1_gray<=0;
     syn_wr_addr2_gray<=0;
    end 
    else begin
     syn_wr_addr1_gray<=syn_wr_addr0_gray;
     syn_wr_addr2_gray<=syn_wr_addr1_gray;
    end 
    
    always@(posedge wr_clk or negedge rst_n )
    if(~rst_n)
    begin
     syn_rd_addr1_gray<=0;
     syn_rd_addr2_gray<=0;
    end 
    else begin
     syn_rd_addr1_gray<=syn_rd_addr0_gray;
     syn_rd_addr2_gray<=syn_rd_addr1_gray;
    end 
    
    //将产生的同步后的地址进行比较
    assign asyn_empty = ( rd_nextaddr_gray==syn_wr_addr2_gray );
    //格雷码的高两位相反,其余位相同时,表示fifo满
    assign asyn_full  = ( wr_nextaddr_gray=={ ~{syn_rd_addr2_gray[ADDR_WIDTH:ADDR_WIDTH-1]},syn_rd_addr2_gray[ADDR_WIDTH-2:0] } );
    
    always@(posedge wr_clk or negedge  rst_n )
    if(~rst_n )
     full<=1'b0;
    else
     full<=asyn_full;
     
    always@(posedge rd_clk or negedge rst_n )
    if(~rst_n)
     empty<=1'b1;
    else 
     empty<=asyn_empty;
    endmodule
  • 相关阅读:
    appium 滑动屏幕
    appium 根据属性名获取属性值 特殊情况 element.get_attribute('name')相当于element.get_attribute('content-desc')或element.get_attribute('text')
    appium 获取元素的内容 获取元素的位置和大小
    appium 点击 输入 清空 ;异常处理 当输入中文 ,没有效果时,需要前置代码里加两行代码
    appium 隐式 查找元素
    appium 过滤出带有‘设’的文本
    appium 批量找元素
    通过id class xpath 找元素
    随笔
    spring 事务传播特性
  • 原文地址:https://www.cnblogs.com/luxinshuo/p/13406699.html
Copyright © 2011-2022 走看看