异步时钟域的信号通信问题

随着信息技术的飞速发展,特别是在二十世纪90年代以后,美国在南斯拉夫战争和两次海湾战争中成功地运用了电子战、信息战,以及近年来我国在航天航空事业方 面的高速发展,使我国开始重视和发展信息技术。与此同时对高速、大容量、高可靠性的静态存储器的需求越来越多,对军用的数据存储器的设计也提出了更高的要 求。目前军用计算机传输数据的最快方式——DMA方式的传输速率最大也只是在5Mbps以下。对于几十Mbps的超高速采样速率,往往是上一次数据还没有 被计算机读取,下一次的采集过程就结束了。因此采用传统的计算机传输处理数据的方法,显然会造成数据的丢失与混乱。所以对于快速采集,慢速处理的系统必然 要用到缓存。本文就是针对数据存储器FIFO解决亚稳态问题的设计,经过对不同方法的比较,设计了一种新型的逻辑标志的同步电路。

1亚稳态问题的解决方案
1.1问题的产生

    在数字集成电路中,触发器要满足setup/hold的时间要求。当一个信号被寄存器锁存时,如果信号和时钟之间不满足这个要求,Q端的值是不确定的,并 且在未知的时刻会固定到高电平或低电平,这个过程称为亚稳态,如图1所示。图中clka和clkb即为异步时钟,亚稳态必定会发生在异步时钟电路中。在图 1的异步电路中,电路外部的输入和内部的时钟之间是毫无时间关系的,因此setup/hold冲突是必然的;同在电路内部的两个没有关系的时钟域之间的信 号传递,也必然会导致setup/hold冲突。亚稳态虽然是不可避免的,但采用下面几种设计方法可以将其发生的概率降低到一个可以接受的程度。
异步时钟和亚稳态 
1.2 常见的解决方法
1.2.1格雷码编码法
    写地址/读地址采用格雷码。由实践可知,同步多个异步输入信号出现亚稳态的概率远远大于同步一个异步信号的概率。对于多个触发器的输出所组成的写地址/读 地址可以采用格雷码。由于格雷码每次只变化一位,因此采用格雷码可以很好地节约功耗,有效地减少亚稳态的产生,特别是在地址位比较多的情况下可以更好地解 决亚稳态的问题。
    格雷码是对二进制地址输出进行转换,下面是四位代码之间转换的逻辑表达式:
B码转G码的逻辑表达式:G码转B码的逻辑表达式:
B4=G4                                 G4=B4
B3=B4?G3                        G3=B4?B3
B2=B3?G2                        G2=B3?B2
B1=B2?G1                        G1=B2?B1
    但采用格雷码编码法需要在地址位的每一位增加一级的异或门,这样在计数比较前增大了延时和版图面积。同时在地址分配到其他逻辑单元前要把格雷码转换成二进制代码,这同样也会增大版图设计面积和延时。
1.2.2 双触发器法
    采用触发器来同步异步输入信号,如图2中的两级触发器可以将出现亚稳态的概率降低到一个很小的程度。由于增加了一级触发器,这样在最后的输出就延迟了一个 时钟,使前一个时钟产生的数据被b_clk连续锁存两次。虽然第一次锁存产生亚稳态,但经过一段时间的延时可以有效地解决这个问题。这种方法同时带来了对 输入信号的一级延时,需要在设计时钟的时候加以注意。
 
    虽然两级触发器能有效地抑制亚稳态,但增加了一级的D触发器,这和格雷码编码法一样会增加版图面积。这种方法在clka与clkb的采样周期相差不大的情况下比较适合。
1.2.3 结绳法
    如图3所示,如果aclk的频率比bclk频率高,将可能会出现因为adat变化太快而使balk无法采到的问题,即在信号从快时钟域向慢时钟域过渡时, 如果信号变化太快,慢时钟将可能无法对该信号进行正确采样,即采样失败。所以在使用双锁存器法时,应该使原始信号保持足够长的时间,以便另一个时钟域的锁 存器对其进行正确的采样。
 
    对上述问题,一般采用“结绳法”的设计方法,将慢时钟周期信号通过分频的方式将其周期增长,经过双锁存采样以后再使其恢复原来的时钟周期。即用“结绳”将 信号延长,用“同步”实现双latch采样,用“解绳”还原为原来的时钟,保证另一个时钟域也可以正确采样,而接收方用相反的流程送回响应信号。
    “结绳法” 可以解决快时钟域向慢时钟域过渡的问题,适用的范围也很广。但是“结绳法”实现较为复杂,特别是其频率不高,所以在对设计性能要求较高的场合应该慎用。

 

2 基于异步比较FIFO 逻辑标志的产生
2.1 设计思想

    异步FIFO可以很好地解决时钟速度相差悬殊的时钟间的数据传输问题。异步FIFO存储器在结构上可划分为存储阵列和外围电路两大部分,它由几个主要模块 组成:存储单元RAM、写控制逻辑、读控制逻辑、标志逻辑、扩展逻辑、复位逻辑以及并/串转换逻辑。这里主要考虑产生空、满标志的同步。
    标志逻辑是用以产生反映器件内部RAM 阵列占用情况的状态标志信号,使系统可以及时采取措施以免数据溢出。在FIFO中标志位的产生是关键的一步,如果能够及时判断出每一个时钟下写入和读出的 位置,就可以防止产生误操作,做到写满不再写、读空则停止读。在异步FIFO中的标志位主要包括空标志、满标志、半满标志和将近满、将近空标志。异步 FIFO逻辑框图如图4所示。
 
2.2 标志位的产生
2.2.1空、满标志位的产生标志逻辑
    满标志是为了防止FIFO在满状态时被写,空标志是为了防止FIFO在空状态时被读。对于异步FIFO 而言,数据是由某一个时钟域的控制信号写入FIFO,而由另一个时钟域的控制信号将数据读出FIFO。也就是说,读写指针的变化动作是由不同的时钟产生 的。因此,对FIFO空或满的判断是跨时钟域的。如何根据异步的指针信号对FIFO的满状态或空状态进行正确的判断是研究的重点之一。
    当读指针和写指针相等也就是指向同一个内存位置时,FIFO可能处于满或空两种状态。可以通过不同的方法判断或区分FIFO究竟是处于满状态还是空状态, 也就是说究竟是写指针从后赶上了读指针,还是读指针从后赶上了写指针。本文采用设置一个额外的状态位的方法,即指针由它的地址位以及状态位组成。地址位随 着相应的操作递增,指针由内存的最后位置返回到初始位置时,状态位取反。因此,当读写指针的地址位和状态位全部吻合的时候,读写指针经历了相同次数的循环 移动,也就是说,FIFO处于空状态;如果读写指针的地址位相同而状态位相反,写指针比读指针多循环一次,标志FIFO处于满状态。
2.2.2异步比较FIFO逻辑标志与时钟的同步
    一般的异步FIFO是先将读地址与写地址同步以后(以上提到的方法)再进行比较,这种方法一般效率不高,不能很好地节省制版面积。本文采用一种异步比较法。能够有效地解决这一问题。目前IDT公司的系列产品一般都采用这种异步比较法。
    在异步FIFO中,由FIFO读时钟产生读地址rptr,写时钟产生写地址wptr。当rptr与wptr进行异步比较时,由于rptr的变化 (assert)产生aempty_n(FIFO空标志),即aempty_n的下降沿是与rptr同属于一个时钟域的;同理,由于wptr的变化 (assert)使aempty_n无效(de-assert),即aempty_n的上升沿是与wptr同属于一个时钟域的。异步比较的时钟域如图5所 示。
 
    因此可以利用上述的理论基础来实现从aempty_n到empty的过渡。其中,empty是属于rclk时钟域的。由于aempty_n的下降沿是属于 rclk时钟域的,所以可以用它来作为empty的复位信号;而aempty_n的上升沿是属于welk时钟域的,因此可以用双锁存器法将其过渡到 relk时钟域,最后得到的empty信号就属于rclk时钟域。同理可以得到full信号。控制信号同步如图6所示。
 
    如图6所示,异步比较法的关键是用异步比较的结果—— 信号的下降沿作为最终比较结果的复位信号,而其上升沿则用传统的双锁存器法进行同步,最终得到的信号的上升沿与下降沿都是属于同一个时钟域。同时增加的两 级锁存器也增加了一个时钟周期的延时输出,这样在满有效状态下,同时来自读写时钟的读写指令存在潜在的亚稳态问题就可以避免。在与传统的先将地址信号同步 然后进行同步比较的方法相比,异步比较法简单、高效、节省版图面积,而且实现起来更简单。

2.2.3 半满、将近满、将近空的产生
    半满、将近满和将近空是对FIFO芯片容量的一种提前判断。半满标志是一个双用输出端口,在单片模式下,当扩展输入端接地时,这个端口就作为半满标志。在字扩展模式下,该端口为扩展输出端。
    以2K字容量的FIFO为例来说明异步FIFO的半满与将近满。如图7所示:半满是指当写指针的位置与读指针的位置相比较,如果w_point和 r_point距离超过总容量的一半,那么输出半满为有效输出。当2K字的FIFO半满有效时,标志w_point地址减去r_point地址的范围在 1K~2K字之间。在具体电路实现上,2K字的FIFO计数器的输出共有12个地址线,其中第12根是为了判断满和空标志用的。所以判断半满主要是对第 11根地址的读和写计数输出相同情况和不同情况下进行判断。
    将近空和将近满一般是读和写总容量相差在0~1/8和7/8~1之间,也有的设计是相差在几个比特范围之内。这个电路一般用的是比较器判断。在2K字的 FIFO中一般把后高4位放在一起,先判断正在读的高4位和写的高4位的大小关系,再对应判断其他低位的大小关系,看是否符合设计要求。当高4位写地址减 去读地址小于1、其低位读地址大于写地址时,产生将近空。同样,将近满也是先判断:若高4位写地址减去读地址大于15、低位读地址大于写地址时,将近满输 出有效。图7为设计2K字的FIFO将近空和半满标志位在Candenee软件下的仿真结果图。
 
    对于标志信号都是采用异步比较输出下降沿作为最终比较结果的复位信号,而其上升沿则采用传统的双锁存器法进行同步的方法。此外,在FIFO 的设计中还要考虑写入和读出的位宽是否相等,在不相等的情况下要设计输入输出的自动匹配,使输出位宽等于输入位宽。同时为FIFO 的深度扩展和宽度扩展设计扩展逻辑,以适应多位宽和大容量的要求。
    一般的异步FIFO通常所采用的是先将读、写地址同步后比较的方法,而本文提出的异步比较以后利用触发器同步的方法相对前者可以减少延时,从而使系统有更 充裕的时间去进行读、写操作,有利于提高时钟频率,减少逻辑器件个数,从根本上节约了版图面积。因此在以面积决定成本的今天,对FIFO标志位的产生采用 异步比较法具有极其重要的现实意义。

 

这里重点说一下结绳法,就是握手法,原理如下:在具体 实现中,假设req、ack、data总线在初始化时都处于无效状态,发送域先把数据放入总线,随后发送有效的req信号给接收域。接收域在检测到有效的 req信号后 锁存数据总线,然后回送一个有效的ack信号表示读取完成应答。发送域在检测到有效ack信号后撤销当前的req信号,接收域在检测到req撤销后也相应 撤销ack信号,此时完成一次正常 握手通信。此后,发送域可以继续开始下一次握手通信,如此循环。该方式能够使接收到的数据稳定可靠,有效的避免了亚稳态的出现,但控制信号握手检测会消耗通信双方较多的时间。




上面这张图不是配套的,我理解vld这个就是由同时钟域的脉冲转换成电平的一个信号,所以基本原理还是很明白的。

以下附上别人的代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//接收域应答信号ack采用两级寄存器同步,便于时序收敛
always @ (negedge rst_n or posedge t_clk)
begin
   if (rst_n == 1'b0)
   begin
      ack_reg1 <= 1'b0;
      ack_reg2 <= 1'b0;
   end
   else
   begin
      ack_reg1 <= ack;
      ack_reg2 <= ack_reg1;
   end
end
  
//数据处理状态机
always @ (negedge rst_n or posedge t_clk)
begin
   if (rst_n == 1'b0)
   begin
      data_buf <= 'b0;
      tr_state <= TR_IDLE;
      TR_MEM_Addr <= 0;
   end
   else
      case (tr_state)
      TR_IDLE :     //初始化状态     
      begin
         req <= 1'b0;
         TR_MEM_Addr <= 0;
         tr_state <= SND_DATA_REQ;
      end
      SND_DATA_REQ: //送数据到总线上和发送请求信号    
      begin
         data_buf <= TR_MEM[TR_MEM_Addr];
         req <= 1'b1; //发送请求信号,请求信号为高,表示请求接收
         TR_MEM_Addr <= TR_MEM_Addr + 1;
         tr_state <= CHK_ACK_ACTIVE;
      end
      CHK_ACK_ACTIVE : //检测应答信号为高,释放请求信号
      begin
         if (ack_reg2 == 1'b1)  //便于时序收敛
         begin
            req <= 1'b0;        //释放请求信号
            tr_state <= CHK_COMM_END;
         end
         else
            tr_state <= CHK_ACK_ACTIVE;
      end
      CHK_COMM_END :   //检测握手通信结束,如果应答信号被释放,一次握手结束                   
      begin
         if (ack_reg2 == 1'b0)
            tr_state <= SND_DATA_REQ;
         else
            tr_state <= CHK_COMM_END;
      end
      default : tr_state <= TR_IDLE;
        
   endcase
end
  
assign dout = data_buf;
  
//接收端代码:
//发送域请求信号req采用两级寄存器同步,便于时序收敛
always @ (negedge rst_n or posedge r_clk)
begin
   if (rst_n == 1'b0)
   begin
      req_reg1 <= 1'b0;
      req_reg2 <= 1'b0;
   end
   else
   begin
      req_reg1 <= req;
      req_reg2 <= req_reg1;
   end
end
  
//数据处理状态机
always @ (negedge rst_n or posedge r_clk)
begin
   if (rst_n == 1'b0)
   begin
      re_state <= RE_IDLE;
      ack <= 1'b0;
      RE_MEM_Addr <= 0;
   end
   else
      case (re_state)
      RE_IDLE :           //初始化状态
      begin
         RE_MEM_Addr <= 0;
         re_state <= CHK_REQ_ACTIVE;
      end
      CHK_REQ_ACTIVE :    //检测发送端的数据发送请求信号
      begin
         if (req_reg2 == 1'b1)     //如果有请求信号,接收数据
         begin
            RE_MEM[RE_MEM_Addr] <= din; //接收数据存放到MEM
            ack <= 1'b1; //检测到请求信号,发送接收端应答信号
            RE_MEM_Addr <= RE_MEM_Addr + 1;   //接收数据存储器地址累加
            re_state <= CHK_REQ_RELEASE;
         end
         else
            re_state <= CHK_REQ_ACTIVE;
      end
      CHK_REQ_RELEASE :     //检测请求信号释放,释放应答信号
      begin
         if (req_reg2 == 1'b0)
         begin
            ack <= 1'b0;  //释放应答信号,一次握手通信结束
            re_state <= CHK_REQ_ACTIVE;
         end
         else
            re_state <= CHK_REQ_RELEASE;
      end
      default : re_state <= RE_IDLE;
   endcase
end

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值