别再死记硬背Verilog语法了!用这5个实战小例子,帮你快速理解模块、wire和reg

张开发
2026/4/7 17:39:06 15 分钟阅读

分享文章

别再死记硬背Verilog语法了!用这5个实战小例子,帮你快速理解模块、wire和reg
别再死记硬背Verilog语法了用这5个实战小例子帮你快速理解模块、wire和reg学习Verilog最痛苦的事情莫过于面对一堆枯燥的语法规则却不知道它们在实际电路设计中有什么用。很多初学者会陷入死记硬背的泥潭记住了wire是连线reg是寄存器却不知道什么时候该用哪个背下了module的语法结构却写不出一个能工作的模块。今天我们就用5个从简单到复杂的实战例子带你从功能需求出发反向理解Verilog的核心语法概念。1. 从灯泡开关理解模块和端口想象我们要设计一个最简单的电路——用开关控制灯泡。在Verilog中这个电路可以这样描述module light_switch( input wire switch, // 输入端口 - 开关 output wire bulb // 输出端口 - 灯泡 ); assign bulb switch; // 灯泡状态直接由开关控制 endmodule这个例子展示了Verilog模块的四个基本要素模块声明module light_switch定义了一个名为light_switch的模块就像给我们的电路板贴了个标签端口定义input/output声明了模块与外界交互的接口相当于电路板上的接线端子信号类型wire表示这是一个直接的物理连线功能实现assign语句描述了输入输出的关系关键理解模块(module)就是电路的黑盒子端口(port)是盒子的对外接口wire是连接这些接口的导线。2. 用与门电路理解wire和连续赋值现在我们来设计一个稍微复杂点的电路——两个开关同时按下时灯泡才亮的与门逻辑module and_gate( input wire switch1, input wire switch2, output wire bulb ); wire and_result; // 内部连线 assign and_result switch1 switch2; // 与运算 assign bulb and_result; // 结果输出到灯泡 endmodule这里我们学到了wire类型用于表示模块内部的连接线可以暂存中间结果连续赋值(assign)只要右边的表达式值变化左边的wire会立即更新位运算是按位与运算符实现与门逻辑常见误区很多初学者会疑惑为什么这里不用reg。记住只有需要保存状态的电路才需要reg纯组合逻辑用wire就够了。3. 用D触发器理解reg和时序逻辑让我们进入时序电路的世界。一个带异步复位的D触发器可以这样实现module d_flip_flop( input wire clk, // 时钟 input wire reset_n, // 异步复位(低有效) input wire d, // 数据输入 output reg q // 数据输出 ); always (posedge clk or negedge reset_n) begin if (!reset_n) // 复位信号有效 q 1b0; // 输出清零 else // 时钟上升沿 q d; // 锁存输入数据 end endmodule这个例子揭示了几个重要概念reg类型用于存储状态只有在时钟边沿或特定事件发生时才会改变always块用于描述时序逻辑内部的赋值使用非阻塞赋值敏感列表(posedge clk or negedge reset_n)定义了触发条件关键区别特性wirereg赋值方式assignalways块内更新时机立即更新事件触发时更新用途组合逻辑连线存储状态4. 用计数器理解参数和位宽现在我们来设计一个4位二进制计数器它能在每个时钟周期自动加1并在达到最大值时自动归零module counter( input wire clk, input wire reset_n, output reg [3:0] count // 4位宽的输出 ); parameter MAX_COUNT 4d15; // 参数定义 always (posedge clk or negedge reset_n) begin if (!reset_n) count 4b0000; // 复位时清零 else if (count MAX_COUNT) count 4b0000; // 达到最大值归零 else count count 1b1; // 正常计数 end endmodule新知识点包括位宽声明[3:0]表示4位宽信号最高位是第3位参数定义parameter用于定义常量提高代码可读性和可维护性算术运算直接对reg变量进行1操作实用技巧在FPGA设计中明确的位宽声明可以帮助综合器生成更优化的电路。5. 用状态机理解复杂时序逻辑最后我们来看一个简单的交通灯控制器状态机它在红、绿、黄三种状态间循环切换module traffic_light( input wire clk, input wire reset_n, output reg [1:0] light // 00:红 01:黄 10:绿 ); // 状态定义 parameter RED 2b00; parameter YELLOW 2b01; parameter GREEN 2b10; // 状态寄存器 reg [1:0] state; // 定时计数器 reg [31:0] timer; always (posedge clk or negedge reset_n) begin if (!reset_n) begin state RED; timer 32d0; end else begin case (state) RED: begin if (timer 32d10_000_000) begin // 10秒 state GREEN; timer 32d0; end else begin timer timer 1; end end GREEN: begin if (timer 32d15_000_000) begin // 15秒 state YELLOW; timer 32d0; end else begin timer timer 1; end end YELLOW: begin if (timer 32d5_000_000) begin // 5秒 state RED; timer 32d0; end else begin timer timer 1; end end endcase end end // 输出逻辑 always (*) begin light state; end endmodule这个综合例子展示了状态机设计使用parameter定义状态编码用case语句实现状态转移混合时序/组合逻辑一个always块处理时序另一个处理组合输出大型寄存器32位定时计数器的使用非阻塞赋值确保状态转移的原子性设计经验复杂时序逻辑最适合用状态机实现每个状态明确对应一个电路行为。

更多文章