当前位置: 首页 > news >正文

Verilog 语法 (二)

        在掌握了 Verilog 的基础语法和常用程序框架之后,本节将带大家深入学习一些 高级设计知识点。这些内容包括:

阻塞赋值(=)与非阻塞赋值(<=)的区别及使用场景;

assignalways 语句的差异;

什么是锁存器(Latch),以及如何避免不必要的锁存器;

有限状态机(FSM)的基本结构与应用;

模块化设计思想及其实践方法。

阻塞赋值
阻塞赋值,顾名思义即在一个 always 块中,后面的语句会受到前语句的影响,具体来说就是在同一个 always 中,一条阻塞赋值语句如果没有执行结束,那么该语句后面的语句就不能被执行,即被 阻塞 。也就是说 always 块内的语句是一种顺序关系,这里和 C 语言很类似。符号“ = ”用于阻塞的赋值(如 :b = a;),阻塞赋值“ = ”在 begin end 之间的语句是顺序执行,属于串行语句。
RHS :赋值等号右边的表达式或变量可以写作 RHS 表达式或 RHS 变量;
LHS :赋值等号左边的表达式或变量可以写作 LHS 表达式或 LHS 变量;
阻塞赋值的执行可以认为是只有一个步骤的操作,即计算 RHS 的值并更新 LHS ,此时不允许任何其他语句的干扰,所谓的阻塞的概念就是值在同一个 always 块中,其后面的赋值语句从概念上来讲是在前面一条语句赋值完成后才执行的。

 

posedge clk:时钟上升沿触发;

negedge rst_n:低电平复位触发(rst_n 是低有效复位信号);

这表示在复位时,三个变量分别被赋初值。

a = 0;
b = a;
c = b;

这三行是阻塞赋值,意味着它们是顺序执行的不是并行的

b = a; 举例,由于 a = 0; 已经执行完了,b 实际上赋的值就是 0。

同理,c = b; 也赋的是更新后的 b,也是 0。

最终 a = 0, b = 0, c = 0

如果我们改用非阻塞赋值(<=):

a <= 0;
b <= a;
c <= b;

这样所有赋值将在时钟沿结束后同时生效,即:

a <= 0;

b <= 原来的 a 值

c <= 原来的 b 值

这就实现了寄存器的移位操作(流水线结构),是我们设计中经常想要的行为。

特性阻塞赋值 (=)非阻塞赋值 (<=)
执行方式按顺序执行(立即更新)并行执行(统一在时钟边沿更新)
用于一般用于组合逻辑推荐用于时序逻辑(寄存器)
本例中问题变量值被覆盖,行为不符合预期可实现流水线等预期行为
非阻塞赋值
符号“ <= ”用于非阻塞赋值(如 :b <= a; ),非阻塞赋值是由时钟节拍决定,在时钟上升到来时,执行赋值语句右边,然后将 begin-end 之间的所有赋值语句同时赋值到赋值语句的左边,注意:是 begin—end之间的所有语句,一起执行,且一个时钟只执行一次,属于并行执行语句。这个是和 C 语言最大的一个差异点,大家要逐步理解并行执行的概念。
非阻塞赋值的操作过程可以看作两个步骤:
1 )赋值开始的时候,计算 RHS
2 )赋值结束的时候,更新 LHS

 

这部分内容是非阻塞的内容,在此阻塞的内容也介绍了。

ok完毕~,接下来就是assign always 区别了。

assign always 区别

在 Verilog 中,assignalways 是两种描述逻辑行为的基本语句。两者既有相似性也有明显的区别,特别是在时序逻辑和组合逻辑的描述中用途不同。

assign 语句

用法: 用于连续赋值(continuous assignment)。

只能用于组合逻辑

不能包含时钟

语句写法非常简洁,适用于简单的逻辑关系。

always @(*) begincase (led_ctrl_cnt)2'd0 : led = 4'b0001;2'd1 : led = 4'b0010;2'd2 : led = 4'b0100;2'd3 : led = 4'b1000;default : led = 4'b0000;endcase
end
项目assignalways @(*)
用于描述连续赋值的组合逻辑过程赋值的组合逻辑或更复杂的逻辑
是否必须赋值所有输出是(自动)是(手动,否则会生成锁存器)
写法单行表达式(简洁)可多行,逻辑复杂时更清晰
可读性简洁,逻辑简单时最直观更灵活,适合多判断、多分支等场景
是否需要 default 分支不需要建议加上,否则可能综合成锁存器
是否可用于时序逻辑❌ 否(不含时钟,不能生成寄存器)✅ 可用于时序逻辑(带 clk)

 

latch 是指锁存器,是一种对脉冲电平敏感的存储单元电路。锁存器和寄存器都是基本存储单元,锁存器是电平触发的存储器,寄存器是边沿触发的存储器。两者的基本功能是一样的,都可以存储数据。锁器是组合逻辑产生的,而寄存器是在时序电路中使用,由时钟触发产生的。
latch 的主要危害是会产生毛刺( glitch ),这种毛刺对下一级电路是很危险的。并且其隐蔽性很强,不易查出。因此,在设计中,应尽量避免 latch 的使用。
代码里面出现 latch 的两个原因是在组合逻辑中, if 或者 case 语句不完整的描述,比如 if 缺少 else 分支,case 缺少 default 分支,导致代码在综合过程中出现了 latch 。解决办法就是 if 必须带 else 分支, case 必须带 default 分支。
大家需要注意下,只有不带时钟的 always 语句 if 或者 case 语句不完整才会产生 latch ,带时钟的语句 if 或者 case 语句不完整描述不会产生 latch
下面为缺少 else 分支的带时钟的 always 语句和不带时钟的 always 语句,通过实际产生的电路图可以看到第二个是有一个 latch 的,第一个仍然是普通的带有时钟的寄存器。
项目锁存器(Latch)寄存器(Register)
触发方式电平触发(高电平或低电平)边沿触发(posedge 或 negedge)
属于哪种逻辑组合逻辑推导而来时序逻辑
是否带时钟信号❌ 不依赖时钟✅ 依赖时钟
容易产生的问题⚠️ 容易引入毛刺竞争冒险✅ 稳定,常规使用
综合方式always @(*) 中未完整赋值会生成使用 always @(posedge clk) 等生成

 

latch 是组合逻辑中赋值不完整的副产品,既不安全也不推荐,应靠良好编码习惯避免。

状态机

Verilog 是用于描述并行硬件电路的语言,但在某些功能中,我们想按“步骤”来完成逻辑,比如:

串口收发数据(开始 → 收 → 校验 → 存储)

SDRAM 控制(初始化 → 激活 → 读写 → 刷新)

协议处理器(等待命令 → 解码 → 执行)

这时候,大量的 if/else 嵌套 不仅难写,而且容易出错。状态机(FSM)能把这些步骤清晰地“拆分成状态”,通过时钟驱动状态跳转来控制整个流程,逻辑结构清晰、易于维护。

状态机的分类:Mealy vs Moore

类型状态转移是否依赖输入输出是否依赖输入特点
Moore✅ 是❌ 否输出只依赖状态,更稳定、更容易综合
Mealy✅ 是✅ 是输出响应更快,但逻辑更复杂

相关文章:

  • 小刚说C语言刷题——1565成绩(score)
  • element-ui tabs 组件源码分享
  • 品融电商:以全域增长方法论,解码2025情绪消费新机遇
  • Coze高阶玩法 | 使用Coze制作思维认知提升视频,效率提升300%!(附保姆级教程)
  • OpenHarmony之电源管理子系统公共事件定义
  • Vue选项式 API 与组合式 API
  • jdk-8u202-linux-x64.tar.gz官方下载地址
  • 统计服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
  • 大学IP广播系统解决方案:构建数字化智慧化大学校园IP广播平台
  • 创建型设计模式之:简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式
  • Oracle Recovery Tools修复ORA-00742、ORA-600 ktbair2: illegal inheritance故障
  • 路由器的基础配置全解析:静态动态路由 + 华为 ENSP 命令大全
  • 3D模型文件格式之《STL格式介绍》
  • 知识蒸馏和迁移学习的区别
  • Cannot read properties of null (reading ‘classList‘)
  • A2A与MCP之间的简单理解
  • 【Google上包前APK自检】
  • 深入理解网络原理:UDP协议详解
  • 【Linux】Vim文本编辑器
  • Java使用IText7动态生成带审批文本框的PDF文档
  • 淮安四韵·名城新章: 网络名人领略“运河之都”魅力
  • 李公明|一周画记:哈佛打响第一枪
  • 人民日报:应对外贸行业风险挑战,稳企业就是稳就业
  • AI应用大盘点:谁暴涨?谁掉队?
  • 人民日报:光荣属于每一个挺膺担当的奋斗者
  • 体坛联播|皇马上演罢赛闹剧,杨瀚森宣布参加NBA选秀