4. Verilog语法基础(一):模块结构、端口定义、assign语句、常用运算符

好,咱们正式开始啃Verilog语法了。说实话,很多新手一上来就被各种语法细节吓住,其实没必要。你想想看,Verilog说白了就是描述硬件的一种语言,跟C语言那种“顺序执行”的思路完全不同。今天这一章,我带你先把最核心的骨架搭起来。

4.1 模块结构——Verilog的基本单元

在FPGA的世界里,模块(module)就是一切。每个模块相当于一个“黑盒子”,有输入、有输出,内部实现具体的逻辑功能。我刚开始学的时候,总觉得模块就是C语言里的函数,后来发现完全不是一回事——模块是并行执行的,不是顺序调用。

一个完整的模块长这样:

module 模块名 (
    端口列表
);
    // 内部信号声明
    // 逻辑功能描述
endmodule

注意看,moduleendmodule是一对,就像括号一样,必须成对出现。我见过不少新手漏掉endmodule,结果编译报错半天找不到原因。

核心要点:每个Verilog文件通常只包含一个模块,模块名最好跟文件名保持一致。这是行业惯例,也是我个人的习惯,方便后期维护。

4.2 端口定义——模块的“手脚”

端口就是模块跟外界通信的通道。分为三种:input(输入)、output(输出)、inout(双向)。实际项目中,inout用得不多,咱们先把前两个搞明白。

举个例子,一个最简单的与门模块:

module and_gate (
    input  wire a,      // 输入端口a
    input  wire b,      // 输入端口b
    output wire y       // 输出端口y
);
    // 逻辑功能
    assign y = a & b;
endmodule

这里有个细节:wire表示线网类型,是默认的。如果你不写wire,编译器也会自动推断。但我建议你养成好习惯,明确写出来,代码可读性会高很多。

个人经验:我在项目中遇到过一位同事,端口定义时把input和output写反了,结果仿真怎么跑都不对。查了两天才发现是端口方向搞错了。所以,每次写完端口列表,我习惯再扫一遍,确认方向没问题。

4.3 assign语句——连续赋值

assign是Verilog里最常用的语句之一,用于描述组合逻辑。它的意思是“只要右边表达式发生变化,左边就立即更新”。说白了,就是一根导线,一端接逻辑表达式,另一端接输出。

看个例子:

assign sum = a + b;
assign flag = (a > b) ? 1'b1 : 1'b0;

注意,assign语句的左边必须是wire类型,不能是reg。这个坑我踩过——刚开始写代码时,总想把assign赋值给reg,结果编译报错“左侧不是net类型”。

避坑指南:我曾经在一个项目里,用assign给一个reg类型信号赋值,仿真器没报错,但综合时报了一堆警告。后来查资料才知道,assign只能驱动wire。记住:assignwirealwaysreg,这是铁律。

4.4 常用运算符——算术、逻辑、位运算

运算符这部分,跟C语言很像,但有些细节不一样。我挑几个重点说说。

4.4.1 算术运算符

运算符 含义 示例
+ 加法 a + b
- 减法 a - b
* 乘法 a * b
/ 除法 a / b
% 取模 a % b

注意,乘法和除法在FPGA里很“贵”。乘法器会消耗大量LUT,除法更是如此。我一般建议:能用移位实现的,就别用乘除法。比如乘以2,写成a << 1,比a * 2高效得多。

4.4.2 逻辑运算符

逻辑运算符返回的结果是布尔值(0或1)。常用于条件判断。

运算符 含义 示例
&& 逻辑与 (a > 0) && (b > 0)
|| 逻辑或 (a > 0) || (b > 0)
! 逻辑非 !a

这里有个容易混淆的点:&&&不一样。前者是逻辑与,后者是按位与。我见过有人写if (a & b),本意是判断a和b都不为0,结果变成了按位与,逻辑完全错了。

4.4.3 位运算符

位运算符是对二进制位逐位操作,在FPGA里用得非常多。

运算符 含义 示例
& 按位与 a & b
| 按位或 a | b
^ 按位异或 a ^ b
~ 按位取反 ~a

举个例子,如果你想取一个8位信号的低4位,可以这样写:

assign low_4bit = data & 8'b0000_1111;

这种写法比用data[3:0]更清晰,尤其是在做位掩码操作时。

小技巧:异或运算在FPGA里特别有用。比如做奇偶校验、数据翻转,都可以用^。我曾在项目中用异或实现了一个简单的CRC校验,代码简洁,综合效率也高。

4.5 知识体系结构图

下面这张图,帮你把本章的核心知识点串起来:

Verilog语法基础(一) 模块结构 端口定义 assign语句 常用运算符 算术运算符 逻辑运算符 位运算符 图:本章知识体系结构

嗯,这张图把今天的内容都串起来了。模块是骨架,端口是接口,assign是血肉,运算符是工具。四者结合,就能写出最基本的Verilog代码。

总结一下:今天讲了模块的写法、端口怎么定义、assign怎么用,还有三种常用运算符。这些都是基本功,就像练武要先扎马步一样。别急,慢慢来,后面几章我们会把这些基础组合起来,做出真正有用的东西。


公众号:蓝海资料掘金营,微信deep3321