赞
踩
全同步设计:1个时钟
全异步设计:没有时钟(存在少)
全局异步,局部同步设计:不可避免,单一时钟不能满足设计需求
多时钟域设计不可避免问题:亚稳态,同步失败
同步化:同步器;保持寄存器和握手(效率不高);异步FIFO设计;
两级寄存器
一级寄存概率的平方,虽然两级并不能完全消除亚稳态危害,但是提高了可靠性,减少其发生概率
分类:电平同步器,边沿检测同步器,脉冲同步器
电平同步器(打两拍)
从Clock1到Clock2的跨时钟,触发器之间无组合逻辑,电平同步一般只适用于频率一样,相位上没有同步,但是两者频率不一样,就不能使用。如果是慢时钟到快时钟域,会出现数据重复采样。
边沿检测同步器(慢到快)
将慢时钟域的脉冲同步到快时钟域,快时钟采集慢数据,会出现数据重复,将数据变化转为一个脉冲,并进行门运算,去除重复数据
脉冲同步器(快到慢)
慢到快只需要考虑亚稳态问题,快到慢要考虑采样速率,保证数据不丢失,这个问题称为信号宽度问题。一般安全的宽度是快时钟域的信号宽度必须是慢时钟域周期的1.5倍以上,也就是持续三个时钟沿以上。整个设计包括脉冲电平检测、双触发器同步、边沿检测三部分。
多bit信号跨时钟域传输
b_load和b_en各自经过同步器延时之后,产生不同步的问题,解决方案将两路合成一路,再经过同步器,分成两路信号控制置位和使能端
总线信号的跨时钟域
正确方法:保持寄存器加握手信号;异步FIFO设计
异步FIFO:读时钟和写时钟为独立时钟,思想:隔离时钟域,匹配读写速度;
异步FIFO介绍
FIFO(First In First out)先进先出,它是一种存储器结构,能读写数据,所以有双口RAM作为存储数据的单元,在不同时钟域传输数据,使用异步FIFO来作为传输的缓冲区,既可以保证异步时钟数据传输的时序要求变得宽松,也提高传输效率。
FIFO写满和读空标志的产生
读写指针比较产生,同步FIFO直接把读写指针比较或者运算产生,而异步FIFO由于读写指针不同时钟域,比较前指针必须同步化,由于二进制的指针会出现多位同时跳变,直接由同步器进行同步化会有问题
判断存储器(RAM)写入写出的状态,需要有写满判断(wfull信号),和读空判断(empty信号),如何得到写满和读空信号?通过比较读写地址(告诉我们数据数据位置)、指针(四个信号 waddr,wptr,raddr,rptr)来判断此刻FIFO的写满和读空。
判断中涉及到w2r和r2w时钟域问题(2级寄存器同步)
对于异步FIFO,读写为不同时钟,如果直接采样,就会有亚稳态问题,比如写地址从00111改变01000的时候,读时钟恰好采样,除了最高位,其他4为有可能出现亚稳态,也有可能同步到错误的地址,这就是需要引入格雷码的原因。
设定地址指针位数时需要+1位,如16个数组需要4位,地址指针位数为5,
当最高位和次高位相同,其余位相同则认为是读空;
当最高位和次高位不同,其余位相同则认为是写满;
下面是用Verilog HDL设计深度为256(存储器可以写入256个数据),位宽为16(每个数据的宽度为16)的FIFO
module asyn_fifo #( parameter data_width = 16, parameter data_depth = 8, parameter ram_depth = 256 ) ( input rst_n, input wr_clk, input wr_en, input [data_width-1:0] data_in, output full, input rd_clk, input rd_en, input reg [data_width-1:0] data_out, output empty ); reg [data_depth-1:0] wr_adr; reg [data_depth-1:0] rd_adr; reg [data_depth:0] wr_adr_ptr; reg [data_depth:0] rd_adr_ptr; wire [data_depth:0] wr_adr_gray; reg [data_depth:0] wr_adr_gray1; reg [data_depth:0] wr_adr_gray2; wire [data_depth:0] rd_adr_gray; reg [data_depth:0] rd_adr_gray1; reg [data_depth:0] rd_adr_gray2; //dual port ram -write and read assign wr_adr = wr_adr_ptr[data_depth-1:0]; assign rd_adr = rd_adr_ptr[data_depth-1:0]; integer i; reg [data_width-1:0] ram_fifo [ram_depth-1:0]; always@(posedge wr_clk or negedge rst_n)begin if(!rst_n)begin for(i=0;i<ram_depth;i++) ram_fifo[i] <= 'd0;//全部清零 end else if(wr_en && (~full)) ram_fifo[wr_adr] <= data_in; else ram_fifo[wr_adr] <= ram_fifo[wr_adr]; end always@(posedge rd_clk or negedge rst_n)begin if(!rst_n) data_out <= 'd0; end else if(rd_en && (~empty)) data_out <= ram_fifo[rd_adr]; else data_out <= 'd0; end //wr_adr_ptr ++ and rd_adr_ptr ++ always@(posedge wr_clk or negedge rst_n)begin if(!rst_n) wr_adr_ptr <= 'd0; else if(wr_en && (~full)) wr_adr_ptr <= wr_adr_ptr + 1'b1; else wr_adr_ptr <= wr_adr_ptr; end always@(posedge rd_clk or negedge rst_n)begin if(!rst_n) rd_adr_ptr <= 'd0; end else if(rd_en && (~empty)) rd_adr_ptr <= rd_adr_ptr + 1'b1 ; else rd_adr_ptr <= rd_adr_ptr; end //binary to gray assign wr_adr_gray = (wr_adr_ptr >> 1) ^ wr_adr_ptr; assign rd_adr_gray = (rd_adr_ptr >> 1) ^ rd_adr_ptr; //gray cdc compare always@(posedge wr_clk or negedge rst_n)begin if(!rst_n)begin wr_adr_gray1 <= 'd0; wr_adr_gray2 <= 'd0; end else begin wr_adr_gray1 <= wr_adr_gray; wr_adr_gray2 <= wr_adr_gray1; end end always@(posedge rd_clk or negedge rst_n)begin if(!rst_n)begin rd_adr_gray1 <= 'd0; rd_adr_gray2 <= 'd0; end else begin rd_adr_gray1 <= rd_adr_gray; rd_adr_gray2 <= rd_adr_gray1; end end assign empty = (rd_adr_gray == wr_adr_gray2)?1'b1:1'b0; assign full=(wr_adr_gray[data_depth:data_depth-1] !=rd_adr_gray2[data_depth:data_depth-1])&&(wr_adr_gray[data_depth:data_depth-2:0] ==rd_adr_gray2[data_depth-2:0]); endmodule
测试代码如下
'timescale 1us/1us module asyn_fifo_tb; reg rst_n; reg wr_clk; reg wr_en; reg [15:0] data_in; wire full; reg rd_clk; reg rd_en; wire [15:0] data_out; wire empty; asyn_fifo asyn_fifo_inst ( .rst_n (rst_n), .wr_clk (wr_clk), .wr_en (wr_en), .data_in (data_in), .full (full), .rd_clk (rd_clk), .rd_en (rd_en), data_out (data_out), .empty (empty) ); initial wr_clk = 0; always#10 wr_clk=~wr_clk; initial rd_clk = 0; always#30 rd_clk=~rd_clk; always@(posedge wr_clk or negedge rst_n)begin if(!rst_n) data_in <= '0d0; else if(wr_en) data_in <=data_in + 1'b1; else data_in <= data_in; end initial begin rst_n = 0; wr_en = 0; rd_en = 0; #200; rst_n = 1; wr_en = 1; #20000; wr_en = 0; rd_en = 1; #20000; rd_en = 0; $stop; end endmodule
仿真测试结果如下图所示
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。