Verilog入门实战——第2讲:核心语法基础(数据类型+赋值语句)

一、前言

完成开发环境搭建后,掌握Verilog核心语法是编写硬件逻辑的基础。与软件编程语言不同,Verilog语法设计围绕"硬件电路映射"展开,数据类型与赋值语句的选择直接决定电路逻辑的正确性。

本文摒弃复杂理论,只讲新手开发必备的核心知识点,通过代码案例直观呈现语法规则,为后续流程控制、模块设计打下坚实基础。

二、核心数据类型:wire与reg(新手必掌握)

Verilog中数据类型繁多,新手只需精通wirereg两种,即可覆盖90%的基础开发场景,二者分别对应不同的硬件电路特性。

1. wire型:线网型数据

  • 核心特性 :表示硬件电路中的"物理连线",无存储功能,值随输入信号实时变化,仅能通过连续赋值(assign)赋值。
  • 适用场景:组合逻辑输出、模块间信号连接、输入端口定义。
  • 定义语法wire [位宽-1:0] 变量名;(位宽默认1位,可省略)
  • 示例
verilog 复制代码
// 定义1位wire变量a,连接输入端口
wire a;
// 定义8位wire变量data,存储8位数据
wire [7:0] data;

2. reg型:寄存器型数据

  • 核心特性 :表示硬件电路中的"存储单元"(如触发器),有记忆功能,值在时钟边沿或条件触发时更新,仅能在过程块(always、initial)中赋值。
  • 适用场景:时序逻辑变量、计数器、状态机状态变量。
  • 定义语法reg [位宽-1:0] 变量名;
  • 示例
verilog 复制代码
// 定义1位reg变量flag,用于标记状态
reg flag;
// 定义4位reg变量cnt,用于十进制计数
reg [3:0] cnt;

3. 核心区别总结(避坑重点)

数据类型 赋值方式 硬件映射 适用逻辑
wire assign连续赋值 物理连线 组合逻辑
reg 过程块赋值(always/initial) 存储单元 时序逻辑

三、赋值语句:3种方式的严格区分

赋值语句是Verilog编写的核心,赋值方式与数据类型强绑定,混用会直接导致编译报错或逻辑错误,新手需严格区分。

1. 连续赋值(assign):专属wire型

  • 语法规则assign 目标变量 = 表达式;
  • 核心特点:赋值语句执行不受时间控制,表达式中任意信号变化,目标变量会立即更新,完全贴合组合逻辑"无记忆、实时响应"的特性。
  • 案例:二输入或门(组合逻辑)
verilog 复制代码
module assign_demo(
    input wire a,
    input wire b,
    output wire y
);

// 连续赋值:y随a、b实时变化,a=1或b=1时,y立即为1
assign y = a | b;

endmodule

2. 阻塞赋值(=):专属reg型(组合逻辑过程块)

  • 语法规则 :仅在always过程块中使用,格式为变量 = 表达式;
  • 核心特点:赋值操作"先执行完再继续",同一过程块中,前面的赋值会立即影响后面的语句,类似软件编程语言的赋值逻辑。
  • 适用场景always块实现组合逻辑时(如用always写多路选择器)。
  • 案例:二选一选择器(组合逻辑)
verilog 复制代码
module block_assign(
    input wire sel,
    input wire data0,
    input wire data1,
    output reg out  // 过程块赋值,需定义为reg型
);

// always块实现组合逻辑,敏感列表包含所有输入信号
always @(sel or data0 or data1) begin
    if(sel == 1'b1)
        out = data1;  // 阻塞赋值,先执行
    else
        out = data0;  // 受前面赋值影响(本案例无体现,复杂逻辑中需注意)
end

endmodule

3. 非阻塞赋值(<=):专属reg型(时序逻辑过程块)

  • 语法规则 :仅在always过程块中使用,格式为变量 <= 表达式;
  • 核心特点:赋值操作"先暂存,过程块结束后统一执行",同一过程块中,所有赋值语句互不影响,完美贴合时序逻辑"时钟边沿同步更新"的特性。
  • 适用场景always块实现时序逻辑时(如计数器、触发器)。
  • 案例:简单D触发器(时序逻辑)
verilog 复制代码
module non_block_assign(
    input wire clk,    // 时钟信号
    input wire rst_n,  // 低电平复位信号
    input wire d,      // 输入数据
    output reg q       // 输出数据,reg型
);

// always块实现时序逻辑,敏感列表为时钟上升沿+复位下降沿
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        q <= 1'b0;    // 复位,输出0
    else
        q <= d;       // 时钟上升沿,将d的值赋给q,非阻塞赋值
end

endmodule

4. 赋值语句避坑指南

  1. 禁止用assign给reg型变量赋值,禁止在过程块中给wire型变量赋值;
  2. 组合逻辑过程块(always)必须用阻塞赋值(=),时序逻辑过程块(always)必须用非阻塞赋值(<=),禁止混用;
  3. 过程块中,reg型变量必须初始化,避免出现不定态(x)。

四、实操验证:语法混合案例

结合上述知识点,编写一个"带复位的简单计数器",整合wire、reg、阻塞/非阻塞赋值的使用,帮助新手融会贯通。

verilog 复制代码
// 顶层模块:4位二进制计数器(0-15)
module counter_demo(
    input wire clk,      // 时钟输入
    input wire rst_n,    // 低电平复位
    output wire [3:0] out// 计数输出,wire型
);

// 定义reg型变量,存储计数值(时序逻辑,需reg型)
reg [3:0] cnt;

// 时序逻辑:计数器核心,非阻塞赋值
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        cnt <= 4'b0000;  // 复位,计数值清零
    else
        cnt <= cnt + 1'b1;  // 时钟上升沿,计数值+1
end

// 组合逻辑:将reg型的cnt赋值给wire型的out,连续赋值
assign out = cnt;

endmodule
相关推荐
minglie112 小时前
黑金AX301的SDRAM
fpga开发
hahaha601613 小时前
HLS高层次综合设计技巧--高层次综合设计探讨
fpga开发
minglie116 小时前
黑金AX301的EEPROM 24LC04
fpga开发
Hello-FPGA16 小时前
量子计算滨松c15550-22up单光子相机与PCIe1004采集卡
人工智能·计算机视觉·fpga开发
9527华安18 小时前
FPGA实现CameraLink转SFP光口,基于GT Transceivers Wizard Aurora8B10B编解码架构,提供4套工程源码和技术支持
fpga开发·sfp·cameralink·aurora8b10b·transceivers
ALINX技术博客2 天前
【期刊共读】如何应对 FPGA 短缺常态?
嵌入式硬件·fpga开发·fpga
156082072192 天前
短波接收机灵敏度测试
fpga开发
Riwuarua2 天前
从近似0基础开始FPGA开发 -- part.6 逻辑设计与状态机
fpga开发
LCG元2 天前
【实战】Vivado FPGA 从零实现 UART 串口收发:波特率生成、状态机设计与仿真调试
fpga开发
郭郭的柳柳在学FPGA2 天前
紫光DDR3工程仿真遇到的坑
fpga开发