模块边界清晰优先于代码简短 · 参数化可提升模块复用能力 · 模块、信号与参数的作用
Verilog HDL 基础
建立语法基础,并形成“语法服务硬件表达”的学习方法
一、本章导航
二、本章定位
本章是后续建模、状态机、验证章节的语言基础。重点不是死记语法,而是理解每类语句在硬件描述中的角色边界。
- 模块由哪些基本部分组成?
- wire、reg、parameter 分别有什么作用?
- always、initial、assign 如何区分?
- 阻塞赋值和非阻塞赋值为什么容易混淆?
三、知识点讲解
1. 基本单元与基本语法
1.1 模块、信号与参数的作用
module 是硬件功能边界,端口定义决定模块如何与外部协作。清晰的端口命名和职责划分,是后续可维护性的基础。
wire、reg、parameter 是最常用对象:wire 常见于连线语义,reg 常见于过程块赋值语义,parameter 用于可配置设计。
- - 模块边界清晰优先于代码简短
- - 参数化可提升模块复用能力
1.2 疑难点:wire 和 reg 如何正确理解
不要简单把 wire 理解成“导线”、reg 理解成“寄存器”。更可靠的方法是看使用场景:对象在哪里赋值、用于描述什么行为。
当你用“语义 + 场景”而不是“中文直译”来理解对象时,后续赋值与过程块的学习会稳定很多。
2. 过程语句与块语句
2.1 initial、always、begin/end 的定位
initial 常用于仿真初始化语义;always 是事件触发过程块,可用于组合逻辑或时序逻辑描述。两者定位不同,不应混用。
begin/end 用于组织多条相关语句,能提升结构可读性,降低后续修改时的理解成本。
2.2 疑难点:always 为什么不是程序循环
always 不是 while(true) 的硬件版本,而是“由事件触发的过程块”。关键不在“会不会一直执行”,而在“什么条件触发执行”。
若是组合逻辑,关注输入变化触发;若是时序逻辑,关注时钟边沿触发。把触发条件和更新时机说清楚,误解就会明显减少。
3. 赋值、条件、循环与 task/function
3.1 赋值与控制语句的硬件语义
assign 连续赋值常用于组合关系;过程赋值位于过程块中。阻塞赋值和非阻塞赋值的差异本质在“更新时机”,会直接影响仿真理解与实现结果。
if/case、for/repeat/while、task/function 是表达工具。核心问题不是“语法像不像软件”,而是“语义是否符合硬件行为”。
3.2 疑难点:阻塞与非阻塞怎么选
实用规则是:组合逻辑优先阻塞赋值,时序逻辑优先非阻塞赋值。该规则目的不是形式统一,而是保持语义一致,减少隐性错误。
遇到不确定场景时,先判断逻辑是“立即组合计算”还是“时钟边沿更新”。判断更新时机后,赋值方式自然清晰。