hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv Cov: 100%

   1: // Copyright lowRISC contributors.
   2: // Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
   3: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   4: // SPDX-License-Identifier: Apache-2.0
   5: 
   6: /**
   7:  * Compressed instruction decoder
   8:  *
   9:  * Decodes RISC-V compressed instructions into their RV32 equivalent.
  10:  * This module is fully combinatorial, clock and reset are used for
  11:  * assertions only.
  12:  */
  13: module ibex_compressed_decoder (
  14:     input  logic        clk_i,
  15:     input  logic        rst_ni,
  16:     input  logic        valid_i,
  17:     input  logic [31:0] instr_i,
  18:     output logic [31:0] instr_o,
  19:     output logic        is_compressed_o,
  20:     output logic        illegal_instr_o
  21: );
  22:   import ibex_pkg::*;
  23: 
  24:   // valid_i indicates if instr_i is valid and is used for assertions only.
  25:   // The following signal is used to avoid possible lint errors.
  26:   logic unused_valid;
  27:   assign unused_valid = valid_i;
  28: 
  29:   ////////////////////////
  30:   // Compressed decoder //
  31:   ////////////////////////
  32: 
  33:   always_comb begin
  34:     // By default, forward incoming instruction, mark it as legal.
  35:     instr_o         = instr_i;
  36:     illegal_instr_o = 1'b0;
  37: 
  38:     // Check if incoming instruction is compressed.
  39:     unique case (instr_i[1:0])
  40:       // C0
  41:       2'b00: begin
  42:         unique case (instr_i[15:13])
  43:           3'b000: begin
  44:             // c.addi4spn -> addi rd', x2, imm
  45:             instr_o = {2'b0, instr_i[10:7], instr_i[12:11], instr_i[5],
  46:                        instr_i[6], 2'b00, 5'h02, 3'b000, 2'b01, instr_i[4:2], {OPCODE_OP_IMM}};
  47:             if (instr_i[12:5] == 8'b0)  illegal_instr_o = 1'b1;
  48:           end
  49: 
  50:           3'b010: begin
  51:             // c.lw -> lw rd', imm(rs1')
  52:             instr_o = {5'b0, instr_i[5], instr_i[12:10], instr_i[6],
  53:                        2'b00, 2'b01, instr_i[9:7], 3'b010, 2'b01, instr_i[4:2], {OPCODE_LOAD}};
  54:           end
  55: 
  56:           3'b110: begin
  57:             // c.sw -> sw rs2', imm(rs1')
  58:             instr_o = {5'b0, instr_i[5], instr_i[12], 2'b01, instr_i[4:2],
  59:                        2'b01, instr_i[9:7], 3'b010, instr_i[11:10], instr_i[6],
  60:                        2'b00, {OPCODE_STORE}};
  61:           end
  62: 
  63:           3'b001,
  64:           3'b011,
  65:           3'b100,
  66:           3'b101,
  67:           3'b111: begin
  68:             illegal_instr_o = 1'b1;
  69:           end
  70: 
  71:           default: begin
  72:             illegal_instr_o = 1'b1;
  73:           end
  74:         endcase
  75:       end
  76: 
  77:       // C1
  78:       //
  79:       // Register address checks for RV32E are performed in the regular instruction decoder.
  80:       // If this check fails, an illegal instruction exception is triggered and the controller
  81:       // writes the actual faulting instruction to mtval.
  82:       2'b01: begin
  83:         unique case (instr_i[15:13])
  84:           3'b000: begin
  85:             // c.addi -> addi rd, rd, nzimm
  86:             // c.nop
  87:             instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2],
  88:                        instr_i[11:7], 3'b0, instr_i[11:7], {OPCODE_OP_IMM}};
  89:           end
  90: 
  91:           3'b001, 3'b101: begin
  92:             // 001: c.jal -> jal x1, imm
  93:             // 101: c.j   -> jal x0, imm
  94:             instr_o = {instr_i[12], instr_i[8], instr_i[10:9], instr_i[6],
  95:                        instr_i[7], instr_i[2], instr_i[11], instr_i[5:3],
  96:                        {9 {instr_i[12]}}, 4'b0, ~instr_i[15], {OPCODE_JAL}};
  97:           end
  98: 
  99:           3'b010: begin
 100:             // c.li -> addi rd, x0, nzimm
 101:             // (c.li hints are translated into an addi hint)
 102:             instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], 5'b0,
 103:                        3'b0, instr_i[11:7], {OPCODE_OP_IMM}};
 104:           end
 105: 
 106:           3'b011: begin
 107:             // c.lui -> lui rd, imm
 108:             // (c.lui hints are translated into a lui hint)
 109:             instr_o = {{15 {instr_i[12]}}, instr_i[6:2], instr_i[11:7], {OPCODE_LUI}};
 110: 
 111:             if (instr_i[11:7] == 5'h02) begin
 112:               // c.addi16sp -> addi x2, x2, nzimm
 113:               instr_o = {{3 {instr_i[12]}}, instr_i[4:3], instr_i[5], instr_i[2],
 114:                          instr_i[6], 4'b0, 5'h02, 3'b000, 5'h02, {OPCODE_OP_IMM}};
 115:             end
 116: 
 117:             if ({instr_i[12], instr_i[6:2]} == 6'b0) illegal_instr_o = 1'b1;
 118:           end
 119: 
 120:           3'b100: begin
 121:             unique case (instr_i[11:10])
 122:               2'b00,
 123:               2'b01: begin
 124:                 // 00: c.srli -> srli rd, rd, shamt
 125:                 // 01: c.srai -> srai rd, rd, shamt
 126:                 // (c.srli/c.srai hints are translated into a srli/srai hint)
 127:                 instr_o = {1'b0, instr_i[10], 5'b0, instr_i[6:2], 2'b01, instr_i[9:7],
 128:                            3'b101, 2'b01, instr_i[9:7], {OPCODE_OP_IMM}};
 129:                 if (instr_i[12] == 1'b1)  illegal_instr_o = 1'b1;
 130:               end
 131: 
 132:               2'b10: begin
 133:                 // c.andi -> andi rd, rd, imm
 134:                 instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], 2'b01, instr_i[9:7],
 135:                            3'b111, 2'b01, instr_i[9:7], {OPCODE_OP_IMM}};
 136:               end
 137: 
 138:               2'b11: begin
 139:                 unique case ({instr_i[12], instr_i[6:5]})
 140:                   3'b000: begin
 141:                     // c.sub -> sub rd', rd', rs2'
 142:                     instr_o = {2'b01, 5'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7],
 143:                                3'b000, 2'b01, instr_i[9:7], {OPCODE_OP}};
 144:                   end
 145: 
 146:                   3'b001: begin
 147:                     // c.xor -> xor rd', rd', rs2'
 148:                     instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b100,
 149:                                2'b01, instr_i[9:7], {OPCODE_OP}};
 150:                   end
 151: 
 152:                   3'b010: begin
 153:                     // c.or  -> or  rd', rd', rs2'
 154:                     instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b110,
 155:                                2'b01, instr_i[9:7], {OPCODE_OP}};
 156:                   end
 157: 
 158:                   3'b011: begin
 159:                     // c.and -> and rd', rd', rs2'
 160:                     instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b111,
 161:                                2'b01, instr_i[9:7], {OPCODE_OP}};
 162:                   end
 163: 
 164:                   3'b100,
 165:                   3'b101,
 166:                   3'b110,
 167:                   3'b111: begin
 168:                     // 100: c.subw
 169:                     // 101: c.addw
 170:                     illegal_instr_o = 1'b1;
 171:                   end
 172: 
 173:                   default: begin
 174:                     illegal_instr_o = 1'b1;
 175:                   end
 176:                 endcase
 177:               end
 178: 
 179:               default: begin
 180:                 illegal_instr_o = 1'b1;
 181:               end
 182:             endcase
 183:           end
 184: 
 185:           3'b110, 3'b111: begin
 186:             // 0: c.beqz -> beq rs1', x0, imm
 187:             // 1: c.bnez -> bne rs1', x0, imm
 188:             instr_o = {{4 {instr_i[12]}}, instr_i[6:5], instr_i[2], 5'b0, 2'b01,
 189:                        instr_i[9:7], 2'b00, instr_i[13], instr_i[11:10], instr_i[4:3],
 190:                        instr_i[12], {OPCODE_BRANCH}};
 191:           end
 192: 
 193:           default: begin
 194:             illegal_instr_o = 1'b1;
 195:           end
 196:         endcase
 197:       end
 198: 
 199:       // C2
 200:       //
 201:       // Register address checks for RV32E are performed in the regular instruction decoder.
 202:       // If this check fails, an illegal instruction exception is triggered and the controller
 203:       // writes the actual faulting instruction to mtval.
 204:       2'b10: begin
 205:         unique case (instr_i[15:13])
 206:           3'b000: begin
 207:             // c.slli -> slli rd, rd, shamt
 208:             // (c.ssli hints are translated into a slli hint)
 209:             instr_o = {7'b0, instr_i[6:2], instr_i[11:7], 3'b001, instr_i[11:7], {OPCODE_OP_IMM}};
 210:             if (instr_i[12] == 1'b1)  illegal_instr_o = 1'b1; // reserved for custom extensions
 211:           end
 212: 
 213:           3'b010: begin
 214:             // c.lwsp -> lw rd, imm(x2)
 215:             instr_o = {4'b0, instr_i[3:2], instr_i[12], instr_i[6:4], 2'b00, 5'h02,
 216:                        3'b010, instr_i[11:7], OPCODE_LOAD};
 217:             if (instr_i[11:7] == 5'b0)  illegal_instr_o = 1'b1;
 218:           end
 219: 
 220:           3'b100: begin
 221:             if (instr_i[12] == 1'b0) begin
 222:               if (instr_i[6:2] != 5'b0) begin
 223:                 // c.mv -> add rd/rs1, x0, rs2
 224:                 // (c.mv hints are translated into an add hint)
 225:                 instr_o = {7'b0, instr_i[6:2], 5'b0, 3'b0, instr_i[11:7], {OPCODE_OP}};
 226:               end else begin
 227:                 // c.jr -> jalr x0, rd/rs1, 0
 228:                 instr_o = {12'b0, instr_i[11:7], 3'b0, 5'b0, {OPCODE_JALR}};
 229:                 if (instr_i[11:7] == 5'b0)  illegal_instr_o = 1'b1;
 230:               end
 231:             end else begin
 232:               if (instr_i[6:2] != 5'b0) begin
 233:                 // c.add -> add rd, rd, rs2
 234:                 // (c.add hints are translated into an add hint)
 235:                 instr_o = {7'b0, instr_i[6:2], instr_i[11:7], 3'b0, instr_i[11:7], {OPCODE_OP}};
 236:               end else begin
 237:                 if (instr_i[11:7] == 5'b0) begin
 238:                   // c.ebreak -> ebreak
 239:                   instr_o = {32'h00_10_00_73};
 240:                 end else begin
 241:                   // c.jalr -> jalr x1, rs1, 0
 242:                   instr_o = {12'b0, instr_i[11:7], 3'b000, 5'b00001, {OPCODE_JALR}};
 243:                 end
 244:               end
 245:             end
 246:           end
 247: 
 248:           3'b110: begin
 249:             // c.swsp -> sw rs2, imm(x2)
 250:             instr_o = {4'b0, instr_i[8:7], instr_i[12], instr_i[6:2], 5'h02, 3'b010,
 251:                        instr_i[11:9], 2'b00, {OPCODE_STORE}};
 252:           end
 253: 
 254:           3'b001,
 255:           3'b011,
 256:           3'b101,
 257:           3'b111: begin
 258:             illegal_instr_o = 1'b1;
 259:           end
 260: 
 261:           default: begin
 262:             illegal_instr_o = 1'b1;
 263:           end
 264:         endcase
 265:       end
 266: 
 267:       // Incoming instruction is not compressed.
 268:       2'b11:;
 269: 
 270:       default: begin
 271:         illegal_instr_o = 1'b1;
 272:       end
 273:     endcase
 274:   end
 275: 
 276:   assign is_compressed_o = (instr_i[1:0] != 2'b11);
 277: 
 278:   ////////////////
 279:   // Assertions //
 280:   ////////////////
 281: 
 282:   // Selectors must be known/valid.
 283:   `ASSERT(IbexInstrLSBsKnown, valid_i |->
 284:       !$isunknown(instr_i[1:0]), clk_i, !rst_ni)
 285:   `ASSERT(IbexC0Known1, (valid_i && (instr_i[1:0] == 2'b00)) |->
 286:       !$isunknown(instr_i[15:13]), clk_i, !rst_ni)
 287:   `ASSERT(IbexC1Known1, (valid_i && (instr_i[1:0] == 2'b01)) |->
 288:       !$isunknown(instr_i[15:13]), clk_i, !rst_ni)
 289:   `ASSERT(IbexC1Known2, (valid_i && (instr_i[1:0] == 2'b01) && (instr_i[15:13] == 3'b100)) |->
 290:       !$isunknown(instr_i[11:10]), clk_i, !rst_ni)
 291:   `ASSERT(IbexC1Known3, (valid_i &&
 292:       (instr_i[1:0] == 2'b01) && (instr_i[15:13] == 3'b100) && (instr_i[11:10] == 2'b11)) |->
 293:       !$isunknown({instr_i[12], instr_i[6:5]}), clk_i, !rst_ni)
 294:   `ASSERT(IbexC2Known1, (valid_i && (instr_i[1:0] == 2'b10)) |->
 295:       !$isunknown(instr_i[15:13]), clk_i, !rst_ni)
 296: 
 297: endmodule
 298: