Verilog 语言基础学习

一、Verilog 语言概述

  • 用途:硬件描述语言(HDL),用于数字电路设计、仿真和综合。
  • 设计层次:从门级(Gates)到行为级(Behavioral),支持自顶向下(Top-Down)和自底向上(Bottom-Up)设计。
  • 核心思想:通过模块(Module)描述电路功能,模块间通过端口(Port)连接。

二、基本语法

1. 模块结构(Module)
复制代码
module 模块名(端口列表);
    // 端口声明(输入、输出、双向)
    input  [位宽-1:0] 输入端口;  // 例:input [3:0] a;
    output [位宽-1:0] 输出端口;
    inout  [位宽-1:0] 双向端口;  // 需配合三态门(tri)
    
    // 内部信号声明(reg/wire)
    reg   [位宽-1:0] 寄存器型;  // 用于时序逻辑(always块内赋值)
    wire  [位宽-1:0] 线网型;    // 用于组合逻辑(assign赋值或模块间连接)
    
    // 逻辑描述(组合/时序逻辑)
    // ...
    
endmodule
2. 数据类型
  • 线网型(Wire)

    • 表示物理连线,无存储功能,需持续驱动(assign或模块输出)。
    • 例:wire [7:0] data;
  • 寄存器型(Reg)

    • 表示存储单元(如触发器),在always块内赋值,默认初始值为x(未知)。
    • 例:reg clk;
  • 其他类型

    • integer:32 位有符号整数(仿真用,不推荐综合)。

    • parameter:参数(常量),用于定义位宽、延迟等。

      复制代码
      parameter WIDTH = 8;  // 定义参数
      reg [WIDTH-1:0] data;
3. 运算符
类型 运算符示例
算术运算 + - * / %(取模)
逻辑运算 &&(与) ` (或) !`(非)
位运算 & ` ~(非) ^`(异或)
关系运算 == != < > <= >=
移位运算 <<(左移) >>(右移)
拼接运算 {a, b[2:0], 1'b1}(组合信号)
4. 组合逻辑描述
  • assign语句(连续赋值,用于 wire 型):

    复制代码
    assign out = a & b;  // 与门
    assign {c_out, sum} = a + b + c_in;  // 全加器(拼接结果)
  • always @(*)(敏感于所有输入,用于 reg 型):

    复制代码
    reg [1:0] out;
    always @(*) begin  // * 表示所有输入信号变化时触发
        case (sel)
            2'b00: out = a;
            2'b01: out = b;
            2'b10: out = c;
            default: out = 2'bxx;  // 避免 latch
        endcase
    end

    注意 :组合逻辑always块需覆盖所有输入情况,否则会生成锁存器(Latch),不推荐。

5. 时序逻辑描述
  • 边沿触发(触发器)

    复制代码
    reg [7:0] data_reg;
    always @(posedge clk or negedge rst_n) begin  // 上升沿触发,低电平复位
        if (!rst_n) begin
            data_reg <= 8'd0;  // 复位状态
        end else begin
            data_reg <= data_in;  // 时钟沿更新
        end
    end

    注意 :时序逻辑用非阻塞赋值(<=),避免竞争冒险。

6. 条件与循环语句
  • if-else

    复制代码
    always @(*) begin
        if (en) out = a;
        else out = b;
    end
  • case

    复制代码
    always @(*) begin
        casez (addr)  // casez 忽略z位,casex忽略x/z位
            3'b1??: out = 8'hff;
            3'b01?: out = 8'h00;
            default: out = 8'hxx;
        endcase
    end
  • 循环语句(主要用于仿真,综合支持有限):

    复制代码
    // 生成块(generate,用于重复实例化)
    generate
        genvar i;
        for (i=0; i<4; i=i+1) begin: reg_array
            reg dff;
            always @(posedge clk) dff <= data[i];
        end
    endgenerate
7. 模块实例化
  • 位置关联:按端口顺序连接。

    复制代码
    adder u_adder (a, b, c_in, sum, c_out);  // 实例名 u_adder
  • 名称关联(推荐,可读性好):

    复制代码
    adder u_adder (
        .a(a),
        .b(b),
        .c_in(carry_in),
        .sum(result),
        .c_out(carry_out)
    );

三、常用电路示例

1. 2 选 1 多路选择器
复制代码
module mux2_1(
    input a, b, sel,
    output out
);
    assign out = sel ? b : a;  // 组合逻辑
endmodule
2. 4 位加法器(带进位)
复制代码
module adder_4bit(
    input [3:0] a, b,
    input c_in,
    output [3:0] sum,
    output c_out
);
    assign {c_out, sum} = a + b + c_in;  // 拼接运算
endmodule
3. D 触发器(带异步复位)
复制代码
module dff(
    input clk, rst_n, d,
    output reg q
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) q <= 1'b0;
        else q <= d;
    end
endmodule
4. 计数器(模 16)
复制代码
module counter_16(
    input clk, rst_n, en,
    output reg [3:0] cnt,
    output reg overflow
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt <= 4'd0;
            overflow <= 1'b0;
        end else if (en) begin
            if (cnt == 4'd15) begin
                cnt <= 4'd0;
                overflow <= 1'b1;
            end else begin
                cnt <= cnt + 1'b1;
                overflow <= 1'b0;
            end
        end
    end
endmodule

四、仿真相关(Testbench)

  • 用于验证设计的正确性,生成激励信号并观察输出。

    module tb_counter; // 测试模块(无端口)
    reg clk, rst_n, en;
    wire [3:0] cnt;
    wire overflow;

    复制代码
      // 实例化被测试模块
      counter_16 u_counter(
          .clk(clk),
          .rst_n(rst_n),
          .en(en),
          .cnt(cnt),
          .overflow(overflow)
      );
      
      // 生成时钟(50MHz,周期20ns)
      initial begin
          clk = 1'b0;
          forever #10 clk = ~clk;
      end
      
      // 生成激励
      initial begin
          rst_n = 1'b0;  // 复位
          en = 1'b0;
          #20 rst_n = 1'b1;  // 20ns后释放复位
          #10 en = 1'b1;     // 使能计数
          #300 en = 1'b0;    // 300ns后停止
          #50 $finish;       // 结束仿真
      end
      
      // 打印输出
      initial begin
          $monitor("Time: %0t, cnt: %d, overflow: %b", $time, cnt, overflow);
      end

    endmodule

五、关键注意事项

  1. 组合逻辑 vs 时序逻辑

    • 组合逻辑:无时钟,用assignalways @(*),阻塞赋值(=)。
    • 时序逻辑:有时钟,用always @(posedge clk),非阻塞赋值(<=)。
  2. 避免 Latch :组合逻辑需覆盖所有输入情况(ifelsecasedefault)。

  3. 可综合性 :仿真语句(如$display#延迟)不能被综合,仅用于 Testbench。

  4. 参数化设计 :用parameter提高代码复用性(如位宽可配置)。

相关推荐
brave and determined7 小时前
可编程逻辑器件学习(day26):低主频FPGA为何能碾压高主频CPU?
人工智能·嵌入式硬件·深度学习·学习·fpga开发·云计算·fpga
the sun348 小时前
数电基础:移位寄存器、顺序脉冲、序列信号发生器
单片机·嵌入式硬件·fpga开发·数电
海涛高软2 天前
yolov8目标检测训练在rk3588上部署
fpga开发
第二层皮-合肥2 天前
USB3.0专题-硬件的测试
fpga开发
hexiaoyan8272 天前
高速数据采集卡设计方案:886-基于RFSOC的8路5G ADC和8路9G的DAC PCIe卡
fpga开发·高速数据采集卡·光纤pcie卡·通用pcie卡·xc7a100t板卡
嵌入式软硬件攻城狮2 天前
2.FPGA板卡通过电脑映射连接上网
fpga开发·电脑
brave and determined2 天前
可编程逻辑器件学习(day22):“让ARM穿上FPGA的马甲“:赛灵思Zynq的命名哲学与技术革命
arm开发·嵌入式硬件·fpga开发·zynq·fpga设计·嵌入式设计·fpga开发流程
FPGA_小田老师3 天前
FPGA语法基础(二):SystemVerilog 数组清零方法详解
fpga开发·systemverilog·数组清零·systemverilog数组·systemverilog语法
jiushun_suanli3 天前
FPGA(现场可编程门阵列)详解
经验分享·学习·fpga开发