Home > Net >  Is there a way to simplify the case logic for an enum in verilog?
Is there a way to simplify the case logic for an enum in verilog?

Time:01-06

I'm looking to simplify an expression for decoding the opcode for a risc v microcontroller:

always @ * begin
    case (opcode)
        LOAD | LOAD_FP | MISC_MEM | OP_IMM  OP_IMM_32 : begin // I_TYPE
            imm[0] <= inst[20];
            imm[4:1] <= inst[24:21];
            imm[10:5] <= inst[30:25];
            imm[31:11] <= inst[31];
        end
        STORE | STORE_FP | AMO : begin // S_TYPE
            imm[0] <= inst[7];
            imm[4:1] <= inst[11:8];
            imm[10:5] <= inst[30:25];
            imm[31:11] <= inst[31];
        end
        BRANCH, JALR : begin // B_TYPE
            imm[0] <= 0;
            imm[4:1] <= inst[11:8];
            imm[10:5] <= inst[30:25];
            imm[11] <= inst[7];
            imm[31:12] <= inst[31];
        end
        AUIPC, LUI, OP_32 : begin // U_TYPE
            imm[11:0] <= 0;
            imm[19:12] <= inst[19:12];
            imm[30:20] <= inst[30:25];
            imm[31] <= inst[31];
        end
        JAL, SYSTEM : begin // J_TYPE
            imm[0] <= 0;
            imm[4:1] <= inst[24:21];
            imm[10:5] <= inst[30:25];
            imm[11] <= inst[20];
            imm[19:12] <= inst[19:12];
            imm[31:20] <= inst[30];
        end
        default :
            imm <= 0;   
    endcase 
end

to somewthing like this:

always @ * begin
    case (opcode)
        I_TYPE : begin
            imm[0] <= inst[20];
            imm[4:1] <= inst[24:21];
            imm[10:5] <= inst[30:25];
            imm[31:11] <= inst[31];
        end
        S_TYPE : begin
            imm[0] <= inst[7];
            imm[4:1] <= inst[11:8];
            imm[10:5] <= inst[30:25];
            imm[31:11] <= inst[31];
       end
       // ...continued
       default :
            imm <= 0;   
    endcase 
end

Is this possible, can I add methods to an enum/class like in c , is this worth doing, if so how? this is my enum:

typedef enum logic [6:2] {
  LOAD   = 5'b00_000,  LOAD_FP  = 5'b00_001,  CUSTOM_0   = 5'b00_010,  MISC_MEM = 5'b00_011,  OP_IMM = 5'b00_100,  AUIPC      = 5'b00_101,  OP_IMM_32 = 5'b00_110,  OP_48_1 = 5'b00_111,
  STORE  = 5'b01_000,  STORE_FP = 5'b01_001,  CUSTOM_1   = 5'b01_010,  AMO      = 5'b01_011,  OP     = 5'b01_100,  LUI        = 5'b01_101,  OP_32     = 5'b01_110,  OP_64   = 5'b01_111,
  MADD   = 5'b10_000,  MSUB     = 5'b10_001,  NMSUB      = 5'b10_010,  NMADD    = 5'b10_011,  OP_FP  = 5'b10_100,  RESERVED_6 = 5'b10_101,  CUSTOM_2  = 5'b10_110,  OP_48_2 = 5'b10_111,
  BRANCH = 5'b11_000,  JALR     = 5'b11_001,  RESERVED_A = 5'b11_010,  JAL      = 5'b11_011,  SYSTEM = 5'b11_100,  RESERVED_D = 5'b11_101,  CUSTOM_3  = 5'b11_110,  OP_80   = 5'b11_111
} base_opcode_map;

If not can somebody tell me the kind of pattern I need to follow?

CodePudding user response:

There are a few things you can do. You can use a let construct

let I_TYPE = opcode inside {LOAD, LOAD_FP, MISC_MEM, OP_IMM, OP_IMM_32};
let S_TYPE = opcode inside {STORE, STORE_FP, AMO};
...

let is a shorthand for defining a simple function

function bit I_TYPE;
  return opcode inside {LOAD, LOAD_FP, MISC_MEM, OP_IMM, OP_IMM_32};
endfunction 
function bit S_TYPE;
  return opcode inside {STORE, STORE_FP, AMO};
endfunction

Then you can write a case statement

always @ * begin
    case (1'b1)
        I_TYPE : begin
            imm[0] <= inst[20];
            imm[4:1] <= inst[24:21];
            imm[10:5] <= inst[30:25];
            imm[31:11] <= inst[31];
        end
        S_TYPE : begin
            imm[0] <= inst[7];
            imm[4:1] <= inst[11:8];
            imm[10:5] <= inst[30:25];
            imm[31:11] <= inst[31];
       end
       // ...continued
       default :
            imm <= 0;   
    endcase 
end
  • Related