组合逻辑--时序逻辑--状态机

1. 组合逻辑 (Combinational Logic)

1.1 专业描述

组合逻辑电路是指在任何时刻,其输出值仅取决于该时刻输入值的逻辑电路。它不包含任何记忆元件(如触发器或寄存器),因此电路本身没有“状态”的概念。可以将其视为一个纯粹的、无状态的计算函数,输入一旦确定,输出便唯一确定。

核心特征:

无记忆性: 电路不存储历史信息。

无时钟依赖: 理论上,组合逻辑的运算与时钟信号无关。其输出会随着输入的改变而立即(经过一定的传播延迟后)改变。

传播延迟 (Propagation Delay): 电流通过逻辑门需要时间,从输入变化到输出稳定下来的这段时间称为传播延迟。这是组合逻辑电路中一个非常关键的物理特性。

1.2 设计与实现

组合逻辑是实现数据通路(Datapath)的基础,用于执行各种算术和逻辑运算。

常见电路:

逻辑门 (Logic Gates): AND, OR, NOT, XOR 等是构成所有组合逻辑的基础。

加法器 (Adder): 从半加器、全加器到多位的超前进位加法器。

比较器 (Comparator)**: 比较两个二进制数的大小。

多路选择器 (Multiplexer, MUX): 根据选择信号从多个输入中选择一个输出。

解码器/编码器 (Decoder/Encoder): 将一种编码转换为另一种编码,如将二进制码转换为独热码(One-hot)。

算术逻辑单元 (ALU): 能够执行多种算术和逻辑运算的复杂组合逻辑单元。

HDL 实现 (以 Verilog 为例):  主要使用 `assign` 连续赋值语句和 `always @(*)` 块来实现。

`always @(*)` 是描述组合逻辑的推荐方式,其敏感列表会自动包含所有在块内读取的信号,可以有效避免因敏感列表不完整而意外生成锁存器(Latch)。

示例:一个2选1多路选择器

module Mux2_to_1 (
    input  wire a,      // 输入数据0
    input  wire b,      // 输入数据1
    input  wire sel,    // 选择信号
    output reg  y       // 输出
);

    // 使用 always@(*) 块描述组合逻辑
    always @(*) begin
        if (sel == 1'b0) begin
            y = a;
        else begin
            y = b;
        end
    end

    // 也可以用 assign 语句实现,更为简洁
    // assign y = (sel == 1'b0) ? a : b;

endmodule

设计关键点:

避免生成锁存器 (Latch): 在 `always` 块中,如果 `if` 或 `case` 语句没有覆盖所有可能的情况,并且没有为所有分支下的所有输出信号赋值,综合器会为了“记住”之前的值而生成一个锁存器。锁存器对时序非常敏感,容易导致时序问题,在同步设计中应极力避免。逻辑冒险 (Logic Hazard): 由于信号通过不同路径的延迟不同,输入信号的单个跳变可能导致输出产生短暂的毛刺(Glitch)。这在异步电路中是致命的,但在全同步设计中,只要保证在时钟有效沿到来之前输出已经稳定,毛刺通常不会造成危害。

2. 时序逻辑 (Sequential Logic)

2.1 专业描述

时序逻辑电路的输出不仅取决于当前的输入,还与电路过去的状态(存储在记忆元件中的值)有关。因此,时序逻辑是具有记忆功能的电路。时钟信号(Clock)是时序逻辑的灵魂,它规定了电路状态更新的节奏,确保整个系统能够同步、有序地工作。

核心特征:

记忆性: 电路包含存储元件(通常是D触发器),能够保存状态信息。

时钟驱动: 电路的状态通常只在时钟的特定边沿(上升沿或下降沿)发生变化。

反馈 (Feedback): 时序逻辑通常包含从记忆元件输出到其输入的反馈路径,这是实现状态更新的基础。

2.2 设计与实现

时序逻辑是构建寄存器、计数器、移位寄存器以及状态机等模块的基础。

核心元件: D触发器 (D Flip-Flop, DFF): 是FPGA中最基本的时序逻辑单元。在时钟有效沿,它会将D输入端的值锁存到Q输出端,并保持到下一个有效沿。

HDL 实现 (以 Verilog 为例): 使用 `always @(posedge clk or negedge rst_n)` 这种带有时钟边沿触发的 `always` 块来描述。 使用非阻塞赋值 (`<=`)是时序逻辑设计的金科玉律。它能够正确地模拟出在同一个时钟沿,所有触发器同时采样、然后同时更新的行为。    

示例:一个带异步复位的4位计数器

module Counter_4bit (
    input  wire clk,      // 时钟
    input  wire rst_n,    // 异步复位,低有效
    output reg  [3:0] q   // 计数器输出
);

    // 使用带时钟边沿的 always 块描述时序逻辑
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            // 异步复位逻辑
            q <= 4'b0000;
        else begin
            // 同步逻辑
            q <= q + 1'b1;
        end
    end

endmodule

设计关键点:

同步设计原则:

坚持“所有存储元件都使用同一个(或同源的)时钟”的原则,可以极大简化时序分析。

复位策略:

异步复位: 复位信号不依赖时钟,可以立即生效。优点是复位快,缺点是复位信号的释放(撤销)必须是同步的,否则会引入亚稳态,即所谓的“异步复位,同步释放”。

同步复位: 复位信号只有在时钟有效沿才生效。优点是设计更稳定,时序分析更简单

阻塞赋值 vs. 非阻塞赋值: 在时序逻辑块中,务必使用非阻塞赋值 (`<=`)。如果误用阻塞赋值 (`=`),会改变仿真行为,使其不再能准确模拟硬件的并行更新特性,可能导致仿真结果与实际硬件行为不符

3. 状态机 (Finite State Machine, FSM)

3.1专业描述

状态机是时序逻辑的一种特殊且强大的应用,用于设计控制逻辑(Control Path)。它由一组有限的状态(States)、一个初始状态(Initial State)、一组输入(Inputs)以及在输入作用下决定状态如何转移的转移函数(Transition Function)和决定输出的输出函数(Output Function)构成。 FSM是系统控制逻辑的抽象模型,能够清晰、结构化地描述一个系统如何根据外部输入和内部状态来决策其行为。

两大类型:  

Mealy 型状态机: 输出不仅与当前状态有关,还与当前输入有关。这意味着输入的变化能够立即(经过组合逻辑延迟后)影响输出,而无需等待下一个时钟沿。

Moore 型状态机: 输出只与当前状态有关。这意味着只有在时钟沿到来、状态发生改变后,输出才会更新。

特性Moore 型状态机 Mealy 型状态机
输出仅依赖于当前状态依赖于当前状态和当前输入
响应速度输出对输入的响应会延迟一个时钟周期输出对输入的变化可以立即响应
状态数量通常需要更多的状态来实现相同功能可能用更少的状态
硬件实现输出逻辑更简单,通常直接是状态寄存器的输出或其译码输出逻辑更复杂,是状态和输入的组合逻辑
时序时序性能更好,因为输出是寄存器输出,没有长的组合逻辑路径从输入到输出的组合逻辑路径可能很长,影响最高工作频率

3.2 设计与实现

一个标准的FSM实现包含三个部分:

1. 次态逻辑 (Next State Logic): 这是一个组合逻辑块,根据当前状态和输入,决定下一个状态是什么。

2. 状态寄存器 (State Register): 这是一个时序逻辑块,在时钟有效沿到来时,用次态更新当前状态。

3. 输出逻辑 (Output Logic): 这是一个组合逻辑块,根据当前状态(和输入,如果是Mealy型)产生输出信号

HDL 实现 (三段式描述法): 这是最推荐、最清晰、最不易出错的FSM写法。

示例:一个检测序列“1101”的Mealy型状态机

module SequenceDetector_1101 (
    input  wire clk,
    input  wire rst_n,
    input  wire din,
    output reg  match
);

    // 1. 定义状态 (使用 parameter 定义,增加可读性)
    parameter S_IDLE = 3'b000;
    parameter S_1    = 3'b001;
    parameter S_11   = 3'b010;
    parameter S_110  = 3'b011;

    // 2. 状态寄存器 (时序逻辑)
    reg [2:0] current_state, next_state;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            current_state <= S_IDLE;
        else begin
            current_state <= next_state;
        end
    end

    // 3. 次态逻辑 (组合逻辑)
    always @(*) begin
        // 默认情况下保持当前状态
        next_state = current_state;
        case (current_state)
            S_IDLE: if (din == 1'b1) next_state = S_1;   else next_state = S_IDLE;
            S_1:    if (din == 1'b1) next_state = S_11;  else next_state = S_IDLE;
            S_11:   if (din == 1'b0) next_state = S_110; else next_state = S_11;
            S_110:  if (din == 1'b1) next_state = S_1;   else next_state = S_IDLE;
            default: next_state = S_IDLE;
        endcase
    end

    // 4. 输出逻辑 (组合逻辑, Mealy型)
    always @(*) begin
        // 默认输出为0
        match = 1'b0;
        if (current_state == S_110 && din == 1'b1) begin
            match = 1'b1;
        end
    end

endmodule

示例:一个检测序列“1101”的 Moore 型状态机

module SequenceDetector_1101_Moore (
    input  wire clk,
    input  wire rst_n,
    input  wire din,      // 输入数据
    output reg  match     // 匹配成功信号
);

    // 1. 定义状态 (比Mealy型多一个专门的匹配状态)
    parameter S_IDLE        = 3'b000;
    parameter S_1           = 3'b001;
    parameter S_11          = 3'b010;
    parameter S_110         = 3'b011;
    parameter S_1101_MATCH  = 3'b100; // <--- 专门用于输出 match=1 的状态

    // 2. 状态寄存器 (时序逻辑,与Mealy型完全相同)
    reg [2:0] current_state, next_state;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            current_state <= S_IDLE;
        else begin
            current_state <= next_state;
        end
    end

    // 3. 次态逻辑 (组合逻辑)
    // 根据当前状态和当前输入,决定下一个状态
    always @(*) begin
        // 默认情况下,下一个状态是IDLE,这是一种安全的设计实践
        next_state = S_IDLE;
        case (current_state)
            S_IDLE:
                if (din == 1'b1) next_state = S_1;
                else             next_state = S_IDLE;
            S_1:    
                if (din == 1'b1) next_state = S_11;
                else             next_state = S_IDLE;
            S_11:  
                if (din == 1'b0) next_state = S_110;
                else             next_state = S_11; // 接收到"111",末尾两位仍是"11"
            S_110:  
                if (din == 1'b1) next_state = S_1101_MATCH; // <--- 序列匹配成功,跳转到MATCH状态
                else             next_state = S_IDLE;
            S_1101_MATCH: // 在输出匹配信号之后,判断下一个状态
                if (din == 1'b1) next_state = S_11; // 处理重叠序列,"1101"后面的"1"可以是新序列"11"的开始
                else             next_state = S_IDLE;
            default:
                next_state = S_IDLE;
        endcase
    end

    // 4. 输出逻辑 (组合逻辑, Moore型)
    // 输出只和当前状态有关!
    always @(*) begin
        if (current_state == S_1101_MATCH) begin
            match = 1'b1;
        else begin
            match = 1'b0;
        end
    end
   
    // 上面的 always 块也可以用一条 assign 语句等效实现,更简洁:
    // assign match = (current_state == S_1101_MATCH);

endmodule


原文链接:,转发请注明来源!