fpga锁存器设计
always @ ( a or b)
begin if (a == 1'b1) q <= b; end 例 2 因为代码中未对 z 变量赋值,而产生锁存器 process (c) begin case c is when '0' => q <= '1'; z <= ' 0'; when others => q <= '0'; end case; end process; 例 3 因为代码中缺少赋值和条件语句,而产生锁存器
if (g == 1'b1) q <= 0; else if (a == 1'bl) q <= b;
end 推荐的编码风格: always @(g1 or g2 or a or b) begin:
q <= 1'b0 ; if (gl == 1'b1) q <= a; else if (g2 == 1'bl) q <= b;
⎧
⎪ ⎪ ⎩Q = 0
G2 输出 Q = 0 ⋅1 +1⋅1⋅ D = 1 ,所以 D 不影响 Q 和 Q
锁存器原理图
⎧ ⎪Q = 0 ⎪ ⎪ ⎩Q = 1
G2 输出 Q = 1⋅1 + 0 ⋅1⋅ D = 0 ,所以 D 也不影响 Q 和 Q
∴结论:原来状态不被改变,D 不影响 Q 和 Q 。 由上述分析看出:
C 是锁存控制信号输入端,D 数据输入端, Q 和 Q 是数据互补输出端。
Ⅰ: C =0, G2 左与门被封锁, G3 被封锁
⎧ ⎪Q = D G2 输出, Q = 0 ⋅ Q + 1⋅ D = D ,∴ ⎪ ⎨ ⎪ ⎪ ⎩Q = D
Ⅱ: C 时,分两种情况
⎪Q = 1 (a) ⎪ ⎨
(b) ⎪ ⎨
Page 5 of 8
让锁存器不再让人头痛
/bbs
图5带full case的例子 由于在例 8 中使用了 full case 语句,综合工具在综合时不会产生锁存器。另外,综合指令 “synthesis full_case”以注释的方式出现在代码中,只影响综合工具的综合结果,对设 计模型的语义没有其它影响。警告:使用full_case指令可能会导致设计模型和综合出的网表 功能不一致。 四、再谈锁存器 前面已经讲了当条件语句没有覆盖到所有分支时将产生锁存器, 很多资料也提到在设计中要 避免锁存器,其中的原因是什么呢? 例9 一个锁存器 module test_latch(y, a, b); output y; input a; input b; reg y; always @(a or b) begin if(a==1’b1) y=b; end endmodule
always @(d)
begin case (d) 2’b00: z <= 1’b1; //缺少对s的赋值 2’b01: z <= 1’b0; //缺少对s的赋值 2’b10: z <= 1’b1;s <= 1’b 1; endcase end //缺少在条件2’b11下对变量z和s的赋值
通过使用以下编码技术,可以避免产生锁存器。
参考文献: [1] Verilog HDL的数字系统应用设计。王钿,国防工业出版社 [2] Reuse Methodology Manual for System-on-a-chip Designs. Michael Keating [3] Verilog HDL Synthesis A Practical Primer. J.Bhasker [4] /bbs/
Page 6 of 8
让锁存器不再让人头痛
/bbs
从图6可知,例9对应的电路是锁存器。在信号a为高电平的时候,信号b可以传递给y,即使b是 带毛刺的信号。 例10 一个D触发器 module test_d(y,clk,a,b); output y; input clk; input a; input b; reg y; always @(posedge clk) begin if(a==1'b1) y=b; end endmodule
⎧ ⎪ ⎪C = 0时,Q = D,电路不锁存数据,相当于缓冲器 ⎨ ⎪ ⎪ ⎩C = 1时,D不起作用,电路状态保持C由0 → 1时刻前D决定的状态
也就是说, C 由 0 → 1 时刻将数据 D 锁定并保持,直到 C 由 1 → 0。 二、下面谈在你的设计中,如何避免使用任何锁存器 但也有例外,你可以使用工艺无关的 GTECH D 锁存器。然而,对于所有的锁存器都必
process (state, bus_request) begin -- 对输入进行初始化被避免产生锁存器 bus_hold <= ‘0’;
Page 2 of 8
让锁存器不再让人头痛
/bbs
bus_interrupt <= ‘0’; case (state) ... ... end process; 例 5 通过对所有输入条件赋输入值,避免产生锁存器 差的编码风格: always @(g or a or b) begin :
让锁存器不再让人头痛
/bbs
让锁存器不再让人头痛
(喜欢把学的东西整理一下,欢迎大家指正 chenhongyi123@ 2007.04.13) 触发器是指由时钟边沿触发的存储器单元。 锁存器指一个由信号而不是时钟控制的电平 敏感的设备。 一、锁存器的工作原理 锁存器不同于触发器,它不在锁存数据时,输出端的信号随输入信号变化,就像信号通 过一个缓冲器一样;一旦锁存信号起锁存作用,则数据被锁住,输入信号不起作用。锁存器 也称为透明锁存器,指的是不锁存时输出对于输入是透明的。 如下图所示为锁存器的原理图
Page 3 of 8
让锁存器不再让人头痛
/bbs
设计者就不可能完成PCI规范中对Reset功能的定义。为了设计是可测试的,可以采用如图1所 示的方法。它们使用多选的方法,提供一般功能或者I/O接口的数据。多选器的选择控制位来自 于扫描控制全能的测试模式管脚。
图1 让锁存器变得可测试 避免产生组合电路反馈 组合电路反馈是指组合逻辑电路形式的反馈环路.组合反馈环路会引发一系列问题,包括会使精 确静态时序分析难以实现。如图2、3所示。 不好:出现组合环路
end 例6 VHDL代码中,通过对条件语句的最后分支使用else语句,避免产生锁存器 差的编码风格: MUX3_PROC: process (decode, A, B) begin if (decode = ‘0’) then
C <= A;
elsif (decode = ‘1’) then
C <= B; end if; end process MUX3_PROC;
图2 好:不出现组合环路
图3 对于CASE语句生成锁存器的问题: 例7 case条件分支不完整导致了锁存器的产生 module latch_test(y1,a,sel); output y1; input [3:0] a; input [2:0] sel; reg y1; always @(sel or a) begin case(sel) 3'b000: y1=a[0];
Page 4 of 8
让锁存器不再让人头痛
/bbs
3'b001: y1=a[1]; 3'b010: y1=a[2]; 3'b011: y1=a[3]; endcase end endmodule 其综合出来的RTL图如图4。
图4 例七是一个不完整的条件分支的例子,sel信号位宽为3,可出现8种输入情况,但是在前级保证 输入只可能出现3’000、3’001、3’010、3’011四种情况下,在使用综合指令“synthesis full_case”后,综合工具将其综合成不带锁存器的电路如下图5所示。 例8 带full case的例子 module latch_test(y1,a,sel); output y1; input [3:0] a; input [2:0] sel; reg y1; always @(sel or a) begin case(sel) /*synthesis full_case*/ 3'b000: y1=a[0]; 3'b001: y1=a[1]; 3'b010: y1=a[2]; 3'b011: y1=a[3]; endcase end endmodule
推荐的编码风格: MUX3_PROC: process (decode, A, B) begin if (decode = ‘1’) then
C <= A;
else
C <= B; end if; end process MUX3_PROC;
三、如果必须使用锁存器 在有些设计中,不可避免地需要用到锁存器。例如,在PCI接口设计中,如果不用锁存器,
如例 4 的 VHDL 代码所示,将默认值赋值语句写在进程的开始。 如例 5 的 Verilog 代码所示,对所有可能的输入条件,都有明确的输出。 如例 6 的 VHDL 代码所示,对于条件语句的最后一个分支,使用 else 语句(而不使用 elsif 语句) 。 例 4 通过默认值,避免产生锁存器
Page 1 of 8
让锁存器不再让人头痛
/bbs
须提供文档记录。包括对每个锁存器的列表、描述和相关的时序特殊需求。寄存器堆、存储 器、FIFO 和其它一些设计中使用的 D 锁存器是允许的。 注意:用设计检查工具对设计中的锁存器进行检查。 例 1 所示的 Verilog 程序,综合会产生锁存器。因为在 if 语句的使用中缺少 else 语句。 例 2 所示的 VHDL 程序,综合后会产生锁存器。因为,when others 条件成立时,z 变量没 有被赋值。 例 1 因为缺少 else 语句,而产生锁存器