You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Verilog状态机同一状态多时钟周期停留的always块触发问题问询

解决同步状态机中停留多周期的问题

看起来你在同步状态机的实现上踩了个典型的坑——你的组合逻辑状态转移块只对pstate敏感,导致当你想在状态1停留时,这个块根本不会重复执行,自然没法完成多周期的数据采集。让我一步步帮你理清问题并给出修复方案。

原代码的核心问题

  1. 敏感列表太窄:always@(pstate)只有当pstate变化时才会触发。当你在状态1时把nstate设为1,pstate不会改变,这个组合逻辑块就不会再次运行,count根本没法累加,永远满足不了count>2的跳转条件。
  2. 时序变量错误地放在组合逻辑里更新:count是时序寄存器,你却在组合逻辑里用阻塞赋值修改它,这会带来竞争冒险,而且不符合同步设计的规范。
  3. 笔误:ref [2:0] count = 0;里的ref应该是reg。

正确的实现思路

同步状态机的关键是所有时序操作(状态更新、计数)都要在时钟沿触发,这样每个时钟周期都会执行一次逻辑,不管状态是否变化。我们可以用两种常见的写法来实现:

方案1:一段式同步状态机(更简洁)

把状态转移、计数更新都放在同一个时钟沿触发的always块里,这样每个时钟周期都会执行,完美解决多周期停留的问题:

module TestModule( input clk, rst, data_int);
reg [2:0] pstate = 0;
reg [1:0] count = 0; // 只需要2位就够,因为最多计数到2

always@(posedge clk, posedge rst) begin
    if(rst) begin
        pstate <= 0;
        count <= 0;
    end else begin
        case(pstate)
            0: begin
                // 从状态0跳转到状态1,同时重置计数
                pstate <= 1;
                count <= 0;
            end
            1: begin
                // 每个时钟周期都执行这里,采集data_int(可添加采样逻辑,比如data_reg <= data_int)
                count <= count + 1;
                // 当计数到1时,说明已经在状态1停留了2个时钟周期(从0开始计数)
                if(count >= 1) begin
                    pstate <= 2;
                end
                // 否则保持在状态1
            end
            2: begin
                // 状态2的逻辑,示例:保持在状态2,可根据需求修改
                pstate <= 2;
            end
            default: pstate <= 0;
        endcase
    end
end
endmodule

方案2:两段式同步状态机(更清晰,适合复杂状态机)

把状态转移的组合逻辑和状态更新的时序逻辑分开,组合逻辑用@(*)自动包含所有敏感信号(避免漏写),时序逻辑负责更新状态和计数:

module TestModule( input clk, rst, data_int);
reg [2:0] pstate;
reg [2:0] nstate;
reg [1:0] count;

// 时序逻辑:更新状态和计数,每个时钟沿触发
always@(posedge clk, posedge rst) begin
    if(rst) begin
        pstate <= 0;
        count <= 0;
    end else begin
        pstate <= nstate;
        // 只有在状态1时才累加计数,其他状态重置
        if(pstate == 1) begin
            count <= count + 1;
        end else begin
            count <= 0;
        end
    end
end

// 组合逻辑:计算下一个状态,敏感于所有输入(pstate、count)
always@(*) begin
    nstate = pstate; // 默认保持当前状态
    case(pstate)
        0: begin
            nstate = 1;
        end
        1: begin
            // 完成2个周期采集后跳转到状态2
            if(count >= 1) begin
                nstate = 2;
            end
        end
        2: begin
            // 状态2的逻辑,可根据需求修改
        end
        default: nstate = 0;
    endcase
end
endmodule

为什么这样能解决问题?

  • 时序逻辑块always@(posedge clk, posedge rst)每个时钟沿都会触发,不管pstate是否变化,所以count能在每个时钟周期正常累加。
  • 两段式中的组合逻辑用@(*)会自动包含所有影响nstate的信号,当count变化时,组合逻辑会重新计算nstate,确保状态转移的正确性。
  • 所有时序变量(pstate、count)都在时钟沿更新,符合同步设计的最佳实践,避免了竞争冒险和不可预测的行为。

内容的提问来源于stack exchange,提问作者joequest1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 09:52:38