第二讲:Verilog基础语法(上)——模块与端口、数据类型、赋值语句、操作符
各位同学,今天我们正式开始啃Verilog的语法基础。说实话,语法这东西,光看书容易犯困。但你要是真写过几行代码,就会发现——嗯,其实就那么回事。
这一讲,我们聚焦四个核心:模块与端口、数据类型、赋值语句、操作符。把这四个搞明白,你就能看懂大部分Verilog代码了。
一、模块与端口:Verilog的“黑盒子”
Verilog里,所有设计都从模块(module)开始。模块就像芯片里的一个功能块,有输入、有输出,内部藏着逻辑。
我个人习惯把模块想象成一个黑盒子。你只管告诉它“输入什么”,它按规则算出“输出什么”。至于里面怎么算的,那是我们写代码的人决定的。
模块的基本结构:
module 模块名 (
端口列表
);
// 内部逻辑
endmodule
端口分三种:input(输入)、output(输出)、inout(双向)。我建议初学者先别碰inout,容易把自己绕晕。
举个例子,一个最简单的与门模块:
module and_gate (
input wire a,
input wire b,
output wire y
);
assign y = a & b;
endmodule
你看,端口声明里我写了wire。这是什么?我们接着聊。
二、数据类型:wire 和 reg
Verilog里最常用的两种数据类型就是wire和reg。很多新手搞不清它们的区别,我当年也踩过坑。
| 类型 | 含义 | 典型用法 |
|---|---|---|
| wire | 连线型,组合逻辑 | assign 赋值、模块端口连接 |
| reg | 寄存器型,时序逻辑 | always 块内赋值 |
wire 说白了就是一根物理导线。它不存储值,只是把驱动端的值传递出去。你想想看,导线本身能存东西吗?不能。
reg 就不同了。它代表一个存储单元,可以保持上一次赋的值。注意,reg不一定真的综合成寄存器——如果你在组合逻辑的always块里用reg,它综合出来还是连线。嗯,这里要注意。
我的经验:端口声明时,input/output默认是wire类型。如果你需要输出是reg,必须显式写output reg。我曾经因为漏写这个,仿真对了,综合却报错,查了半天。
三、赋值语句:assign 和 always
赋值是Verilog的灵魂。两种方式:连续赋值(assign)和过程赋值(always)。
3.1 assign:组合逻辑的直通车
assign 用于组合逻辑。只要右边表达式变了,左边立刻更新。它只能对wire类型赋值。
assign y = a & b; // 组合逻辑,y随a、b变化
我刚开始做设计时,喜欢把所有组合逻辑都用assign搞定。简单、直观、不容易出错。
3.2 always:时序逻辑的主战场
always 块可以描述组合逻辑,也可以描述时序逻辑。区别在于敏感列表。
// 组合逻辑:电平敏感
always @(*) begin
y = a & b;
end
// 时序逻辑:边沿敏感
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q <= 1'b0;
else
q <= d;
end
注意看,时序逻辑里我用了<=(非阻塞赋值),组合逻辑用了=(阻塞赋值)。这是硬性规定,搞反了仿真结果会一塌糊涂。
避坑指南:我曾经在一个项目里,把时序逻辑的赋值写成了阻塞赋值。仿真时看着没问题,综合后时序全乱套。从那以后,我给自己定了个规矩:always @(posedge clk) 里只用 <=。
四、操作符:Verilog的“计算器”
操作符没什么神秘的,就是C语言那套,加加减减、与或非。但有几个细节值得注意。
| 类别 | 操作符 | 说明 |
|---|---|---|
| 算术 | + - * / % | 乘除法综合出来面积大,慎用 |
| 逻辑 | && || ! | 返回1位布尔值 |
| 位运算 | & | ~ ^ | 按位操作,常用 |
| 归约 | & | ^ ~& ~| ~^ | 将多位数归约为1位 |
| 移位 | << >> | 逻辑移位,空位补0 |
| 拼接 | { } | 把多个信号拼在一起 |
| 条件 | ? : | 类似C的三目运算符 |
我个人最常用的是位运算和拼接。比如你要把两个4位数拼成8位数:
wire [3:0] a, b;
wire [7:0] c = {a, b}; // 拼接
归约操作符也挺有意思。比如你想检查一个8位数是否全为0:
wire [7:0] data;
wire all_zero = ~|data; // 归约或,再取反
你想想看,一行代码搞定,多清爽。
我的建议:操作符本身不难,难的是位宽匹配。两个不同位宽的数做运算,Verilog会自动扩展。扩展规则是:无符号数补0,有符号数补符号位。我见过太多因为位宽不匹配导致的bug了。
五、知识体系总览
为了帮你理清思路,我画了一张图。这张图把本章的核心知识点串在了一起。
这张图把模块、端口、数据类型、赋值语句、操作符串在了一起。你顺着箭头看,就能理解它们之间的关系。
好了,这一讲的内容就到这里。语法是工具,多用几次就熟了。下一讲我们继续深入,聊聊更进阶的语法结构。
公众号:蓝海资料掘金营,微信deep3321