Verilog HDL 语言整理

Verilog HDL 语言

Verilog HDL 简介

硬件描述语言 Hardware Description Language是一种用形式化方法即文本形式 来描述和设计数字电路和数字系统的高级模块化语言

  • Verilog HDL(Hardware Description Language)是一种硬件描述语言,用于建模、设计和验证数字系统,比如芯片(ASIC)、FPGA等。
  • 它既可以用于描述电路结构(结构级建模),也可以描述电路行为(行为级建模)。

基本组成

  • 模块(module):Verilog的基本单元,定义了输入输出端口和内部逻辑。
  • 端口(ports):模块的输入(input)、输出(output)、双向(inout)信号。
  • 信号类型(nets和variables):例如wire(连线类型),reg(寄存器类型)。

数据类型

变量值

含义
0 代表逻辑0 或 否条件
1 代表逻辑1 或 真条件
X 代表未知的逻辑值(可能是0也可能是1)
Z 代表一个高阻态

0 在电路中一般是低电平

1 在电路中是高电平

X 一般是寄存器类型( reg )未初始化

Z 是线型( wire )变量未接驱动

(实际写代码时要避免出现X和Z)

wire(线网)

  • wire 表示一根连接线(物理连线)。
  • 不能自己存值,通常用于连续赋值,只能连接别的东西,比如assign语句、模块的输出。
  • 一般用于组合逻辑(纯逻辑运算)。

例子:

verilog 复制代码
wire a;   // 声明一根线,1-bit位宽
assign a = b & c;  // a 由 b 和 c 按位与得到
wire d = 1'b0;   //1代表1-bit位宽,'b'代表二进制,0是初值

reg(寄存器)

  • reg 是一个存储单元
  • always块或initial块里赋值。
  • 不一定是真正硬件的"寄存器",但可以存住一个值直到下次变化。

例子:

verilog 复制代码
reg rstn;
initial begin
    rstn = 1'b0;
    #100;  // 等待100单位时间(单位根据仿真设置,比如ns或ps)
    // # 是延时操作
    rstn = 1'b1;
end
verilog 复制代码
reg d;    // 声明一个寄存单元
always @(posedge clk) begin
  d <= a; // 非阻塞赋值,时序逻辑 每次时钟上升沿,d取a的值
end

🔔 注意:

  • wire 用在 assign、模块之间连线
  • reg 用在 always 块里

向量vector

当你声明多位的 wirereg 时,就叫向量(Vector)

向量本质上就是:一组用一根名字表示的多位信号。

你可以整体操作,也可以单独取其中一位或几位。

verilog 复制代码
wire [7:0] data;  // 8-bit位宽线
reg  [15:0] addr; // 16-bit位宽寄存器

多位信号可以通过下标访问:

verilog 复制代码
a = data[0];    // 取最低位
b = data[7:4];  // 取高4位
用途 说明
表示多位数据 比如8位数据总线、16位寄存器、32位地址
方便整体操作 可以一次赋值、比较、传递
位选取灵活 可以随时取某几位,比如取高字节、低字节
节省命名空间 不用每一位单独声明变量

[高位:低位]强制要求高位写左边。

数组 Array

在 Verilog 中允许声明 reg, wire, integer, time, real 及其向量类型的数组,数组的大小代表深度

verilog 复制代码
reg y1 [11:0];  //是一个1-bit位宽,深度为12的寄存器
wire [7:0] y2 [11:0];  //是一个8-bit位宽,深度为12的线
reg [15:0] y3[0:1][0:3];  //二维数组

数组定义时,索引的定义可以自由选择,但通常使用 [高:低] 的写法。

写法 含义 应用习惯
[高:低](如 [11:0] 数字从高到低排列 通常用于总线、数据字节流,符合大部分硬件设计习惯
[低:高](如 [0:11] 数字从低到高排列 有些数组或存储器设计喜欢用递增顺序

其他类型

类型 说明 是否可综合 特别说明
integer 32位有符号整数变量 ✅ 可综合(但慎用) 适合建模简单计数器,但综合成硬件时表现不够精准
real 浮点实数变量 ❌ 不可综合 只能用于仿真,比如仿真计算,不能转成硬件
time 64位无符号整数,存仿真时间 ❌ 不可综合 只用于仿真(比如记录时间点)
realtime 浮点数形式存时间 ❌ 不可综合 和 time 类似,但有小数精度
string 字符串,存储在 reg 中 ❌ 理论可综合,但实际几乎只用于仿真 硬件几乎不会真的合成字符串
logic [n:0] SystemVerilog扩展型变量,结合了wire+reg特性 ✅ 可综合 现在新项目基本用 logic 代替 reg
概念 解释 举例
可综合(Synthesisable) 能够被综合工具(如 Vivado、Quartus)转成真正的硬件电路(逻辑门、触发器、存储单元等) wire, reg, logic
不可综合(Non-Synthesisable) 只在仿真阶段起作用,不能转成电路,硬件里不会存在对应结构 real, time, realtime, string

模块 module

  • 模块(module)是 Verilog 的基本单位,相当于C语言的函数、Java的类,代表一个可以综合为实际硬件的功能单元
  • 每一个 module 可以是一个门电路、触发器、加法器、CPU子模块,甚至整个SoC。

基本写法

Verilog模块的结构由在 module 和 endmodule 关键词之间的 4 个主要部分组成:

  • 端口定义 module 模块名 端口 1 端口 2
  • I/O 说明 包括输入 (input) 、 输出 (output) 和双向(inout)
  • 信号类型声明 声明信号的数据类型和函数声明 wire,reg, integer, real, time
  • 逻辑描述 用来描述设计模块的内部结构和模块端口间的逻辑关系 。 常用 assign 语句 、 always 块语句等方法实现
verilog 复制代码
module 模块名(端口列表);
    // 端口定义 (input output)
    // 内部信号定义(wire, reg等)
    // 电路描述(assign语句、always块等)
endmodule

例子:

verilog 复制代码
module block1(a,b,c,d);
    input a,b,c;
    output d;
    wire x;
    assign d = a|x;  //a或x 按位"或"运算
    assign x = (b & ~c);
endmodule
verilog 复制代码
module and_gate (input a, input b, output y);
  assign y = a & b;
endmodule

意思:建了一个名字叫 and_gate 的模块,它有两个输入端口 ab,一个输出端口 y,输出是 a AND b

模块实例化

模块是具一个有特定功能的设计单元, 在电路综合时模块会被 转 换为相应的数字电路

给定模块一组输入, 模块会返回一组输出, 这意味着模块可以被重复使用, 由此来实现更加复杂的电路(相当于函数)

verilog 复制代码
module mod1(input d, ...);
    // 模块内容
endmodule

module mod2;
    wire data;
    mod1 u0 (.d(data),...);
    // 模块内容
endmodule

mod1 u0 (.d(data),...);这句在实例化模型时,需要把本模块内的data信号连接到mod1模块的端口d上。

位置关联(不推荐)
verilog 复制代码
module my_module;
    wire a, b, c;

    and_gate u1 (a, b, c);  // a 连接 .a, b 连接 .b, c 连接 .y
endmodule

问题:你必须知道子模块端口的顺序,一旦顺序改了容易出错。


命名关联(推荐)
verilog 复制代码
and_gate u1 (
    .a(a),    // 上层的 a 连接到模块的 a
    .b(b),    // 上层的 b 连接到模块的 b
    .y(c)     // 上层的 c 连接到模块的 y
);

优点

  • 与顺序无关
  • 更直观、可读性强
  • 推荐用于所有复杂模块

带参数模块的实例化(parameter)

当模块带有 parameter 参数时,可以通过 #()语法传值:

模块定义

verilog 复制代码
module counter #(
    parameter WIDTH = 8
)(
    input clk,
    output [WIDTH-1:0] out
);
    ...
endmodule

实例化方式

verilog 复制代码
counter #(.WIDTH(4)) my_cnt (
    .clk(clk),
    .out(cnt_out)
);

多个实例的情况

可以实例化多个同一个模块:

verilog 复制代码
and_gate U1 (.a(a1), .b(b1), .y(y1));
and_gate U2 (.a(a2), .b(b2), .y(y2));

每次实例代表"一个新的电路副本"。

实践建议 说明
命名关联优于位置关联 尤其是模块接口复杂时
实例名推荐加前缀 u_and1, u_mux4
参数化模块要注意 default 给定默认值可提升复用性
用注释标出每个模块 增加结构清晰度

generate实例化

generate 是 Verilog 中的代码生成机制 ,用于在模块定义中动态、结构性地实例化多个模块、赋值、或条件逻辑

它本质上是语法上的工具 ,允许我们在模块中通过 forif 等控制结构,自动生成重复或条件性的硬件结构。

generate 可以用来循环实例化模块条件实例化模块

它常用于:

  • 批量实例化模块(如多个乘法器、加法器)
  • 条件生成不同的硬件结构
  • 构建参数化设计(如可变位宽)

因为重复构建多个实例是结构层面的代码,不是行为逻辑 ,因此不能用 alwaysiffor 这种行为语句来写,必须用 generate

基本语法
verilog 复制代码
generate
    // 结构代码
endgenerate

generate ... endgenerate 包围的结构会在编译时处理,不会在仿真或综合时运行。


for-generate 用法(循环生成)
verilog 复制代码
genvar i; // 必须用 genvar 声明控制变量

generate
    for (i = 0; i < N; i = i + 1) begin : gen_block
        // 可实例化模块、连接线、赋值等
    end
endgenerate

说明:

  • genvar 是 generate 专用的变量,不能用于普通 always 块
  • gen_block 是可选的名字,用于结构层次(类似作用域)

if-generate 用法(条件生成)
verilog 复制代码
generate
    if (USE_REG == 1) begin : reg_block
        // 生成寄存器逻辑
    end else begin : comb_block
        // 生成组合逻辑
    end
endgenerate

常用于根据参数开关生成不同的硬件结构。


case-generate 用法(多分支生成)
verilog 复制代码
generate
    case (WIDTH)
        8:  begin : w8  // 8位逻辑
        end
        16: begin : w16 // 16位逻辑
        end
    endcase
endgenerate

根据参数选择不同硬件实现(比如不同位宽的乘法器)。


用途 描述
多模块实例化 自动生成多个模块副本
参数化设计 根据传入的参数动态生成逻辑
条件生成 控制生成哪种逻辑(例如是否使用寄存器)
多分支生成 根据参数做 case 分支

注意事项:

  1. genvar 只能在 generate 块中使用
  2. generate 块中的变量不会出现在仿真或综合时刻的信号列表中
  3. 实例名称尽量唯一,可用 gen_block[i] 等结构防止冲突
  4. generate 是静态生成语法,不可在运行时决定

【例子】
verilog 复制代码
// 半加器模块的定义
module ha ( input a, b,        // 输入 a 和 b
            output sum, cout  // 输出 sum 和进位 cout
          );

    assign sum = a ^ b;        // sum 为 a 和 b 的异或运算结果
    assign cout = a & b;       // cout 为 a 和 b 的与运算结果(即进位)
endmodule

// 顶层模块:包含 N 个半加器实例
module my_design
    #(parameter N = 4)         // 定义参数 N,默认值为 4,表示半加器的个数
    (
        input  [N-1:0] a, b,   // 输入 a、b 是 N 位的向量
        output [N-1:0] sum, cout // 输出 sum 和 cout 也是 N 位向量
    );

    // 声明一个用于 generate 的临时变量 i,仿真时不可见
    genvar i;

    // generate-for 循环,实例化 N 个半加器
    generate
        for (i = 0; i < N; i = i + 1) begin
            // 实例化名为 u0 的半加器模块,第 i 位的输入和输出分别连接
            ha u0 (
                .a(a[i]),        // 输入 a 的第 i 位
                .b(b[i]),        // 输入 b 的第 i 位
                .sum(sum[i]),    // 输出 sum 的第 i 位
                .cout(cout[i])   // 输出 cout 的第 i 位
            );
        end
    endgenerate

endmodule

运算符

在逻辑运算中 如果操作数不止一位 应将操作数作为一个整体来对待

算术运算符

运算符 含义 示例 说明
+ 加法 a + b
- 减法 a - b
* 乘法 a * b
/ 除法 a / b 整数除法,小数部分舍弃
% 取模(余数) a % b

注意 :除法/取整除,不是浮点数除法!


比较运算符(返回1或 0 或 x)

运算符 含义 示例 结果
== 等于 a == b 相等为1,不等为0,不确定为 X
!= 不等于 a != b
=== 全等于 a === b 相等为1,不等为0
!== 不全等于 a !== b
< 小于 a < b
> 大于 a > b
<= 小于等于 a <= b
>= 大于等于 a >= b

==!= 的特点(普通等于)

  • 只看数值是否一致
  • 忽略 未知值 X 或高阻值 Z
  • 若任一位为 XZ,比较结果是 X(也就是逻辑不确定)

===!== 的特点(全等运算符

  • 会逐位比较
  • 不会忽略 XZ
  • 只有每一位都完全一致(包括 X/Z),才返回 1

使用建议:

场景 建议用
判断具体数值(如状态) 使用 ==
判断信号是否含 X 或用于测试用例 使用 ===
testbench 中对 X/Z 做比较 一定用 ===!==
case语句中的匹配项 默认用 ==,可以用 casez/casex 处理模糊匹配

位逻辑运算符(逐位操作)

两个不同长度的操作数进行位运算时, 将自动按右端对齐 , 位数少的操作数会在高位用 0 补齐

运算符 含义 示例 说明
~ 按位取反 ~a 0变1,1变0
& 按位与 a & b 两位都1,结果才是1
` ` 按位或 `a
~& 与非
`~ ` 或非
^ 按位异或 a ^ b 不同为1,相同为0
~^^~ 按位同或(XNOR) a ~^ b 相同为1,不同为0

逻辑运算符(整体为0或1)

运算符 含义 示例 说明
! 逻辑非 !a a为0则返回1,非0返回0
&& 逻辑与 a && b 两个都非0才返回1
` `

区别

  • 位运算每一位单独算
  • 逻辑运算整体判断真假(0或非0)

移位运算符

在移位运算中 将操作数左移或者右移后空位补 0

运算符 含义 示例 说明
<< 左移 a << 2 左移2位,右边补0
>> 右移 a >> 2 右移2位,左边补0(逻辑右移)
<<< 算术左移 a <<< 2 保持符号位,左移(和逻辑左移相同)
>>> 算术右移 a >>> 2 保持符号位(最高位扩展)右移

✅ 一般情况下,普通>>逻辑右移,>>>符号扩展右移。


条件运算符(三目运算符)

运算符 含义 示例
? : 条件判断 d = sel ? a : b;

意思是:

  • 如果 sel==1,那么 d=a
  • 如果 sel==0,那么 d=b

拼接与重复运算符

拼接运算符 { , }

  • 把多个信号拼接成一个大的信号。

例子:

verilog 复制代码
{a, b}   // a在高位,b在低位

如果:

verilog 复制代码
a = 4'b1100;
b = 4'b0011;
{a,b} = 8'b11000011;

重复运算符 {N{表达式}}

  • 把表达式复制N次。

例子:

verilog 复制代码
{4{1'b1}}  // 结果是 4'b1111

优先级

顺序(高到低):

复制代码
1. () 小括号
2. ~ ! 取反(位、逻辑)
3. * / % 乘除取模
4. + - 加减
5. << >> <<< >>> 移位
6. < <= > >= 比较
7. == != 等于、不等
8. & 位与
9. ^ ~^ 位异或/同或
10. | 位或
11. && 逻辑与
12. || 逻辑或
13. ?: 条件选择

✅ 写复杂表达式时,一定多用小括号 (),不要只靠优先级,避免出错。

分类 常用运算符
算术运算 + - * / %
比较运算 == != < > <= >=
位运算 `~ &
逻辑运算 `! &&
移位运算 << >> <<< >>>
条件运算 ? :
拼接/重复 { , }, {N{}}

信号赋值

assign 连续赋值(只给wire用)

  • 用来连接信号或者表达式。
  • 等式左边必须是一个标量或者线性向量,而不能是寄存器类型
  • 等式右边的类型没有要求,等式右边的值一旦发生变化,就会立刻重新计算并同时赋值给左侧

例子:

verilog 复制代码
assign y = a & b;

意思:y 始终是 ab 按位与的结果。

分类 特点 常用赋值方式
wire 连线,不存储数据 assign
reg 存储单元,可在always赋值 always块
assign 连续赋值,只能给wire assign y = a & b;
always块 过程赋值,时序或组合逻辑 always @(...) begin ... end

wire初始化写法

这段:

verilog 复制代码
wire c = 1'b0;

实际上是简写,它等价于:

verilog 复制代码
wire c;
assign c = 1'b0;

就是说:

  • 声明了一根名叫c的线。
  • 然后用assign1'b0这个常量连上去。
  • 在综合和仿真里,c就相当于一直是0。
常量表示法
  • N'bX格式

    • N是位宽(多少位)
    • 'b是进制(b是binary,d是decimal,h是hexadecimal)
    • X是值
  • 例子:

    verilog 复制代码
    4'b1010  // 4位宽,二进制1010
    8'd255   // 8位宽,十进制255
    16'h1A2B // 16位宽,16进制1A2B

过程赋值(时序控制)

  • 阻塞赋值(=):语句顺序执行。下一条语句执行前,当前语句一定会执行完毕。

    【例】:

    verilog 复制代码
    always @(posedge clk) begin
        b=a
        c=b
    end
  • 非阻塞赋值(<=):语句并行执行,常用于时序逻辑(如D触发器)。下一条语句和当前语句是同时进行的。

    【例】:

    verilog 复制代码
    always @(posedge clk)begin
        b <= a;
        c <= b;
    end

    不要在同一个 always 块中混用 =<= 对同一个变量赋值

类型 运算符 执行顺序 典型作用域 用法建议
阻塞赋值 = 顺序执行 initialalways @* 组合逻辑、测试初始化等
非阻塞赋值 <= 并发执行 always @(posedge ...) 时序逻辑

always块(过程赋值)

过程赋值 是在 initial 或 always 语句块里的赋值 主要用于对寄存器(rag)类型变量进行赋值。

寄存器变量在被赋值后,其值将保持不变,直到重新被赋予新值

  • 描述时序逻辑或组合逻辑。
  • 过程赋值可以是**阻塞赋值 **或者 非阻塞赋值

always 语句块通常带有触发条件
语句块中的语句会重复执行,一个变量不能在多个 always 块中被赋值。
在 always 块中被赋值的只能是 register 型变量
always 语句块即可以用来实现组合逻辑也可以用来实现时序逻辑

基础语法:

verilog 复制代码
always @(sensitivity_list)
begin
    // 一系列语句
end

其中 sensitivity_list 是敏感列表,表示当列表中的信号发生变化时触发 always 块。

always 块的分类

根据 sensitivity_list 内容不同,分为以下几种类型:

① 组合逻辑(组合逻辑电路建模)

verilog 复制代码
always @(*)  // 或 always @(a or b or sel)
begin
    // 组合逻辑
end

等价于 assign 写的逻辑,常用于使用 ifcase 等构建复杂组合逻辑。

🔸 示例:多路选择器(MUX)

verilog 复制代码
module mux_2to1 (
    input wire a, b,
    input wire sel,
    output reg y
);
    always @(*) begin
        if (sel)
            y = b;
        else
            y = a;
    end
endmodule

② 时序逻辑(用于寄存器建模)

verilog 复制代码
always @(posedge clk)
begin
    // 时序逻辑(寄存器)
end

verilog 复制代码
always @(posedge clk or negedge rst_n)
begin
    if (!rst_n)
        q <= 0;
    else
        q <= d;
end

🔸 示例:D触发器

verilog 复制代码
module dff (
    input clk,
    input rst_n,
    input d,
    output reg q
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            q <= 1'b0;
        else
            q <= d;
    end
endmodule

③ 时序逻辑 + 状态机

🔸 示例:简单 FSM(两个状态,翻转输出)

verilog 复制代码
module fsm (
    input clk, rst_n,
    input in,
    output reg out
);
    reg state;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            state <= 1'b0;
        else
            state <= ~state;
    end

    always @(*) begin
        if (state)
            out = in;
        else
            out = ~in;
    end
endmodule
项目 内容
@(*) 自动推导敏感信号,建议用于组合逻辑
=(阻塞赋值) 常用于组合逻辑
<=(非阻塞赋值) 常用于时序逻辑
always 不是函数 它是对"硬件电路行为"的一种模拟
多个 always 可同时使用 同时描述不同逻辑块或功能单元

类型 敏感列表 用途 赋值类型
组合逻辑 @(*) 多路选择器、加法器等 =
时序逻辑 @(posedge clk)@(posedge clk or negedge rst) 寄存器、计数器、状态机 <=
状态机建模 多个 always 配合使用 控制逻辑、序列识别 混合

另外,不带有敏感信号的 always 语句块会一直执行,因此可用于仿真时钟信号生成

verilog 复制代码
always #10 clk = ~clk;

initial块(只在仿真用)

  • 只在仿真(simulation)时使用。沿时间轴只执行一次。
  • 主要用途是在仿真的初级阶段对各变量进行初始化
  • 在电路上不综合成硬件。

【例】:初始时,a赋0,b赋1。

verilog 复制代码
initial begin
  a = 0;
  b = 1;
end

组合逻辑 vs 时序逻辑

  • 组合逻辑:输出只依赖输入,没有存储状态

    verilog 复制代码
    assign y = a & b;

    或者

    verilog 复制代码
    always @(a or b) begin
      y = a & b;
    end
  • 时序逻辑:输出依赖时钟(clk),有状态记忆

    verilog 复制代码
    always @(posedge clk) begin
      q <= d;
    end

关键语法

  • 模块定义

    verilog 复制代码
    module module_name (input a, input b, output y);
      // 逻辑
    endmodule
  • 连续赋值

    verilog 复制代码
    assign y = a & b;
  • 过程块

    • always块(常用于描述时序逻辑和组合逻辑)

      verilog 复制代码
      always @(posedge clk) begin
        q <= d;
      end
    • initial块(仅用于仿真初始化)

      verilog 复制代码
      initial begin
        a = 0;
        b = 1;
      end
  • **设计层次

结构建模(Structural Modeling)

像搭积木一样,用已有的模块(门级、子模块)实例化并连接,描述硬件结构。

特点:

  • 接近硬件电路图结构
  • 每个模块都要明确实例化
  • 比如用 andorxornot 或用户定义模块来搭建电路

示例(半加器结构建模):

verilog 复制代码
module ha (input a, b, output sum, cout);
    wire xor_out, and_out;

    xor u1 (xor_out, a, b);  // 门级建模
    and u2 (and_out, a, b);

    assign sum = xor_out;
    assign cout = and_out;
endmodule

也可以这样模块化使用:

verilog 复制代码
module top;
    wire s, c;
    ha u0 (.a(1'b1), .b(1'b0), .sum(s), .cout(c)); // 实例化 half-adder
endmodule

📌 优点:

  • 电路结构直观,适合底层硬件构建
  • 可以重用子模块

⚠️ 缺点:

  • 不适合复杂逻辑描述
  • 可读性差,模块多时臃肿

数据流建模(Dataflow Modeling)

数据流建模 方式要比结构化描述方式抽象级别要高一些,因为它不在需要清因为它不在需要清晰地刻画出具体的数字电路架构

连续赋值语句(assign表示信号间的数据传递关系,相当于表达电路逻辑函数

特点:

  • 更抽象,强调"数据如何流动"
  • 使用 assign + 表达式建模逻辑
  • 属于组合逻辑

示例(半加器的数据流建模):

verilog 复制代码
module ha (input a, b, output sum, cout);
    assign sum = a ^ b;
    assign cout = a & b;
endmodule

📌 优点:

  • 简洁易写,适合组合逻辑
  • 比结构更抽象,便于阅读

⚠️ 缺点:

  • 不适用于时序逻辑(需要时钟的寄存器等)
  • 纯数据流的描述方式只适用于小规模的电路设计

行为建模(Behavioral Modeling)

行为描述 是对设计电路的逻辑功能的描述 并不关心设计电路使用哪些元件以及这些元件之间的连接关系(更接近高级语言)

属于高层次的描述方法 类似高级语言可以使用 控制流循环语句 等功能

描述电路行为,比如if-else、case等。

定义:

描述的是"行为"或"功能",用**过程语句(alwaysinitial)**来控制电路行为。更接近写软件代码的风格。

特点:

  • 使用 always 块来表示组合/时序逻辑
  • 可使用 ifcasefor 等语句
  • 分为组合逻辑建模和时序逻辑建模

示例(时序逻辑建模 - 寄存器):

verilog 复制代码
module dff(input clk, rst, d, output reg q);
    always @(posedge clk or negedge rst) begin
        if (!rst)
            q <= 1'b0;
        else
            q <= d;
    end
endmodule

📌 优点:

  • 抽象度最高,适合复杂控制逻辑(如 FSM)
  • 逻辑简洁,代码量少

⚠️ 缺点:

  • 与硬件结构关系不直接,难以优化资源
  • 更依赖综合工具识别其意图
常用语句
  • if语句

    verilog 复制代码
    always @(a or b) begin
      if (a)
        y = 1;
      else
        y = 0;
    end
  • case语句

    verilog 复制代码
    always @(sel or a or b) begin
      case(sel)
        0: y = a;
        1: y = b;
        default: y = 0;
      endcase
    end
  • for循环(通常只用于仿真或者可综合的有限循环)

    1.给控制循环次数的变量赋初值

    2.判定循环执行条件, 若为假则跳出循环;若为真, 执行指定的语句后, 转到第 3 步

    3.修改循环变量的值 返回第 2 步

    verilog 复制代码
    integer i;
    always @(posedge clk) begin
      for (i = 0; i < 8; i = i + 1)
        mem[i] <= 0;
    end
  • while循环

    执行一条语句直到某个条件不满足 。

    首先判断循环执行条件表达式是否为真:

    若为真 则执行后面的语句或语句块 直到条件表达式不为真;

    若不为真 则其后的语句一次也不被执行

  • repeat 语句

  • forever语句

  • task语句

  • function语句

其他常见概念

  • 参数(parameter):定义常量或可配置的参数。

    verilog 复制代码
    parameter WIDTH = 8;
    wire [WIDTH-1:0] data;
  • 生成块(generate):用于生成结构化重复硬件(如阵列结构)。

    verilog 复制代码
    genvar i;
    generate
      for (i = 0; i < 4; i = i + 1) begin
        my_module u (.in(in[i]), .out(out[i]));
      end
    endgenerate
  • 仿真专用语句

    • $display:打印信息。
    • $monitor:实时监视信号变化。
    • $finish:仿真结束。

测试平台(Testbench)

  • Testbench是验证设计模块正确性的仿真代码,不综合进电路。
  • 包含:
    • initial块生成激励(stimulus)
    • 实例化待测模块(DUT)
    • 观察输出(可加断言、检查)
相关推荐
FPGA_ADDA9 小时前
基于PXIE 总线架构的Kintex UltraScale 系列FPGA 高性能数据预处理板卡
fpga开发·pxie总线·ku060·ku115
搬砖的小码农_Sky18 小时前
FPGA:Lattice的FPGA产品线以及器件选型建议
嵌入式硬件·fpga开发·硬件架构·硬件工程
超能力MAX20 小时前
ZYNQ-AXI4 DDR读写测试
fpga开发
fpga小白历险记21 小时前
BUFDS_GTE2,IBUFDS,BUFG缓冲的区别
fpga开发
zly88653721 天前
MMIO机制详解
fpga开发
北京青翼科技1 天前
【PXIE301-211】基于PXIE总线的16路并行LVDS数据采集、1路光纤数据收发处理平台
图像处理·fpga开发·信号处理
霖002 天前
PCIe数据采集系统
数据结构·经验分享·单片机·嵌入式硬件·fpga开发·信号处理
FakeOccupational2 天前
fpga系列 HDL : Microchip FPGA开发软件 Libero Soc 安装 & license申请
fpga开发
千歌叹尽执夏2 天前
FPGA: UltraScale+ bitslip实现(ISERDESE3)
fpga开发·training·ultrascale+·bitslip