目录

  1. Verilog 基础语法概述
  2. 模块定义
  3. 数据类型
  4. 运算符
  5. 常见控制结构
  6. 时序控制
  7. Verilog 实例
  8. 参考资料

Verilog 基础语法概述

Verilog 是一种硬件描述语言 (HDL),用于描述数字电路的结构和行为。它被广泛应用于 FPGA、ASIC 的设计与验证。Verilog 语言本身的语法结构与 C 语言类似,但专门为硬件设计进行了优化。其基本语法包括模块定义、数据类型、运算符、控制结构、时序控制等。


模块定义

在 Verilog 中,设计是由模块 (module) 组成的。每个模块通过 module 关键字定义,模块的端口(输入和输出)通过端口列表定义。

module module_name(input_port, output_port);
    // 输入端口定义
    input wire [3:0] input_port;
    // 输出端口定义
    output wire [3:0] output_port;
    
    // 模块内容
    
endmodule

端口类型

  • input:表示输入端口。
  • output:表示输出端口。
  • inout:表示双向端口,既可输入也可输出。

端口的定义方式

端口可以是单比特或多比特(位宽定义)。例如,input [3:0] 表示一个 4 位宽的输入端口。


数据类型

Verilog 中的基本数据类型包括:

  • wire:表示电路的连接线或信号线。通常用于组合逻辑。
  • reg:表示寄存器,通常用于存储信号的状态。在时序逻辑中使用。
  • integer:整数类型,通常用于描述数值。
  • real:实数类型,通常用于模拟电路的计算。
  • time:表示时间单位,通常用于仿真。

示例:定义数据类型

module example;
    wire [3:0] signal;     // 4 位宽的信号线
    reg [7:0] register;    // 8 位宽的寄存器
    integer count;          // 整数类型
    real delay_time;        // 实数类型
    time clk_time;          // 时间类型
endmodule


运算符

Verilog 支持与 C 语言类似的各种运算符。常见的运算符包括:

1. 算术运算符

  • +:加法
  • -:减法
  • *:乘法
  • /:除法
  • %:取余

2. 比较运算符

  • ==:相等
  • !=:不等
  • <:小于
  • >:大于
  • <=:小于等于
  • >=:大于等于

3. 逻辑运算符

  • &&:逻辑与
  • ||:逻辑或
  • !:逻辑非

4. 位运算符

  • &:按位与
  • |:按位或
  • ^:按位异或
  • ~:按位非
  • <<:左移
  • >>:右移

5. 条件运算符

assign result = (a > b) ? 1 : 0;  // 如果 a > b,result 为 1,否则为 0


常见控制结构

Verilog 提供了多种控制结构,用于描述电路的行为。

1. if-else 语句

always @ (a or b) begin
    if (a > b)
        y = a;
    else
        y = b;
end

2. case 语句

Verilog 中的 case 语句可以用来选择多个条件中的一个。它类似于 C 语言中的 switch 语句。

always @ (select) begin
    case(select)
        2'b00: y = 4'b0001;
        2'b01: y = 4'b0010;
        2'b10: y = 4'b0100;
        2'b11: y = 4'b1000;
        default: y = 4'b0000;
    endcase
end

3. 循环语句

Verilog 支持 forwhilerepeat 循环语句。

for 循环

for (i = 0; i < 10; i = i + 1) begin
    // 执行循环体
end

while 循环

while (a < 10) begin
    a = a + 1;
end

repeat 循环

repeat (5) begin
    // 执行循环体
end


时序控制

Verilog 主要用于描述硬件的时序行为,时序控制主要依赖于时钟信号和复位信号。常见的时序控制语句包括 alwaysinitial

1. always 块

always 块用来描述时序逻辑,它是由时钟信号驱动的,通常用于描述触发器和状态机。

always @ (posedge clk or negedge rst) begin
    if (~rst)
        q <= 0;
    else
        q <= d;
end

  • posedge:上升沿触发
  • negedge:下降沿触发

2. initial 块

initial 块在仿真开始时执行一次。通常用于初始化信号或设置初始条件。

initial begin
    a = 0;
    b = 1;
end

3. 延迟与事件控制

Verilog 支持对信号的延迟控制和事件控制。

#10 a = 1;  // 延迟 10 个时间单位后将 a 赋值为 1


Verilog 实例

以下是一个简单的 Verilog 示例,展示了如何用 Verilog 语言设计一个 4 位加法器:

module adder (
    input [3:0] a, b,     // 输入信号
    output [3:0] sum,     // 输出信号
    output carry_out      // 进位输出
);
    assign {carry_out, sum} = a + b;  // 通过加法器计算和与进位
endmodule

Testbench 示例

为了验证加法器的正确性,可以编写一个简单的 Testbench:

module testbench;
    reg [3:0] a, b;        // 输入信号
    wire [3:0] sum;        // 输出信号
    wire carry_out;        // 进位输出

    adder uut (
        .a(a),
        .b(b),
        .sum(sum),
        .carry_out(carry_out)
    );

    initial begin
        a = 4'b0101; b = 4'b0011;  // 设置输入值
        #10;
        a = 4'b1111; b = 4'b0001;  // 修改输入值
        #10;
        $finish;  // 结束仿真
    end

    initial begin
        $monitor("a=%b, b=%b, sum=%b, carry_out=%b", a, b, sum, carry_out);
    end
endmodule


参考资料