VHDL/Verilog 硬件描述语言:组合与时序逻辑设计

FreeGuideOnline 最新 2026-06-15

VHDL/Verilog 硬件描述:组合与时序逻辑设计

硬件描述语言(HDL)是数字电路设计的基础,VHDL 和 Verilog 是两大主导标准。本教程聚焦于如何使用这两种语言实现组合逻辑与时序逻辑,从基本概念到可综合代码范例,帮助初学者快速上手。

1. 硬件描述语言的核心概念

在开始之前,理解 HDL 与软件编程语言的本质区别:

  • 描述硬件而非算法:代码对应逻辑门、触发器等物理结构,执行是并行的。
  • 可综合与不可综合:只有符合特定编码风格的代码才能被 EDA 工具转化为门级网表,本教程仅限可综合设计。
  • 两种主流语言:Verilog 语法类似 C,简洁灵活;VHDL 语法严格,强类型,适合大型项目。二者在组合和时序逻辑设计上遵循相同的硬件思想。

2. 组合逻辑设计

2.1 组合逻辑概念

组合逻辑的输出仅取决于当前输入,无记忆元件。典型电路:译码器、多路选择器、加法器。设计要点:避免生成锁存器,确保所有输入情况都有输出赋值。

2.2 Verilog 中的组合逻辑

Verilog 使用 assign 连续赋值语句或 always @(*) 块描述组合逻辑。

连续赋值(assign)

// 2 输入多路选择器
module mux2_1 (
    input  a, b, sel,
    output y
);
    assign y = sel ? b : a;
endmodule

阻塞赋值(=)的 always 块

// 三态缓冲器
module tri_buf (
    input  en, data_in,
    output reg data_out
);
    always @(*) begin
        if (en)
            data_out = data_in;
        else
            data_out = 1'bz;      // 高阻态
    end
endmodule

关键规则

  • 敏感信号列表用 @(*) 自动包含所有输入,避免遗漏。
  • 使用阻塞赋值 =
  • 不要部分赋值,务必在条件分支结束前为所有输出赋值,否则综合出锁存器。

2.3 VHDL 中的组合逻辑

VHDL 组合逻辑通常用并发的信号赋值或 process 语句实现。

并发信号赋值

-- 4 位加法器
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity adder is
    port (
        a, b : in  std_logic_vector(3 downto 0);
        sum  : out std_logic_vector(4 downto 0)
    );
end adder;

architecture comb of adder is
begin
    sum <= std_logic_vector(unsigned('0' & a) + unsigned('0' & b));
end comb;

含 process 的组合逻辑

-- 优先编码器
process(a) begin
    if    a(3) = '1' then y <= "100";
    elsif a(2) = '1' then y <= "011";
    elsif a(1) = '1' then y <= "010";
    elsif a(0) = '1' then y <= "001";
    else                 y <= "000";
    end if;
end process;

VHDL 规则

  • 敏感信号列表必须包含所有被读取的信号(或使用 all)。
  • 使用信号赋值 <=,但 process 内部仍然为顺序执行。
  • 同样需避免锁存器:务必在条件分支最后覆盖所有情况。

3. 时序逻辑设计

3.1 时序逻辑概念

时序逻辑的输出不仅取决于当前输入,还取决于先前状态,依赖时钟边沿触发。常见元件:触发器(FF)、寄存器、计数器。设计核心:时钟信号与复位策略

3.2 Verilog 中的时序逻辑

使用 always @(posedge clk) (或 negedge)描述边沿触发行为,并要求使用非阻塞赋值 <=

带异步复位的 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

同步使能的寄存器

module reg_en (
    input  clk, en, d,
    output reg q
);
    always @(posedge clk) begin
        if (en)
            q <= d;
    end
endmodule

规则

  • 时序 always 块必须只有时钟边沿和异步复位/置位出现在敏感列表里,不可混合其他信号。
  • 使用非阻塞赋值 <=,避免竞争冒险。
  • 不要在同一个 always 块中混合组合逻辑。

3.3 VHDL 中的时序逻辑

VHDL 使用 process(clk, async_reset) 来描述触发器。

带异步复位的 D 触发器

process(clk, rst_n) begin
    if rst_n = '0' then
        q <= '0';
    elsif rising_edge(clk) then
        q <= d;
    end if;
end process;

同步复位计数器

process(clk) begin
    if rising_edge(clk) then
        if rst = '1' then
            cnt <= (others => '0');
        else
            cnt <= cnt + 1;
        end if;
    end if;
end process;

VHDL 规则

  • 敏感列表里时钟和异步控制信号必须一起列出。
  • 复位条件判断必须在时钟边沿检测之前(若异步)。
  • 信号赋值仍然使用 <=

4. 混合设计实例:有限状态机(FSM)

FSM 是经典的组合与时序逻辑混合结构。将时序部分(状态寄存器)与组合部分(次态逻辑、输出逻辑)分离。

Verilog:三段式状态机

module fsm (
    input  clk, rst_n, in,
    output reg out
);
    reg [1:0] state, next_state;
    parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10;

    // 时序逻辑:状态更新
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            state <= S0;
        else
            state <= next_state;
    end

    // 组合逻辑:次态计算
    always @(*) begin
        case (state)
            S0: next_state = in ? S1 : S0;
            S1: next_state = in ? S2 : S0;
            S2: next_state = in ? S2 : S0;
            default: next_state = S0;
        endcase
    end

    // 组合逻辑:输出(此处为 Moore 型)
    always @(*) begin
        case (state)
            S0: out = 0;
            S1: out = 0;
            S2: out = 1;
            default: out = 0;
        endcase
    end
endmodule

VHDL:两段式状态机

architecture rtl of fsm is
    type state_type is (S0, S1, S2);
    signal state, next_state : state_type;
begin
    -- 时序部分
    process(clk, rst_n) begin
        if rst_n = '0' then
            state <= S0;
        elsif rising_edge(clk) then
            state <= next_state;
        end if;
    end process;

    -- 组合部分
    process(state, in) begin
        case state is
            when S0 =>
                next_state <= S1 when in = '1' else S0;
                out <= '0';
            when S1 =>
                next_state <= S2 when in = '1' else S0;
                out <= '0';
            when S2 =>
                next_state <= S2 when in = '1' else S0;
                out <= '1';
        end case;
    end process;
end rtl;

5. 设计要点与常见陷阱

  • 避免锁存器:组合逻辑中 if/case 未覆盖所有分支,且输出未赋默认值时,综合工具会推断出锁存器(latch),在同步设计中通常非期望。解决方法:使用 elsedefault 覆盖全部分支。
  • 区分阻塞/非阻塞赋值 (Verilog):组合逻辑用 =,时序逻辑用 <=。混用会导致仿真与综合不一致。
  • 时钟域处理:本教程仅限单时钟域设计,跨时钟域需额外同步电路(双触发器、FIFO等)。
  • 初始化与复位:FPGA 设计中寄存器可依靠初始块或复位。强烈建议采用复位信号,确保上电状态确定。
  • 可综合性检查:不要在可综合代码中使用 initialfork#delay 等仿真语句;VHDL 中避免 wait 等不可综合结构。

6. 总结

  • 组合逻辑:纯函数,输出仅取决于当前输入,Verilog 用 assign / always @(*), VHDL 用并发或含所有输入的 process
  • 时序逻辑:依赖时钟边沿,用 always @(posedge clk) (Verilog) 或 process(clk) (VHDL),必须使用非阻塞赋值(Verilog)。
  • FSM 是组合与时序结合的典型模板,三段式 (Verilog) 或两段式 (VHDL) 编码风格清晰、易维护。
  • 严格遵守各语言的编码规范,可以轻松写出正确、高效、可移植的硬件设计。

通过掌握这些基本构件,你已经能够构建绝大多数数字电路。建议在实际项目的仿真和综合中反复练习,将理论知识内化为工程直觉。