数字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 @(*) beginq = en ? d : q;qbar = !q;endendmodule

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

图4 例3的综合结果

使用if-else语句

// 例4
module Latch2 (input wire d,input wire en,output reg q,output reg qbar
);always @(*) beginif (en) beginq = d; qbar = ~d;endelse beginq = q; qbar = qbar;endendendmodule

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

图5 例4的综合结果

隐式锁存器

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

不完整的敏感列表

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

        例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 @(*) beginy = a & b & c;endendmodule

不完整的if语句

// 例7
module Latch3 (input wire a,input wire b,output reg y
);always @(*) beginif (a) y = b;endendmodule

        例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 @(*) beginif (a) y = b;else   y = 1'b0;endendmodule

解决方法2

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

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

不完整的case语句

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

        与例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 @(*) begincase (sel)2'b00: y = a;2'b01: y = b;2'b01: y = 1'b1;2'b01: y = 1'b0;// default: y = 1'b0;endcase
endendmodule

解决方法2

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

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

根本原因

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

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

// 例12
module Latch_or_Not (input wire sel,input wire a,input wire b,output reg y
);reg [1:0] sel_with_constraint;always @(*) beginif (sel) sel_with_constraint = 2'b00;else     sel_with_constraint = 2'b01;
endalways @(*) beginy = 1'b0;case (sel_with_constraint)2'b00: y = a;2'b01: y = b;endcase
endendmodule

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

图9 例13的综合结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/80103.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LVGL源码学习之渲染、更新过程(2)---无效区域的处理

LVGL版本:8.1 往期回顾: LVGL源码学习之渲染、更新过程(1)---标记和激活 区域合并 在前面的代码分析中,发现标记无效区域的工作其实很繁琐,虽然大部分区域因为包含关系被剔除,但仍可能存在相互交叉的区域&#xff0c…

01 dnsmasq 中 dns服务

前言 这里我们主要是 来看一下 dns 服务器这边的相关业务处理 通常来说 在我们日常生活中 还是经常会需要使用 dns 的情况, 主要是更加友好的去给一个主机命名一个别名 比如 现在我的应用在服务器 192.168.220.133 但是我不想记这个生硬的 ip, 我可能更期望记录一个域名, …

最优化方法Python计算:有约束优化应用——线性Lasso回归分类器

利用线性Lasso模型类LineLassoModel类(见博文《最优化方法Python计算:有约束优化应用——线性Lasso回归预测器》)及分类器类Classification(见博文《最优化方法Python计算:无约束优化应用——线性回归分类器》&#xf…

Python基础学习-Day20

目录 奇异值分解(SVD)的输入和输出奇异值的应用实际案例1. 问题分析2. 解决方案:对测试集应用相同的变换3. 为什么不能对测试集单独做 SVD?4. 代码示例:训练集和测试集的 SVD 降维6. 实际操作中的注意事项 奇异值分解&…

2025年 全新 AI 编程工具 Cursor 安装使用教程

一、Cursor 软件下载 首选,登录Cursor官网,进行软件下载,官网下载地址如下: Cursor AI IDE 下载 二、Cursor软件安装配置 此处以Windows10系统安装为例,下载完成之后,右键安装包,以管理员身份…

[vue]error:0308010C:digital envelope routines::unsupported

npm run dev 报错: \node_modules\webpack\hot\dev-server.jsnode:internal/crypto/hash:71 this[kHandle] new _Hash(algorithm, xofLen); Error: error:0308010C:digital envelope routines::unsupported opensslErrorStack: [ error:03000086:digital env…

开放的力量:新零售生态的共赢密码

当某头部生鲜平台向供应商开放销售预测系统后,合作伙伴的库存周转率竟提升12%——这个反常识的案例,正在重塑商业竞争的底层逻辑。 生态共建三板斧 ▌模块化设计:像搭积木一样开放 • 乐高式API架构:30%接口支持自由组合&#xff…

深入理解Spring缓存注解:@Cacheable与@CacheEvict

在现代应用程序开发中,缓存是提升系统性能的重要手段。Spring框架提供了一套简洁而强大的缓存抽象,其中Cacheable和CacheEvict是两个最常用的注解。本文将深入探讨这两个注解的工作原理、使用场景以及最佳实践。 1. Cacheable注解 基本概念 Cacheable…

[python] 函数3-python内置函数

一 内置函数 导入:import builtins 1.1 查看内置函数 大写字母开头的一般是内置变量小写的一般是内置函数 import builtins print(dir(builtins)) 1.2 abs() 求绝对值 print(abs(-10)) 1.3 sum()求和 不能直接用纯数字,因为不是可迭代对象 运算时只要一个是浮点数,结果就…

QT异步线程通信

在使用 QThreadPool 提交任务后,如果你需要知道任务何时完成,并且需要使用任务的执行结果,可以通过以下几种方式来实现: 1. 使用信号和槽 QRunnable 提供了一个 finished() 信号,当任务执行完成后会发出。你可以在任…

利用并行处理提高LabVIEW程序执行速度

在 LabVIEW 编程中,提升程序执行速度是优化系统性能的关键,而并行处理技术则是实现这一目标的有力武器。通过合理运用并行处理,不仅能加快程序运行,还能增强系统的稳定性和响应能力。下面将结合实际案例,深入探讨如何利…

机器学习第三讲:监督学习 → 带答案的学习册,如预测房价时需要历史价格数据

机器学习第三讲:监督学习 → 带答案的学习册,如预测房价时需要历史价格数据 资料取自《零基础学机器学习》。 查看总目录:学习大纲 关于DeepSeek本地部署指南可以看下我之前写的文章:DeepSeek R1本地与线上满血版部署&#xff1…

Open CASCADE学习|实现裁剪操作

1. 引言 Open CASCADE (简称OCC) 是一个功能强大的开源几何建模内核,广泛应用于CAD/CAM/CAE领域。裁剪操作作为几何建模中的基础功能,在模型编辑、布尔运算、几何分析等方面有着重要作用。本文将全面探讨Open CASCADE中的裁剪操作实现原理、应用场景及具…

【redis】分片方案

Redis分片(Sharding)是解决单机性能瓶颈的核心技术,其本质是将数据分散存储到多个Redis节点(实例)中,每个实例将只是所有键的一个子集,通过水平扩展提升系统容量和性能。 分片的核心价值 性能提…

RGB矩阵照明系统详解及WS2812配置指南

RGB矩阵照明系统详解及WS2812配置指南 一、RGB矩阵照明简介 RGB矩阵照明是一种强大的功能,允许使用外部驱动器驱动的RGB LED矩阵为键盘增添绚丽的灯光效果。该系统与RGBLIGHT功能无缝集成,因此您可以使用与RGBLIGHT相同的键码来控制它,操作…

[250509] x-cmd 发布 v0.5.11 beta:x ping 优化、AI 模型新增支持和语言变量调整

目录 X-CMD 发布 v0.5.11 beta📃Changelog🧩 ping🧩 openai🧩 gemini🧩 asdf🧩 mac✅ 升级指南 X-CMD 发布 v0.5.11 beta 📃Changelog 🧩 ping 调整 x ping 默认参数为 bing.com&a…

嵌入式开发学习日志Day17

第十一章 结构体与共用体 一、结构体 1、结构体 一般形式 【struct 标识符】 结构体中的标识符一般首字母大写; 【.】结构体成员运算符; 优先级 1 级 结合方向:从左至右; 【->】:指向结构体成员运算符&#x…

发那科机器人5(异常事件和程序备份加载+ROBOGUIDE离线仿真)

发那科机器人5(异常事件和程序备份加载+ROBOGUIDE离线仿真) 一,异常事件和程序备份加载1,常见异常事件2,零点复归介绍3,程序备份-加载(未整理)二,`ROBOGUIDE`离线仿真1,仿真软件简介及安装步骤(未整理)2,机器人==导入与工具==与==工件添加==2.1,机器人导入(未整…

青少年编程与数学 02-019 Rust 编程基础 01课题、环境准备

青少年编程与数学 02-019 Rust 编程基础 01课题、环境准备 一、Rust核心特性应用场景开发工具社区与生态 二、Rust 和 Python 比较1. **内存安全与并发编程**2. **性能**3. **零成本抽象**4. **跨平台支持**5. **社区与生态系统**6. **错误处理**7. **安全性**适用场景总结 三、…

Java反射 八股版

目录 一、核心概念阐释 1. Class类 2. Constructor类 3. Method类 4. Field类 二、典型应用场景 1. 框架开发 2. 单元测试 3. JSON序列化/反序列化 三、性能考量 四、安全与访问控制 1. 安全管理器限制 2. 打破封装性 3. 安全风险 五、版本兼容性问题 六、最佳…