news 2026/9/6 17:35:25

数字IC前端学习笔记:锁存器的综合

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数字IC前端学习笔记:锁存器的综合

相关阅读

数字IC前端专栏https://blog.csdn.net/weixin_45791458/category_12173698.html?spm=1001.2014.3001.5482


锁存器是一种时序逻辑,与触发器相比面积更小,同时也可以放宽常见设计中的沿到沿时序要求,但它的存在会使静态时序分析(STA)变得更加复杂,因此懂得什么样的设计会综合出锁存器是很重要的,本文就将对此进行详细介绍。

显式锁存器

显式锁存器指的是在连续赋值语句或组合逻辑always结构中,将信号显式赋值给自己时出现的锁存器,一般显式锁存器是有意为之的。

连续赋值语句

最直观的锁存器

图1 D型锁存器

// 例1 module NonLatch1 ( input wire d, input wire en, output wire q, output wire qbar ); wire set, rst; assign set = !(en & d); assign rst = !(en & !d); assign q = !(set & qbar); assign qbar = !(rst & q); endmodule

图2是例1在Design Compiler 2024中的综合结果,可以看出,即使可以综合,综合工具并没有推断出D锁存器,而是综合为存在组合环(Combinational Loop)或者说反馈的结构。

图2 例1的综合结果

使用条件操作符

// 例2 module NonLatch2 ( input wire d, input wire en, output wire q, output wire qbar ); assign q = en ? d : q; assign qbar = !q; endmodule

图3是例2的综合结果,可以看出,综合工具也没有推断出D锁存器,而是综合为存在组合环(Combinational Loop)或者说反馈的多路选择器。

图3 例2的综合结果

always结构

需要注意的是,这里指的是组合逻辑always结构,而不是边沿控制的时序逻辑always块,对于后者,综合工具会推断出触发器而不是锁存器。

使用条件操作符

// 例3 module Latch1 ( input wire d, input wire en, output reg q, output reg qbar ); always @(*) begin q = en ? d : q; qbar = !q; end endmodule

图4是例3的综合结果,可以看出,综合工具将其综合为D锁存器。

图4 例3的综合结果

使用if-else语句

// 例4 module Latch2 ( input wire d, input wire en, output reg q, output reg qbar ); always @(*) begin if (en) begin q = d; qbar = ~d; end else begin q = q; qbar = qbar; end end endmodule

图5是例4的综合结果,可以看出,综合工具将其综合为D锁存器,但与图4有一点区别,原因是发生了在优化过程中发生了相位反转和触发器合并。

图5 例4的综合结果

需要注意的是,如果在例4中将else分支的q和qbar换为!q和!qbar,则会综合出组合逻辑环(Timing Loop)而不是锁存器。

隐式锁存器

隐式锁存器指的是在always结构中,没有将自己显式赋值给自己,但由于意料之外的因素出现的锁存器。

不完整的敏感列表

// 例5 module NonLatch3 ( input wire a, input wire b, input wire c, output reg y ); always @(a) begin y = a & b & c; end endmodule

例5使用组合逻辑always结构描述了一个三输入与门,但敏感列表中只有a而不含b和c,这导致了只有a发生变化时才会激活always结构。对于以前的综合工具,这会导致锁存器的产生;对于现在的综合工具,其对组合逻辑always结构的综合不依赖敏感列表,因此不会有锁存器产生,但这会导致前/后仿真的不一致,因为对于仿真工具根据敏感列表进行判断,因此行为就像是锁存器。

图6是例5的综合结果,可以看出,综合工具将其综合为三输入与门。

图6 例5的综合结果

实际上,由于不完整的敏感列表带来的风险如此巨大,Verilog 2001标准新加了一个*通配符来形成一个完整的敏感列表。使用通配符意味着always结构中RHS表达式、函数和任务调用的参数、case语句的case expression和case item、if语句的expression信号将自动加入敏感列表,如例6所示。

// 例6 module NonLatch4 ( input wire a, input wire b, input wire c, output reg y ); always @(*) begin y = a & b & c; end endmodule

不完整的if语句

// 例7 module Latch3 ( input wire a, input wire b, output reg y ); always @(*) begin if (a) y = b; end endmodule

例7中的if语句缺少else分支,即当a为0时输出保持不变(这其实与例4等价,只不过例4是显式赋值),这是一个锁存器的行为,图7是例7的综合结果,可以看出,综合工具将其综合为D锁存器。

图7 例7的综合结果

解决方法1

保持if语句完整且在每个分支中对所有信号的赋值,如例8所示。

// 例8 module NonLatch5 ( input wire a, input wire b, output reg y ); always @(*) begin if (a) y = b; else y = 1'b0; end endmodule

解决方法2

在always结构的开头对所有信号赋初值,如例9所示。

// 例9 module NonLatch6 ( input wire a, input wire b, output reg y ); always @(*) begin y = 1'b0; if (a) y = b; end endmodule

不完整的case语句

// 例10 module Latch4 ( input wire [1:0] sel, input wire a, input wire b, output reg y ); always @(*) begin case (sel) 2'b00: y = 1'b0; 2'b01: y = 1'b1; endcase end endmodule

与例7类似,例10中的case语句缺少case item,即当sel[1]为1时输出保持不变,这是一个锁存器的行为,图8是例10的综合结果,可以看出,综合工具将其综合为D锁存器。

图8 例10的综合结果

解决方法1

保持case语句完整且在每个分支中对所有信号的赋值(或者干脆使用case default),如例11所示。

// 例11 module NonLatch7 ( input wire [1:0] sel, input wire a, input wire b, output reg y ); always @(*) begin case (sel) 2'b00: y = a; 2'b01: y = b; 2'b01: y = 1'b1; 2'b01: y = 1'b0; // default: y = 1'b0; endcase end endmodule

解决方法2

在always结构的开头对所有信号赋初值,如例12所示。

// 例12 module NonLatch8 ( input wire [1:0] sel, input wire a, input wire b, output reg y ); always @(*) begin y = 1'b0; case (sel) 2'b00: y = a; 2'b01: y = b; endcase end endmodule

根本原因

以上这些无意间综合出的锁存器产生的根本原因是出现了在某些情况下需要保持信号值不变的需求,而又使用了组合逻辑always结构,因此只能使用锁存器实现功能。

思考一个问题:如果不使用本文提到的这些解决方法,不完整的if语句和case语句一定会综合出锁存器吗?例13会综合出锁存器吗?

// 例13 module Latch_or_Not ( input wire sel, input wire a, input wire b, output reg y ); reg [1:0] sel_with_constraint; always @(*) begin if (sel) sel_with_constraint = 2'b00; else sel_with_constraint = 2'b01; end always @(*) begin case (sel_with_constraint) 2'b00: y = a; 2'b01: y = b; endcase end endmodule

图9是例13的综合结果,如果这与你想的不一样,想想锁存器产生的根本原因,而不是孤立地看待if语句和case语句。

图9 例13的综合结果

下面再来看一个例子,例14会综合出组合逻辑环(Timing Loop)吗?

// 例14 module popcount_100 ( input wire [99:0] in, output reg [6:0] count ); integer i; always @(*) begin count = 0; for (i = 0; i < 100; i = i + 1) begin if (in[i] == 1'b1) count = count + 1'b1; end end endmodule

虽然在for语句中,循环中的count信号参与的计算结果显式赋值给自己是描述组合环逻辑环的代码风格,但如今的Design Compiler已经可以处理这种风格的RTL代码,并将其转化为下面这种意思。

count_0 = 0; count_1 = in[0] ? count_0 + 1 : count_0; count_2 = in[1] ? count_1 + 1 : count_1; count_3 = in[2] ? count_2 + 1 : count_2; count = count_3;
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 17:31:33

猫抓怎么解析 MPD、把 DASH 视频存到本地

猫抓怎么解析 MPD、把 DASH 视频存到本地 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 猫抓&#xff08;cat-catch&#xff09;是浏览器资源嗅探…

作者头像 李华
网站建设 2026/9/6 17:31:29

PCIe 5.0 M.2规范深度解读:从金手指到散热,一文避开硬件选型坑

简介&#xff1a;PCI-SIG 官方发布的 PCI Express M.2 规范修订版 5.0&#xff08;Version 0.9&#xff0c;2022 年 12 月 16 日&#xff09;&#xff0c;是面向硬件设计、存储设备开发、PCB 布线与接口测试工程师的权威技术参考文档&#xff0c;也适合电子工程相关专业的学生作…

作者头像 李华
网站建设 2026/9/6 17:29:44

KOReader 开源阅读器:让 Kindle 和 Kobo 重新爱上 PDF 的完整指南

KOReader 开源阅读器&#xff1a;让 Kindle 和 Kobo 重新爱上 PDF 的完整指南 【免费下载链接】koreader An ebook reader application supporting PDF, DjVu, EPUB, FB2 and many more formats, running on Cervantes, Kindle, Kobo, PocketBook and Android devices 项目地…

作者头像 李华
网站建设 2026/9/6 17:28:56

猫抓浏览器插件使用教程:网页视频与 M3U8 流媒体如何保存到本地

猫抓浏览器插件使用教程&#xff1a;网页视频与 M3U8 流媒体如何保存到本地 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 网页上正在播放的视频&…

作者头像 李华