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
相关推荐
嵌入式-老费6 小时前
Linux camera驱动开发(vivado hls不能导出ip的问题)
图像处理·fpga开发
Eloudy8 小时前
NetFPGA 快速入门指南
量子计算·fpga·nvqlink
CoderIsArt10 小时前
FPGA量子计算教学平台设计方案与实现步骤
fpga开发·量子计算
学习永无止境@10 小时前
Vivado FPGA输入时钟约束
开发语言·fpga开发·fpga
上班最快乐1 天前
基于FPGA的APS6404L-3SQR QSPI PSRAM驱动设计(1)
fpga开发
国科安芯1 天前
抗辐照加固CAN FD芯片的商业航天与车规级应用解析
科技·嵌入式硬件·安全·fpga开发·安全威胁分析
简宸~1 天前
FPGA(十一)DataMover 自编辑IP
网络协议·tcp/ip·fpga开发·开源
Eloudy1 天前
Quartus Prime Lite Edition 25.1 安装备忘
fpga
XINVRY-FPGA1 天前
XC7Z020-2CLG400I Xilinx AMDZynq-7000 FPGA
嵌入式硬件·fpga开发·arm·硬件工程·dsp开发·fpga