4. 硬件描述语言速通:Verilog/VHDL核心语法、组合逻辑与时序逻辑、状态机设计

好,咱们直接切入正题。FPGA 开发,说白了就是用硬件描述语言(HDL)去“画电路”。你写的每一行代码,最终都会变成实实在在的门电路、触发器和连线。这和写软件完全是两码事——软件是顺序执行的,硬件是并行工作的。这个思维转变,是入门的第一道坎。

我个人习惯用 Verilog,因为它语法更灵活,在金融交易领域用得也最多。但 VHDL 在军工、航天领域依然很强势。咱们这章以 Verilog 为主线,同时我会点出 VHDL 的关键差异。你只要精通一门,另一门看语法表就能上手。

4.1 核心语法:从“线”到“寄存器”

先看最基本的元素。在 FPGA 里,数据流动靠的是“线”(wire)和“寄存器”(reg)。

  • wire:组合逻辑的输出,相当于物理连线。你不能在 always 块里给它赋值。
  • reg:时序逻辑的存储单元,可以理解为 D 触发器。注意,reg 不一定是寄存器,在组合逻辑的 always 块里它也能用,但我不建议这么干——容易把自己绕晕。

举个例子,一个简单的与门:

// Verilog
module and_gate (
    input  wire a,
    input  wire b,
    output wire y
);
    assign y = a & b;
endmodule

对应的 VHDL 写法:

-- VHDL
entity and_gate is
    port (
        a : in  std_logic;
        b : in  std_logic;
        y : out std_logic
    );
end entity;

architecture rtl of and_gate is
begin
    y <= a and b;
end architecture;

看到区别了吗?Verilog 用 assign 连续赋值,VHDL 用 <= 信号赋值。本质上都是描述组合逻辑。

我的小技巧: 在写组合逻辑时,我习惯用 assignalways @(*)。千万别把组合逻辑和时序逻辑混在一个 always 块里,否则综合工具会给你一堆警告,甚至综合出意想不到的锁存器(latch)。我曾经在一个高频交易项目里,就因为少写了一个 else 分支,综合出了一个 latch,导致整个流水线时序崩溃……排查了整整两天。

4.2 组合逻辑 vs 时序逻辑:核心区别

这是 FPGA 设计的灵魂。你想想看,为什么交易系统需要 FPGA?因为我们要在 一个时钟周期内 完成复杂的计算。组合逻辑负责“算”,时序逻辑负责“存”和“同步”。

特性 组合逻辑 时序逻辑
输出依赖 仅当前输入 当前输入 + 历史状态
存储能力 有(寄存器)
时钟 不需要 需要(边沿触发)
典型代码 assign / always @(*) always @(posedge clk)
延迟 门延迟(ns级) 时钟周期延迟

举个实际例子。在交易系统中,我们需要计算买卖价差(spread)。这个计算本身是组合逻辑:

// 组合逻辑:计算价差
wire [31:0] bid_price, ask_price;
wire [31:0] spread;

assign spread = ask_price - bid_price;

但如果你要把这个结果传给下一级模块,就必须用寄存器打一拍:

// 时序逻辑:寄存结果
reg [31:0] spread_reg;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        spread_reg <= 32'd0;
    else
        spread_reg <= spread;
end

为什么要多此一举?因为组合逻辑的输出可能有毛刺(glitch),而且路径延迟不确定。寄存器可以消除毛刺,让数据在时钟边沿稳定采样。嗯,这里要注意:在高速交易系统里,每一拍延迟都意味着真金白银。所以我们会尽量压缩流水线级数,但绝不能为了省一级寄存器而牺牲时序收敛。

避坑指南: 我曾经见过一个新手,在 always 块里同时写了组合逻辑和时序逻辑,结果综合出来的电路多了一堆不必要的寄存器。记住:always @(posedge clk) 里只放时序逻辑,always @(*) 里只放组合逻辑。这是铁律。

4.3 状态机设计:交易系统的“大脑”

状态机(FSM)是控制逻辑的核心。在交易系统中,状态机用来管理订单生命周期:从“空闲”到“发送订单”,再到“等待确认”,最后到“成交”或“撤销”。

我习惯用三段式状态机。为什么?因为代码清晰,综合工具优化得好,而且时序容易收敛。

三段式包括:

  1. 状态转移:时序逻辑,更新当前状态。
  2. 次态逻辑:组合逻辑,根据当前状态和输入决定下一状态。
  3. 输出逻辑:组合逻辑或时序逻辑,根据当前状态产生输出。

看一个简单的例子:一个交易订单状态机。

// 状态定义
localparam IDLE      = 2'b00;
localparam SEND_ORD  = 2'b01;
localparam WAIT_ACK  = 2'b10;
localparam DONE      = 2'b11;

reg [1:0] state, next_state;

// 第一段:状态转移
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        state <= IDLE;
    else
        state <= next_state;
end

// 第二段:次态逻辑(组合逻辑)
always @(*) begin
    case (state)
        IDLE: begin
            if (start_trade)
                next_state = SEND_ORD;
            else
                next_state = IDLE;
        end
        SEND_ORD: begin
            next_state = WAIT_ACK;
        end
        WAIT_ACK: begin
            if (ack_received)
                next_state = DONE;
            else if (timeout)
                next_state = IDLE;  // 超时重试
            else
                next_state = WAIT_ACK;
        end
        DONE: begin
            next_state = IDLE;
        end
        default: next_state = IDLE;
    endcase
end

// 第三段:输出逻辑(组合逻辑)
reg send_enable;
reg clear_timeout;

always @(*) begin
    // 默认值
    send_enable  = 1'b0;
    clear_timeout = 1'b0;
    case (state)
        SEND_ORD: send_enable = 1'b1;
        WAIT_ACK: clear_timeout = 1'b1;
        // 其他状态保持默认
    endcase
end

你看,三段式把“状态跳转”和“输出”分开了。这样调试的时候,你一眼就能看出状态机在哪个状态卡住了。我在做低延迟交易系统时,经常用逻辑分析仪抓状态机的状态信号,配合三段式代码,定位问题非常快。

核心要点: 状态机的输出逻辑,我建议用组合逻辑实现。这样输出没有额外的一拍延迟。但如果你需要输出无毛刺,可以用寄存器打一拍——代价是多一个时钟周期的延迟。在交易系统里,这一拍可能就是几纳秒,你自己权衡。

4.4 知识体系总览

为了让你对本章内容有个整体印象,我画了一张图。它把 Verilog/VHDL 的核心语法、组合逻辑、时序逻辑和状态机设计串在了一起。

FPGA 硬件描述语言知识体系 核心语法 wire / reg / signal assign / always / process 模块化设计 组合逻辑 无时钟、无状态 门延迟决定速度 避免锁存器 时序逻辑 时钟边沿触发 寄存器存储状态 流水线设计 状态机设计 (FSM) 三段式:状态转移 + 次态逻辑 + 输出逻辑 应用:订单管理、协议解析、控制逻辑 关键:避免冗余状态、确保完备性 三者关系:核心语法是基础,组合逻辑和时序逻辑是两大支柱,状态机是高级应用 在低延迟交易系统中,三者缺一不可

这张图把本章的核心脉络理清了。你从左上角的核心语法出发,掌握 wire/reg 和 assign/always。然后分两条路:组合逻辑负责计算,时序逻辑负责存储。最后,状态机把两者结合起来,实现复杂的控制逻辑。在交易系统里,这三者就像齿轮一样咬合在一起。

我的建议: 刚开始学的时候,别急着写复杂的状态机。先拿简单的计数器、移位寄存器练手。等你对组合逻辑和时序逻辑的“并行感”有了肌肉记忆,再上手状态机。我当年就是先写了100个流水灯,才敢碰交易系统的状态机。

公众号:蓝海资料掘金营,微信deep3321