Search code examples
system-verilogvivado

Why does my FSM not result in combinational logic?


I'm trying to make a fsm and decoder file. The decoder section gives me no issues, all of my errors point to the fsm part of my code. The main issue are the errors about latches and non combinational logic in my always_comb blocks for the fsm.

I already know that I need to include defaults to my case statements to prevent latches, but my code still gives me issues.

Here is what I have: `

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
    );
    
    //creating 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
    
    assign CU_INT_TAKEN_FSM = CU_INT_TAKEN_DCDR;
    
    always_comb
    begin
        case(PS)
            ST_INIT: //Start of program
            begin
                CU_reset = 1;
                CU_PCWrite = 0;
                NS = ST_FETCH;
            end
            ST_FETCH:   //Grabs instruction
            begin
                CU_reset = 0;
                CU_memRDEN1 = 1;
                CU_PCWrite = 0;
                CU_regWrite = 0;
                NS = ST_EXEC;
            end
            ST_EXEC:    //Executes instruction based on its type
            begin
                NS = ST_FETCH;
                case(CU_OP_TYPE)
                    7'b0110011 | 7'b0010011 | 7'b1100111 | 7'b1101111 | 7'b0110111 | 7'b0010111: 
                    //R-TYPEs and I-TYPEs that act like R-TYPEs, U-TYPES, and J-TYPES
                    begin
                        CU_PCWrite = 1;
                        CU_regWrite = 1;
                        CU_memWE2 = 0;
                        CU_memRDEN1 = 0;
                        CU_memRDEN2 = 0;
                        CU_reset = 0;
                        //CSR stuff (dw bout it)
                        CU_csr_WE = 0;
                        CU_INT_TAKEN_FSM = 0;
                        CU_mret_exec = 0;
                    end
                    7'b0000011: // all load instructions
                    begin
                        CU_PCWrite = 0;
                        CU_regWrite = 0;
                        CU_memWE2 = 0;
                        CU_memRDEN1 = 0;
                        CU_memRDEN2 = 1;
                        CU_reset = 0;
                        //CSR stuff (dw bout it)
                        CU_csr_WE = 0;
                        CU_INT_TAKEN_FSM = 0;
                        CU_mret_exec = 0;
                        NS = ST_WB;
                    end
                    7'b0100011: // S-TYPES
                    begin
                        CU_PCWrite = 1;
                        CU_regWrite = 0;
                        CU_memWE2 = 1;
                        CU_memRDEN1 = 0;
                        CU_memRDEN2 = 0;
                        CU_reset = 0;
                        //CSR stuff (dw bout it)
                        CU_csr_WE = 0;
                        CU_INT_TAKEN_FSM = 0;
                        CU_mret_exec = 0;
                    end
                    7'b1100011: // B-TYPES
                    begin
                        CU_PCWrite = 1;
                        CU_regWrite = 0;
                        CU_memWE2 = 0;
                        CU_memRDEN1 = 0;
                        CU_memRDEN2 = 0;
                        CU_reset = 0;
                        //CSR stuff (dw bout it)
                        CU_csr_WE = 0;
                        CU_INT_TAKEN_FSM = 0;
                        CU_mret_exec = 0;
                    end
                    default: begin
                    CU_PCWrite = 1;
                        CU_regWrite = 0;
                        CU_memWE2 = 0;
                        CU_memRDEN1 = 0;
                        CU_memRDEN2 = 0;
                        CU_reset = 0;
                        //CSR stuff (dw bout it)
                        CU_csr_WE = 0;
                        CU_INT_TAKEN_FSM = 0;
                        CU_mret_exec = 0;; //resets program if wrong
                    end
                endcase
            end
            ST_WB:  //writes value from load instruction back to register file
            begin
                CU_PCWrite = 1;
                CU_regWrite = 1;
                CU_memWE2 = 0;
                CU_memRDEN1 = 0;
                CU_memRDEN2 = 0;
                CU_reset = 0;
                //CSR stuff (dw bout it)
                CU_csr_WE = 0;
                CU_INT_TAKEN_FSM = 0;
                CU_mret_exec = 0;
                NS = ST_FETCH;
            end
            default: 
            begin
            CU_PCWrite = 1;
                CU_regWrite = 1;
                CU_memWE2 = 0;
                CU_memRDEN1 = 0;
                CU_memRDEN2 = 0;
                CU_reset = 0;
                //CSR stuff (dw bout it)
                CU_csr_WE = 0;
                CU_INT_TAKEN_FSM = 0;
                CU_mret_exec = 0;
                NS = ST_FETCH;
            end
        endcase
    end
    
    //creating Decoder
    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-TYPES
            begin
                //All R-types behave the same besides what ALU does to values
                CU_alu_srcA = 2'b00;
                CU_alu_srcB = 3'b000;
                CU_pcSource = 3'b000;
                CU_rf_wr_sel = 2'b11;
                case(CU_FUNCT3) //specify what to do to values at ALU
                    3'b010: CU_alu_fun = 4'b0010; // slt
                    3'b100: CU_alu_fun = 4'b000; // xor
                    default: CU_alu_fun = 4'b0000;  //add
                endcase
            end
            7'b0010011: //I_TYPES like R_TYPES
            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_TYPES
            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

I appreciate any advice.


Solution

  • Some variables are not assigned in all cases. For example, CU_regWrite in ST_INIT case. If you feel hard to manage the assignment in case blocks, you may put the default assignment to all variables at the beginning, then overwrite some of the variables in the cases. For example:

    always @*
    begin
      state_next = state;  // Default value
      reg_wr = 0;  // Default value
      reg_rd = 0;  // Default value
      case ( state )
        0:
          if ( cmd_wr )
            state_next = 1;
          else if ( cmd_rd )
            state_next = 2;
        1:
        begin
          reg_wr = 1;
          state_next = 3;  
        end
        2:
        begin
          reg_rd = 1;
          state_next = 3;  
        end
        default: state_next = 0;
      endcase
    end