数字IC系统RTL实现ppt课件.ppt

上传人:小飞机 文档编号:1341534 上传时间:2022-11-11 格式:PPT 页数:170 大小:2.05MB
返回 下载 相关 举报
数字IC系统RTL实现ppt课件.ppt_第1页
第1页 / 共170页
数字IC系统RTL实现ppt课件.ppt_第2页
第2页 / 共170页
数字IC系统RTL实现ppt课件.ppt_第3页
第3页 / 共170页
数字IC系统RTL实现ppt课件.ppt_第4页
第4页 / 共170页
数字IC系统RTL实现ppt课件.ppt_第5页
第5页 / 共170页
点击查看更多>>
资源描述

《数字IC系统RTL实现ppt课件.ppt》由会员分享,可在线阅读,更多相关《数字IC系统RTL实现ppt课件.ppt(170页珍藏版)》请在三一办公上搜索。

1、第三章数字IC系统的逻辑设计RTL实现,3.1 RTL设计基础3.2 RTL设计指南(Verilog),3.1RTL设计基础3.1.1同步电路设计要求RTL设计都采用同步电路设计方式。 了解同步电路设计要求, 是进行RTL设计的第一步。 图3.1给出了一个同步电路的示例。,图 3.1同步电路示例,组合逻辑实现设计所需的功能。 例如, 图中的组合逻辑可能是乘法、 编码器等复杂的逻辑。 寄存器用于暂存数据, 它由时钟控制, 只有当时钟进行有效跳变时, 才将新的数据锁存起来, 否则数据一直保持原值。 时钟相当于同步电路中的“指挥”。 对于图3.1所示的例子, 假设该电路都采用时钟的上升沿进行锁存,

2、时钟周期为8 ns。 从0时刻开始, 时钟变为高电平。,第一个寄存器中, 经过很短的时间(例如0.2 ns)到达Ri的Q端, 再从Q端送到组合逻辑的输入, 跟其他的信号一起进行逻辑操作。 这种逻辑操作必须在规定的时间内完成(满足时钟周期的要求)。 假设组合逻辑的结果在4 ns后稳定下来,则在4.2 ns这一时刻,Rf输入端的数据会稳定下来。 这时候电路暂时“静止下来”。 然后到8 ns这一时刻, 第二个时钟沿到来, 组合逻辑的输出被第二个寄存器锁存, 与此同时, 新的数据会被送到第一个寄存器。 这个过程会一直持续下去。,由此可见, 在图3.1所示的电路中, 时钟保证了电路能按照需要动作, 而不

3、是杂乱无章地各行其是。 下面先简单介绍一下时钟。 时钟一般由晶振产生, 或者由外部输入, 如果需要, 还需要用锁相环进行倍频、 移相等操作。 实际的时钟不可能是理想的, 也就是说, 时钟不可能一直保持同一频率, 时钟边沿不可以“直上直下”。 设计者要根据芯片的要求对时钟提出要求, 并根据时钟规范进行设计。,例如, 假设需要将时钟域A中的数据传递到时钟域B。 数据由clka生成, 被clkb采样。 clka与clkb是异步时钟, 周期都是10 ns, 时钟频率最大为210-4。 这时候我们需要设计一个异步FIFO。 这个FIFO的写入时钟为clka, 读出时钟为clkb。 假设每次传送的最大包为

4、10 KB, FIFO宽度为8位, 那么这个FIFO的深度应该是多少呢?考虑最坏情形, 时钟clka与clkb最大相差为410-4。,FIFO的读指针与写指针至少要相差: 410-410 K4。 这样, FIFO的深度至少为8字节。 接下来, 我们对时序电路中最关键的组成部分寄存器进行说明。 一个寄存器的结构如图3.2所示。,图 3.2寄存器的结构,图 3.3寄存器的功能示意图,寄存器的功能如图3.3所示。,由图3.3可知, 该寄存器在时钟的跳变沿锁存数据, 然后数据会一直保持, 直到下一个跳变沿。 寄存器要正常工作, 必须保证D端数据的变化与时钟的有效沿不能距离太近, 否则可能会锁存错误的数

5、据。 在综合库中, 规定了数据变化端跟时钟跳变沿最短的时间要求, 称为建立时间约束与保持时间约束。建立时间与保持时间是时序电路设计中最重要的两个概念。 建立时间规定, 在时钟沿到达前的某段时间内, 数据必须稳定; 保持时间定义了在时钟沿之后的某段时间之后, 数据才能发生变化。 图3.4给出了建立时间与保持时间的示例。,图 3.4建立时间与保持时间,一般来说, 设计中路径的延时过大, 超出设计要求, 会引起建立时间的违例。 如果设计中时钟树做得不够好, 时钟偏移(skew)过大, 则会引起保持时间违例。 对于一个寄存器来说, 除了数据端与时钟端有时序要求, 异步复位端与时钟端之间也有时序要求。

6、假设一个寄存器是异步复位的, 复位信号低电平有效。 当复位信号为低电平时, 寄存器被初始化。,当复位信号跳高时, 寄存器在时钟跳变沿锁存新的数据。 如果异步复位信号跳高的时刻距离时钟有效沿太近, 那么寄存器可能继续保持复位状态, 也可能会锁存新数据, 这样, 就可能发生锁存错误。 因此, 有必要定义时钟有效沿与异步复位无效沿之间的时序要求, 这就是recovery/removal的时序要求, 如图3.5所示。,图 3.5 recovery/removal,寄存器中建立时间/保持时间、 recovery/removal的时序要求, 对设计的最大组合逻辑延时、 时钟树的构造、 复位树的构造都提出了

7、要求。 复位树、 时钟树一般由后端工具进行处理。 对RTL设计者来说, 最需关注的是建立时间的问题。 设计中的时序违例通过静态时序分析工具可以检查出来。 本书第7章对静态时序分析进行了说明, 这里不再详述。 ,3.1.2RTL设计步骤如何进行RTL设计?RTL设计并非仅仅编写代码那么简单。 在RTL设计前, 要进行如下工作: (1) 仔细阅读设计规范, 了解设计的要求, 例如芯片的I/O采用何种标准, 有多少PIN脚, 采用何种封装形式, 时序要求是多少, 是否需要与其他已有的产品兼容等, 规范越清楚越好。 ,(2) 了解芯片中是否用到其他IP, 这些IP是否满足功能与性能的要求, 这些IP是

8、否经过了验证, 如何与这些IP进行接口, 这些IP是软核还是硬核。(3) 了解芯片是否需要与其他产品进行兼容, 包括与其他厂商的芯片进行兼容, 是否与以前的产品兼容。 兼容性会影响到芯片的功能、 寄存器设置、 PIN脚分配等。 (4)了解流片所用的工艺及综合库。 高水平的RTL设计者必然熟悉综合库, 知道综合库中各单元能够提供怎样的性能, 从而了解在设计中的一个路径上, 最多可以放多少逻辑。,例如, 一个设计要求能运行在时钟频率100 MHz, 而所用的综合库中一个二输入与非门的延迟大约为0. 2 ns, 则一条路径上差不多可以放50个与非门。 有了这种知识, 设计者可以写出更为合理的代码。

9、特别是对于数据通路设计, 对综合库的了解是很有必要的。 (5)了解芯片的外部接口。 例如, 与模拟部分接口是怎么样的, 接口信号的确切含义是什么, 系统是否有PCI或AGP之类的高速接口, 这些接口需要自己来实现还是由IP来实现。,(6) 了解芯片的时钟。 要了解芯片中有多少个时钟, 每个时钟的用途是什么, 这些时钟来自锁相环还是由其他芯片提供, 这些时钟有无相位关系, 频率是多少以及时钟的偏差有多大, 芯片中是否有分频时钟。(7) 了解芯片对功耗的要求, 以决定是否采用低功耗设计技术, 以及采用何种低功耗设计技术。 低功耗设计技术的基本思想是尽量减少设计中的节点的翻转, 例如可以采用并行计算

10、来降低时钟频率、 时钟门控(针对模块或寄存器阵列), 等等。 我们将在第9章对低功耗设计技术进行详述。 ,(8) 了解芯片对可测性的要求。 设计者要了解芯片是采用全扫描还是部分扫描, 是否采用内建自测试的方式, 是否需要JTAG, 这些对RTL设计都有影响。 例如, 扫描链的测试覆盖率受限于RTL设计风格。 我们将在第6章讲述可测性设计的内容。 在进行RTL设计时, 要进行如下工作: (1) 首先划分好设计的结构。 通常来说, 一个设计可以大致分为如下几个部分: I/O Pad、 时钟生成电路、 复位电路、 JTAG电路、 内核, 如图3.6所示。,图 3.6芯片的划分示意图,当然, 芯片划分

11、跟具体设计有关, 要根据实际情况选择合适的划分方法, 不可一概而论。 (2) 要与项目组的其他成员进行有效的沟通。 要与市场人员进行交流以确定产品的功能; 要与其他设计者交流以确定设计的命名规则、 模块划分、 各模块的接口, 等等。 能否进行有效的沟通是一个项目能否成功的关键。 (3) 为项目建立统一的目录结构。 项目的所有成员都在该目录下进行设计。 (4) 统一进行版本控制。 相信每个完成过较大设计的人都能体会版本控制的重要性。 ,在本书附录中对版本控制软件CVS进行了介绍。 (5) 进行合理的模块划分。 要考虑到逻辑功能、 设计目标、 时序方面的要求, 尽量将功能相关的模块放在一起, 以减

12、少各模块间的相关性, 方便以后的综合及布局布线。 按功能划分可以保证设计具有清晰的结构, 并有利于分配给不同成员完成。 (6) 建立统一的验证平台。 同一项目组的不同成员最好使用统一的测试验证框架, 然后分别施加自己的激励。 如果RTL设计开始前已完成了系统设计, 则可以利用系统设计的模型作为RTL设计验证的基准。 测试平台最好在项目初期就建立好。,(7) 考虑芯片的调试方案。 在第一次流片回来后, 需要对芯片进行调试。 由于现在的IC系统规模较大, 功能复杂, 容易出错, 因此调试方案的制定就非常关键。 在设计初期就应该考虑好调试方案。 为了便于定位错误, 设计者应将主要的功能模块分开进行测

13、试。 例如, 对于一个通信芯片, 要能够分别调试模拟部分、 数字信号处理部分和MAC部分。 在大型的设计中, 引脚总是非常宝贵的, 设计者要精心设计引脚的复用方案, 确定这些引脚在正常工作模块、 调试、 DFT时各有什么功能。 引脚分配方案要以文档的形式给出。 ,(8) 给出设计文档。 很遗憾, 在许多项目中都没有做到这一点。 人们往往等到项目结束后, 才开始写设计文档。 (9) 在写每个模块时, 最好能给出框图, 一图胜千言。 ,3.1.3复位策略在RTL设计中, 是采用同步复位的方式还是异步复位的方式?这种争论由来已久, 本节将对这个问题进行阐述。 在IC系统中, 复位的目的是为了将芯片强

14、制到一个已知的状态。 同步复位与异步复位都能达到这个目的。 两者的差别在于: 同步复位需要时钟有效沿到达时才能起作用, 而异步复位不需要。 ,图 3.7同步复位示例,在同步复步方式, 复位信号与数据进行组合操作, 作为寄存器的D端输入, 如图3.7所示。 实现同步复位寄存器的代码如下: module reg-syn (q1, d, clk, rst-n);output q1;input d, clk, rst-n;reg q1;always (posedge clk)if (!rst-n) q1 = 1b0;else q1 = d;endmodule,同步复位的优点在于: 在采用基于周期的仿真

15、器的场合(利用开发算法时), 采用同步复位要比采用异步复位简单许多。 寄存器可以滤掉复位上的毛刺。 同步复位的缺点是: 需要时钟, 在某些场合这会带来不便。 例如, 假如设计中包含三态总线, 总线上接着许多寄存器。 当上电后, 晶振还未起振, 或者锁相环还未稳定, 这时候没有时钟, 所以复位还没有起作用则总线上就可能发生冲突, 产生短路。 只有增加上电复位电路才能解决这个问题。 ,采用同步复位, 复位成为路径中组合逻辑的一部分。 由于复位的负载比较大(设计中寄存器数目较多), 因此会使复位树的延迟比较大, 从而导致在路径上的延迟较大。说明:上电复位电路中包括一个门限比较电路。 当电平超过某一电

16、平时, 会给出复位信号。 实现异步复位寄存器的代码如下: module async-resetFF (q, d, clk, rst-n);output q;input d, clk, rst-n;reg q;,always (posedge clk or negedge rst-n)if (!rst-n) q = 1b0;else q = d;endmodule 异步复位的优点是无需时钟, 且复位延时不会影响到路径延时。 异步复位的缺点是: 复位上的毛刺不能被由它复位的寄存器过滤, 必须采用其他的方法来消除; 复位的无效沿与时钟之间存在时序要求(recovery/removal)。 ,如果能够

17、将同步复位与异步复位的优点结合起来, 则显然是最佳的方案。 图3.8给出了一种方案, 即有效沿异步、 无效沿同步的复位方式。,图 3.8复位方案,在这种方案中, 复位信号由同步器生成。 复位同步器由两个寄存器组成, 其组成方式如图3.8所示。 外部的异步复位信号(来自PAD)接到同步器的异步复位端。 第一个寄存器的数据端接高电平(针对低电平有效的复位信号); 第二个寄存器的数据端接第一个寄存器的Q端。同步器的输出(即第二个寄存器的输出)作为生成的复位信号, 经过复位树接到各个寄存器上。,该电路的原理是: 当复位信号有效时(低电平), 两个同步器都为低, 因此同步器的输出立即变低, 而不管此时是

18、否存在时钟。 而当复位信号变高后, 经过时钟跳变沿后, 才能将高电平锁存到同步器的输出, 也就是说, 同步器的输出的无效沿与时钟是同步的。 这样, 就避免了recovery/removal问题。 复位同步器的波形如图3.9所示。 ,图 3.9复位同步器的波形,实现复位同步器的RTL代码如下: module async-resetFFstyle2 (rst-n, clk, asyncrst-n);output rst-n;input clk, asyncrst-n;reg rst-n, rff1;always (posedge clk or negedge asyncrst-n)if (!asy

19、ncrst-n) rst-n, rff1 = 2b0;else rst-n, rff1 = rff1, 1b1;endmodule,在上述方式中, 复位信号的毛刺仍然无法消除。 为了去掉毛刺, 通常先将由PAD得到的复位信号送到去毛刺电路。 下面给出一种实现方法: / filtering glitch of resetalways (posedge clk-i )glbl-rst-dly3, glbl-rst-dly2, glbl-rst-dly1 = glbl-rst-dly2, glbl-rst-dly1, rst-n-hw;always (posedge clk-i)glbl-rst-n

20、-noglitch= glbl-rst-dly3 | glbl-rst-dly2 |glbl-rst-dly1;,3.1.4状态机的设计在生成复杂的控制逻辑时, 普遍采用状态机的方式。 掌握良好的状态机书写规范, 是对RTL设计者最基本的要求。 图3.10给出了状态机的基本结构。,图 3.10状态机的基本结构,写状态机代码时, 可以采用单进程的方式(用一个always进程), 也可以采用双进程的方式(即采用两个always进程, 一个用于生成图3.10中的next, 一个用于生成图3.10中的state)。 一般而言, 用双进程状态机, 结构更为清晰, 因此在实际应用中应尽量采用这种方式。 图

21、3.11给出了一个状态机的状态转换图。 ,图 3.11状态转换图,针对如图3.11所示的状态转换图, 下面给出双进程状态机的写法。 module fsm1 (ds, rd, go, ws, clk, rst-n); output ds, rd; input go, ws; input clk, rst-n; reg ds, rd; parameter 1:0 IDLE=2b00, READ=2b01, DLY=2b10, DONE=2b11;,reg 1:0 state, next;always (posedge clk or negedge rst-n) if (!rst-n) state

22、= IDLE; else state = next;always (state or go or ws) begin next=2bx; ds=1b0; rd=1b0; case (state) IDLE: if (go) next=READ; else next=IDLE;,READ: begin rd=1b1; next=DLY; end DLY: begin rd=1b1; if (ws) next=READ; else next=DONE; end DONE: begin ds=1b1; next=IDLE; end endcase endendmodule,注意:程序中用黑色字体标出

23、的一句代码“next=2bx”。 加入这种语句, 是为了便于发现设计中的错误。 如果设计者在写描述机时, 没有将可能的状态遍历完整, 则next可能会进入x状态, 通过仿真可以很容易发现这个问题。 在上面所述的状态机中, 输出信号由组合逻辑输出。 为了保证设计的健壮性(消除输出的毛刺), 方便时序分析、 综合及布局布线, 通常需要将状态机的输出用寄存器锁存。 图3.12给出了这种状态机的示意图。,图 3.12状态机示意图(输出锁存),下面给出这种状态机(输出锁存)的代码实现:module fsm1b (ds, rd, go, ws, clk, rst-n); output ds, rd; in

24、put go, ws; input clk, rst-n; reg ds, rd; parameter 1:0 IDLE=2b00, READ=2b01, DLY=2b10, DONE=2b11;,reg 1:0 state, next;always (posedge clk or negedge rst-n) if (!rst-n) state = IDLE; else state = next; always (state or go or ws) begin next=2bx; case (state) IDLE: if (go) next=READ; else next=IDLE; R

25、EAD: next=DLY; DLY: if (ws) next=READ;,else next=DONE; DONE: next=IDLE; endcase endalways (posedge clk or negedge rst-n) if (!rst-n) begin ds = 1b0; rd = 1b0; end else begin ds = 1b0; rd = 1b0;,case (state) IDLE: if (go) rd = 1b1; READ: rd = 1b1; DLY: if (ws) rd = 1b1; else ds = 1b1; endcase endendm

26、odule状态机的编码方式有多种, 最常见的是独热(onehot)编码和二进制编码。,表3.1给出了4位的独热码的编码规则。,独热编码得到的状态机速度快, 缺点是占用资源多, 通常用于FPGA这类寄存器资源丰富的场合。 二进制编码占用资源最少, 在ASIC中应用最普遍。 图3.13对这两种编码方式进行了对比。,图 3.13独热编码与二进制编码,前面所举的例子都采用二进制编码, 下面给出用独热编码设计状态机的示例。module fsm-cc1-3oh(rd, ds, go, ws, clk, rst-n);outputrd;outputds;input go;input ws;input clk

27、;input rst-n;reg rd;reg ds;parameter IDLE=0, ,READ=1, DLY =2, DONE=3;reg 3:0 state, next;always (posedge clk or negedge rst-n)if (!rst-n) beginstate = 4b0;stateIDLE = 1b1;endelse state = next;always (state or go or ws) beginnext=4b0;,case (1b1) / synopsys parallel-casestateIDLE : if (go) nextREAD=1b

28、1;else nextIDLE=1b1;stateREAD : next DLY=1b1;state DLY : if (!ws) nextDONE=1b1;else nextREAD=1b1;stateDONE : nextIDLE=1b1;endcaseendalways (posedge clk or negedge rst-n)if (!rst-n) begin,rd = 1b0;ds = 1b0;endelse beginrd = 1b0;ds = 1b0; case (1b1) / synopsys parallel-casenextREAD : rd = 1b1;next DLY

29、 : rd = 1b1;nextDONE : ds = 1b1;,endcaseendendmodule 根据前面的示例, 我们可以总结出书写状态机的一些规则: 使用参数parameter来定义状态机的编码, 而不要用define。 define定义的常量在该模块之后读入的所有模块中都有效, 而parameter定义的常量仅在该模块中有效。 这样, 状态机编码的改变不会影响到其他文件;,采用双进程状态机; 在生成next的always中, 在起始处加入next=3bx这样的语句; 在生成输出信号的always中, 先给出该信号的缺省值;状态机的输出信号最好是寄存器输出。,3.1.5多时钟域的处

30、理 如果所有的设计都只有一个时钟, 那么RTL设计者的生活就太美好了。 可惜, 在大多数情形下, 我们面临着多时钟的处理问题。 本章主要讲述多时钟域的设计问题。 在第7章介绍多时钟域的静态时序分析技术。 多时钟域之所以难处理, 是因为在两个时钟域之间传递信号时, 不可避免地会出现建立时间/保持时间违例的问题。 寄存器可能会锁存错误的数据, 引起功能错误。下面我们先考虑在两个时钟域间传递1位信号的情形。,1. 1位信号的传递图3.14给出了多时钟域间传递1位信号的一个示例。 在这个例子中, aclk与bclk是两个异步时钟。 由aclk时钟域产生的数据adat要送到bclk的时钟域。 由于bcl

31、k与aclk不同步, 所以会出现这种情形: 在一定时刻, adat的变化沿距离bclk的采样沿非常接近, 不能满足建立时间和保持时间的要求。 这样, 寄存器可能会进入亚稳态。 图3.15给出了这种情形下的波形。,图 3.14多时钟域间传递信号,图 3.15多时钟域间传递信号的波形,bdat1的值会传递给其他模块。 在实际芯片中, 在bdat1处于亚微态的时候, 有些模块会认为自己收到的是“1”, 有些会认为是“0”, 如图3.16所示。 这种不一致会导致功能错误。 ,图 3.16亚稳态引起的数据传递错误,在仿真时, 当bdat1处于亚微态时, 它的值会变成X。 这种X状态会传递下去, 导致其他

32、信号也变成X状态。 如何避免这种情形呢?可以采用图3.17所示的同步器(synchronizer)。 ,图 3.17同步器示意图,采用同步器后, 相应的波形v如图3.18所示。,图 3.18异步信号的同步,由图3.18 可见, 采用同步器后, 同步器的输出信号可以有效地避免亚稳态(亚微态出现的概率大大降低, 可以忽略不计)。 这样, 在不同的接收模块中, 可以得到一致的值。 对于同步器本身, 第一个寄存器在锁存数据时, 仍然会出现建立时间/保持时间违例的情形。 可是我们已在电路结构上消除了隐患, 因此可以将这种违例看作是“虚假的违例”, 通过相应命令将其从报告中去掉即可。 ,需要说明的是, 在

33、仿真过程中, 同步器处仍会出现X状态, 这样X状态仍然会扩散下去, 导致仿真无法进行。 处理这种问题有两种方法, 一种是通过脚本, 修改sdf文件, 将这些同步器的时序检查语句去掉; 另一种方法更方便, 只需写一个文件, 将同步器的notifier置为固定值即可。 这里对第二种方法进行解释。 为理解这种方法, 先解释一下notifier的作用。 在寄存器的仿真模型中, 都有notifier这种结构。 当notifier的值翻转时, 仿真器就会给出X状态。,下面给出一个寄存器的仿真模型表示。 其中, nfr表示notifier结构, CK表示时钟, RN表示复位信号。table/CKRN Dnf

34、r: : Q; r 1 1 ? : ? : 1;r 1 0 ? : ? : 0;? 0 ? ? : ? : 0;n 1 ? ? : ? : ;? (?1) ? ? : ? :;? ? * ? : ? :;? ? ? * : ? : X;endtable,由寄存器仿真模型最后一行可以看出, 当nfr翻转时(取值为*), Q取值为X。 那么, nfr何时会翻转呢?在寄存器仿真模型中, 有一系列的时序检查语句, 用于检查建立时间、 保持时间等是否违例, 如下所示:$setuphold (posedge CK ,$width (posedge CK 当仿真器发现存在这些违例时, nofitier的值会

35、翻转, 从而导致Q取值变为X。 了解了仿真器产生X的机理, 我们就很容易解决这一问题: 只要将同步器的nfr置为固定值, 它的输出就不会变为X, 因此也就不会影响到仿真结果。 ,下面给出一个示例:initial begin$display(forcing notifiers on synchronizer flops at time %t, $time);force tb-top.dut.syn1.notifier=0;force tb-top.dut.syn2.notifier=0; force tb-top.dut.syn3.notifier=0;force tb-top.dut.syn4

36、.notifier=0;force tb-top.dut.syn5.notifier=0;endmodule,说明:在一个设计中, 同步器最好用例化的方式来说明。 例化名最好有相同的前缀, 这样有助于生成同步器的列表, 也方便进行静态时序分析时脚本的书写。 2. 相关的多位信号的传递 同步器适用于在多时钟域间传递1位的信号; 对于相关的多位信号, 采用这种技术依然会出现问题。 图3.19给出了示例。,图 3.19在多时钟域间传递两位信号,在这个例子中, 有两个信号b-load和b-en由bclk时钟域传递到aclk时钟域。 这两个信号相关。 我们假设在某个时钟周期内, b-load与b-en同

37、时有效, 那么这两个信号分别经过同步器后, 会是什么情形呢? 图3.20给出了波形示例。,图 3.20多位信号同步后的波形,由图3.20可见, 由于b-load信号与b-en信号的延迟不同, 两者的上升沿之间有一些偏移。 如果同步器的采样时钟正好也位于两个信号变化沿之间, 则采样后的信号有可能会相差一个周期。 同步器得到的最终信号a-load与a-en与源信号b-load和b-en显然不一致。 这种不一致可能会导致问题。 例如, 若这两个信号是控制一个寄存器的读操作的, 则仅当两个信号同时为高时, 寄存器会将新的值采进来。 尽管在bclk时钟域两个控制信号都变高, 在aclk时钟域却不是这样,

38、 因此, 新的数据并没有被采样进来, 这显然与期望结果不一致。,如何解决这个问题呢? 一种方法是将b-load与b-en信号合并, 生成1位信号。 例如, 我们将这两个信号进行逻辑与操作, 然后送到同步器, 如图3.21所示。,图 3.21在两个时钟域间传递相关信号的解决方案,在这种方案下, 相应的信号波形如图3.22所示。,图 3.22两时钟域间传递相关信号的波形,在很多时候, 无法对传递信号进行简单的合并。 这时候可以考虑先将这些信号编码成格雷码, 然后通过同步器传递。 由于格雷码在一个周期内仅有一位发生变化, 这样, 通过同步器后, 仍可以得到正确的结果。表3.2给出了4位数据的格雷编码

39、。,图3.23给出了一个采用格雷编码传递多位信号的示例。 对于要传递的两个信号bdec0和bdec1, 采用格雷编码, 生成ben0和ben1。 ,图 3.23采用格雷编码进行信号传递,上述的几种方案都是基于同步器的。 依据的基本原理是降低寄存器处于亚稳态的概率。 还有没有其他方案呢?我们为什么不干脆将数据的变化沿与时钟的变化沿隔开呢?一种方案是: 我们可以用多组寄存器来存储信号。 例如, 我们用8组寄存器来存储一个信号a。 在时刻0, 信号a写到第1个寄存器中; 在时刻1, 信号a写到第2个寄存器中; 依次类推。过一段时间, 我们再进行读操作。,例如, 当信号a写入到第4个寄存器时, 我们才

40、开始从寄存器0读出信号, 然后依次开始往下读。 这样, 针对某一个寄存器, 例如寄存器0, 它的数据变化与读时钟总是相差4个周期。 这样, 当开始读操作时, 数据早已经稳定下来, 不会出现建立时间/保持时间违例的情况了。 这就是基于异步FIFO在多时钟域间传递信号的基本原理。 对于这个异步FIFO, 如何生成空/满信号? 由于读指针与写指针是两个时钟域的信号, 比较时, 应该将它们放在一个时钟域来进行。 我们可以将它们编码为格雷码, 然后通过同步器传递到一个时钟域中。,具体地讲, 在生成满标志信号时, 我们将读指针编成格雷码, 然后经同步器送到写时钟域中, 与写指针进行比较; 生成空标志信号时

41、, 我们将写指针编成格雷码, 然后经同步器送到读时钟域中, 与读指针进行比较。 图3.24给出了一个异步FIFO的基本结构。,图 3.24异步FIFO示意图,下面我们给出异步FIFO的实现示例。 我们将这个异步FIFO分解成五个部分: 顶层模块、 FIFO存储体、 读指针同步器、 写指针同步器、 空标志及读地址生成逻辑和满标志及写地址生成逻辑, 用五个文件来完成设计。 对于这种简单设计, 这样划分显然太琐碎了, 在实际中可以写成一个文件。 异步FIFO的实现代码如下所示。首先是顶层模块:,module fifo1 (rdata, wfull, rempty, wdata, winc, wclk

42、, wrst-n, rinc, rclk, rrst-n); parameter DSIZE=8; parameter ASIZE=4; output DSIZE1:0 rdata; output wfull; output rempty; input DSIZE1:0 wdata; input winc, wclk, wrst-n; input rinc, rclk, rrst-n; wire ASIZE1:0 waddr, raddr;,wire ASIZE:0 wptr, rptr, wrptr2, rwptr2; sync-r2w sync-r2w (.wrptr2(wrptr2),

43、.rptr(rptr), .wclk(wclk), .wrst-n(wrst-n); sync-w2r sync-w2r (.rwptr2(rwptr2), .wptr(wptr), .rclk(rclk), .rrst-n(rrst-n); fifomem (DSIZE, ASIZE) fifomem (.rdata(rdata), .wdata(wdata), .waddr(waddr), .raddr(raddr), .wclken(winc), .wclk(wclk);,rptr-empty (ASIZE) rptr-empty (.rempty(rempty), .raddr(rad

44、dr), .rptr(rptr), .rwptr2(rwptr2), .rinc(rinc), .rclk(rclk), .rrst-n(rrst-n); wptr-full (ASIZE) wptr-full (.wfull(wfull), .waddr(waddr), .wptr(wptr), .wrptr2(wrptr2), .winc(winc), .wclk(wclk), .wrst-n(wrst-n);endmodule,接下来是存储体:module fifomem (rdata, wdata, waddr, raddr, wclken, wclk);parameter DATAS

45、IZE=8; / Memory data word widthparameter ADDRSIZE=4; / Number of memory address bitsoutput DATASIZE-1:0 rdata;input DATASIZE-1:0 wdata;input ADDRSIZE-1:0 waddr, raddr;input wclken, wclk;,ifdef VENDORRAM/ instantiation of a vendors dual-port RAMVENDOR-RAM MEM (.dout(rdata), .din(wdata), .waddr(waddr)

46、, .raddr(raddr), .wclken(wclken), .clk(wclk);elsereg DATASIZE-1:0 MEM 0:(1ADDRSIZE)-1;assign rdata=MEMraddr;always (posedge wclk)if (wclken) MEMwaddr = wdata;endifendmodule,module sync-r2w (wrptr2, rptr, wclk, wrst-n);parameter ADDRSIZE=4;output ADDRSIZE:0 wrptr2;input ADDRSIZE:0 rptr;input wclk, wr

47、st-n;reg ADDRSIZE:0 wrptr2, wrptr1;always (posedge wclk or negedge wrst-n)if (!wrst-n) wrptr2, wrptr1 = 0;else wrptr2, wrptr1 = wrptr1, rptr;endmodule,写指针同步模块如下所示: module sync-w2r (rwptr2, wptr, rclk, rrst-n);parameter ADDRSIZE=4;output ADDRSIZE:0 rwptr2;input ADDRSIZE:0 wptr;input rclk, rrst-n;reg

48、ADDRSIZE:0 rwptr2, rwptr1;always (posedge rclk or negedge rrst-n)if (!rrst-n) rwptr2, rwptr1 = 0;else rwptr2, rwptr1 = rwptr1, wptr;endmodule,空标志及读地址生成逻辑、 满标志及写地址生成逻辑是该FIFO最复杂的部分。 首先给出空标志及读地址生成逻辑, 如下所示:module rptr-empty (rempty, raddr, rptr, rwptr2, rinc, rclk, rrst-n);parameter ADDRSIZE=4;output re

49、mpty;output ADDRSIZE1:0 raddr;output ADDRSIZE:0 rptr;input ADDRSIZE:0 rwptr2;input rinc, rclk, rrst-n;,reg ADDRSIZE:0 rptr, rbin, rgnext, rbnext;reg rempty, raddrmsb;/-/ GRAYSTYLE1 pointer/-always (posedge rclk or negedge rrst-n)if (!rrst-n) beginrptr = 0;raddrmsb = 0;endelse beginrptr = rgnext;,rad

50、drmsb i);if (!rempty) rbnext=rbin + rinc;else rbnext=rbin;rgnext=(rbnext1) rbnext;end,最后, 我们给出满标志及写地址生成逻辑, 代码如下所示: module wptr-full (wfull, waddr, wptr, wrptr2, winc, wclk, wrst-n);parameter ADDRSIZE=4;output wfull;output ADDRSIZECD*21:0 waddr;output ADDRSIZE:0 wptr;input ADDRSIZE:0 wrptr2;input win

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号