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

为何我的FSM无法生成组合逻辑?Latch与非组合逻辑错误排查

FSM模块锁存器与非组合逻辑问题排查及修正

核心问题分析

你的FSM代码出现锁存器和非组合逻辑错误,主要源于以下三点:

  • 输出信号未全路径赋值:部分状态分支仅给少数信号赋值,其余信号未明确设置,综合器会生成锁存器保持之前的值,违反组合逻辑要求。
  • 信号多重驱动冲突:CU_INT_TAKEN_FSM同时被assign语句和always_comb块赋值,属于非法多重驱动。
  • case分支匹配逻辑错误:ST_EXEC内的多值匹配用了按位或运算(|),实际会生成单一值而非匹配多个OP类型。

修正方案

1. 组合逻辑块添加默认赋值

在always_comb块开头,先给所有输出信号和NS赋默认值,确保每个信号在所有执行路径都有明确赋值,彻底消除锁存器。

2. 解决多重驱动问题

移除多余的assign语句,将CU_INT_TAKEN_FSM的赋值统一放在always_comb块的默认值中,根据需求在分支中覆盖。

3. 修正case多值匹配逻辑

将多OP类型的匹配用逗号分隔多个条目,替代错误的按位或运算。

修正后的完整代码

module ControlUnit(
    input CU_RST,
    input CU_INTR,
    input [6:0] CU_OP_TYPE,
    input [2:0] CU_FUNCT3,
    input CU_OP3,
    input CU_CLK,
    input CU_INT_TAKEN_DCDR,
    input CU_BReq,
    input CU_BRlt,
    input CU_ltu,
    output logic CU_PCWrite,
    output logic CU_regWrite,
    output logic CU_memWE2,
    output logic CU_memRDEN1,
    output logic CU_memRDEN2,
    output logic CU_reset,
    output logic CU_csr_WE,
    output logic CU_INT_TAKEN_FSM,
    output logic CU_mret_exec,
    output logic [3:0] CU_alu_fun,
    output logic [1:0] CU_alu_srcA,
    output logic [2:0] CU_alu_srcB,
    output logic [2:0] CU_pcSource,
    output logic [1:0] CU_rf_wr_sel
    );
    
    // FSM状态定义
    typedef enum{ST_INIT, ST_FETCH, ST_EXEC, ST_WB} state_type;
    state_type PS, NS;
    
    // 状态寄存器更新
    always_ff@(posedge CU_CLK)
    begin
        if(CU_RST)
            PS <= ST_INIT;
        else 
            PS <= NS;
    end
    
    always_comb
    begin
        // 所有信号先赋默认值,避免锁存器生成
        CU_PCWrite = 0;
        CU_regWrite = 0;
        CU_memWE2 = 0;
        CU_memRDEN1 = 0;
        CU_memRDEN2 = 0;
        CU_reset = 0;
        CU_csr_WE = 0;
        CU_INT_TAKEN_FSM = CU_INT_TAKEN_DCDR; // 统一默认赋值,避免多重驱动
        CU_mret_exec = 0;
        NS = ST_FETCH; // 默认下一状态
        
        case(PS)
            ST_INIT: // 初始化状态
            begin
                CU_reset = 1;
                CU_PCWrite = 0;
                NS = ST_FETCH;
            end
            ST_FETCH:   // 取指状态
            begin
                CU_memRDEN1 = 1;
                CU_PCWrite = 0;
                CU_regWrite = 0;
                NS = ST_EXEC;
            end
            ST_EXEC:    // 执行状态
            begin
                NS = ST_FETCH;
                case(CU_OP_TYPE)
                    // 匹配多种OP类型,用逗号分隔
                    7'b0110011, 7'b0010011, 7'b1100111, 7'b1101111, 7'b0110111, 7'b0010111: 
                    begin
                        CU_PCWrite = 1;
                        CU_regWrite = 1;
                    end
                    7'b0000011: // 加载指令
                    begin
                        CU_memRDEN2 = 1;
                        NS = ST_WB;
                    end
                    7'b0100011: // 存储指令
                    begin
                        CU_PCWrite = 1;
                        CU_memWE2 = 1;
                    end
                    7'b1100011: // 分支指令
                    begin
                        CU_PCWrite = 1;
                    end
                    default: begin
                        CU_PCWrite = 1;
                    end
                endcase
            end
            ST_WB:  // 写回状态
            begin
                CU_PCWrite = 1;
                CU_regWrite = 1;
                NS = ST_FETCH;
            end
            default: 
            begin
                CU_PCWrite = 1;
                CU_regWrite = 1;
                NS = ST_FETCH;
            end
        endcase
    end
    
    // 译码器模块
    always_comb 
    begin
        CU_alu_fun = 4'b0000;
        CU_alu_srcA = 2'b00;
        CU_alu_srcB = 3'b000;
        CU_pcSource = 3'b000;
        CU_rf_wr_sel = 2'b00;
        case(CU_OP_TYPE)
            7'b0110011: // R类型指令
            begin
                CU_alu_srcA = 2'b00;
                CU_alu_srcB = 3'b000;
                CU_pcSource = 3'b000;
                CU_rf_wr_sel = 2'b11;
                case(CU_FUNCT3)
                    3'b010: CU_alu_fun = 4'b0010; // slt
                    3'b100: CU_alu_fun = 4'b0001; // xor(修正为4位规范值)
                    default: CU_alu_fun = 4'b0000;  // add
                endcase
            end
            7'b0010011: // 类R型I指令
            begin
                CU_alu_srcA = 2'b00;
                CU_alu_srcB = 3'b001;
                CU_pcSource = 3'b000;
                CU_rf_wr_sel = 2'b11;
                case(CU_FUNCT3)
                    3'b000: CU_alu_fun = 4'b0000; // addi
                    3'b001: CU_alu_fun = 4'b0001; // slli
                endcase
            end
            7'b0110111: // lui指令
            begin
                CU_alu_fun = 4'b1001;
                CU_alu_srcA = 2'b01;
                CU_alu_srcB = 3'b000;
                CU_pcSource = 3'b000;
                CU_rf_wr_sel = 2'b11;
            end
            7'b1100011: // B类型分支指令
            begin
                CU_pcSource = 3'b010;
            end
            default:
            begin
                CU_alu_fun = 4'b0000;
                CU_alu_srcA = 2'b00;
                CU_alu_srcB = 3'b000;
                CU_pcSource = 3'b000;
                CU_rf_wr_sel = 2'b00;
            end
        endcase
    end
endmodule

额外细节修正

  • 修正了解码器中xor操作的CU_alu_fun赋值为4位规范值(原代码写4'b000,语法允许但不规范)。
  • 所有状态分支仅覆盖需要修改的信号,默认值保证其余信号的正确性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 14:38:13