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提高代码复用性(如位宽可配置)。

相关推荐
3有青年9 小时前
Altera FPGA操作系统支持的情况分析
fpga开发
国科安芯10 小时前
卫星通讯导航FPGA供电单元DCDC芯片ASP4644S2B可靠性分析
单片机·嵌入式硬件·fpga开发·架构·安全性测试
stars-he13 小时前
FPGA学习笔记-图书馆存包柜,乒乓球游戏电路设计
笔记·学习·fpga开发
从此不归路13 小时前
FPGA 结构与 CAD 设计(第3章)下
ide·fpga开发
YprgDay15 小时前
Vivado单独综合某一模块查看资源消耗
fpga开发·vivado
Joshua-a15 小时前
高云FPGA在线调试/逻辑分析仪简要使用流程
嵌入式硬件·fpga开发·高云
博览鸿蒙1 天前
FPGA 工程中常见的基础硬件问题
fpga开发
GateWorld2 天前
FPGA 实现无毛刺时钟切换
fpga开发·实战·无毛刺时钟
Seraphina_Lily2 天前
从接口选型到体系结构认知——谈 CPU–FPGA–DSP 异构处理系统与同构冗余设计
fpga开发
Seraphina_Lily2 天前
CPU–FPGA–DSP 异构系统中的总线接口选型——为什么 CPU 用 eLBC,而 DSP 用 XINTF?
fpga开发