From 2d6c24e87ea4b92e66a3583f31588cd3b5d480c5 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 28 May 2026 01:09:48 -0400 Subject: [PATCH 1/4] Add C extension decoder --- src/ext/c/Compressed_Decode.sv | 111 +++++++++++++++++++++++++++++++++ src/headers/params.svh | 1 + 2 files changed, 112 insertions(+) create mode 100644 src/ext/c/Compressed_Decode.sv diff --git a/src/ext/c/Compressed_Decode.sv b/src/ext/c/Compressed_Decode.sv new file mode 100644 index 0000000..d2326d8 --- /dev/null +++ b/src/ext/c/Compressed_Decode.sv @@ -0,0 +1,111 @@ +`include "src/headers/params.svh" +`include "src/headers/types.svh" +`include "src/timescale.svh" + +module Compressed_Decode + ( input wire [15:0] instr_c // Compressed input instruction + , output reg [31:0] instr_out // Expanded instruction + ); + + wire [1:0] quadrant = instr_c[1:0]; + wire [2:0] funct3 = instr_c[15:13]; + + // Common locations of registers in instruction format + wire [4:0] rd_prime = {2'b01, instr_c[4:2]}; + wire [4:0] rs1_prime = {2'b01, instr_c[9:7]}; + wire [4:0] rs2_prime = {2'b01, instr_c[4:2]}; + wire [4:0] rd_full = instr_c[11:7]; + wire [4:0] rs1_full = instr_c[11:7]; + wire [4:0] rs2_full = instr_c[6:2]; + wire [4:0] shamt = instr_c[6:2]; + + // Pre-compute immediates for each instruction format + wire [11:0] ciw_imm = {2'b00, instr_c[10:7], instr_c[12:11], instr_c[5], instr_c[6], 2'b00}; + wire [11:0] cl_cs_imm = {5'b00000, instr_c[5], instr_c[12:10], instr_c[6], 2'b00}; + wire [11:0] ci_imm = {{6{instr_c[12]}}, instr_c[12], instr_c[6:2]}; + wire [11:0] ci_sp_imm = {{3{instr_c[12]}}, instr_c[4:3], instr_c[5], instr_c[2], instr_c[6], 4'b0000}; + wire [19:0] ci_lui_imm = {{14{instr_c[12]}}, instr_c[12], instr_c[6:2]}; + wire [20:0] cj_imm = {{9{instr_c[12]}}, instr_c[12], instr_c[8], instr_c[10:9], instr_c[6], instr_c[7], instr_c[2], instr_c[11], instr_c[5:3], 1'b0}; + wire [12:0] cb_imm = {{4{instr_c[12]}}, instr_c[12], instr_c[6:5], instr_c[2], instr_c[11:10], instr_c[4:3], 1'b0}; + wire [11:0] ci_lwsp_imm = {4'b0000, instr_c[3:2], instr_c[12], instr_c[6:4], 2'b00}; + wire [11:0] css_imm = {4'b0000, instr_c[8:7], instr_c[12:9], 2'b00}; + + localparam bit [31:0] NOP = 32'h00000013; + + // TODO: add checks for illegal/reserved instructions (currently not handled) + // Note: C.FLW, C.FSW, C.FLD, C.FSD, C.FLWSP, C.FLDSP, C.FSWSP, C.FSDSP should be added alongside future F/D extension support. + always @(*) begin + case (quadrant) // Opcode (see https://docs.riscv.org/reference/isa/unpriv/c-st-ext.html) + 2'b11: instr_out = instr_c; // Not a compressed instruction, just pass through + + 2'b00: begin // Quadrant 0 + case (funct3) + 3'b000: instr_out = {ciw_imm, 5'd2, 3'b000, rd_prime, IType_logic}; // C.ADDI4SPN + 3'b010: instr_out = {cl_cs_imm, rs1_prime, 3'b010, rd_prime, IType_load}; // C.LW + 3'b110: instr_out = {cl_cs_imm[11:5], rs2_prime, rs1_prime, 3'b010, cl_cs_imm[4:0], SType}; // C.SW + default: instr_out = NOP; + endcase + end + + 2'b01: begin // Quadrant 1 + case (funct3) + 3'b000: instr_out = {ci_imm, rd_full, 3'b000, rd_full, IType_logic}; // C.ADDI + // TODO C.JAL does not expand exactly to a base RVI instruction since the link address should be pc+2 instead of pc+4 + // Need to add support for offset of 2 bytes (add an is_compressed output?) + 3'b001: instr_out = {cj_imm[20], cj_imm[10:1], cj_imm[11], cj_imm[19:12], 5'd1, JType}; // C.JAL + 3'b010: instr_out = {ci_imm, 5'd0, 3'b000, rd_full, IType_logic}; // C.LI + 3'b011: begin + case (instr_c[11:7]) + 5'd2: instr_out = {ci_sp_imm, 5'd2, 3'b000, 5'd2, IType_logic}; // C.ADDI16SP + default: instr_out = {ci_lui_imm, rd_full, UType_lui}; // C.LUI + endcase + end + 3'b100: begin + case (instr_c[11:10]) + 2'b00: instr_out = {7'h00, instr_c[6:2], rs1_prime, 3'b101, rs1_prime, IType_logic}; // C.SRLI + 2'b01: instr_out = {7'h20, instr_c[6:2], rs1_prime, 3'b101, rs1_prime, IType_logic}; // C.SRAI + 2'b10: instr_out = {ci_imm, rs1_prime, 3'b111, rs1_prime, IType_logic}; // C.ANDI + 2'b11: begin + case (instr_c[6:5]) + 2'b00: instr_out = {7'h20, rs2_prime, rs1_prime, 3'b000, rs1_prime, RType}; // C.SUB + 2'b01: instr_out = {7'h00, rs2_prime, rs1_prime, 3'b100, rs1_prime, RType}; // C.XOR + 2'b10: instr_out = {7'h00, rs2_prime, rs1_prime, 3'b110, rs1_prime, RType}; // C.OR + 2'b11: instr_out = {7'h00, rs2_prime, rs1_prime, 3'b111, rs1_prime, RType}; // C.AND + default: instr_out = NOP; + endcase + end + default: instr_out = NOP; + endcase + end + 3'b101: instr_out = {cj_imm[20], cj_imm[10:1], cj_imm[11], cj_imm[19:12], 5'd0, JType}; // C.J + 3'b110: instr_out = {cb_imm[12], cb_imm[10:5], 5'd0, rs1_prime, 3'b000, cb_imm[4:1], cb_imm[11], BType}; // C.BEQZ + 3'b111: instr_out = {cb_imm[12], cb_imm[10:5], 5'd0, rs1_prime, 3'b001, cb_imm[4:1], cb_imm[11], BType}; // C.BNEZ + default: instr_out = NOP; + endcase + end + + 2'b10: begin // Quadrant 2 + case (funct3) + 3'b000: instr_out = {7'h00, shamt, rd_full, 3'b001, rd_full, IType_logic}; // C.SLLI + 3'b010: instr_out = {ci_lwsp_imm, 5'd2, 3'b010, rd_full, IType_load}; // C.LWSP + 3'b100: begin + case ({instr_c[12], instr_c[11:7] != 5'd0, instr_c[6:2] != 5'd0}) + 3'b010: instr_out = {12'd0, rs1_full, 3'h0, 5'd0, IType_jalr}; // C.JR + 3'b011: instr_out = {7'h00, rs2_full, 5'd0, 3'h0, rd_full, RType}; // C.MV + 3'b100: instr_out = {12'h001, 5'd0, 3'h0, 5'd0, SYSTEM}; // C.EBREAK + // TODO see note on C.JAL + 3'b110: instr_out = {12'd0, rs1_full, 3'h0, 5'd1, IType_jalr}; // C.JALR + 3'b111: instr_out = {7'h00, rs2_full, rd_full, 3'h0, rd_full, RType}; // C.ADD + default: instr_out = NOP; + endcase + end + 3'b110: instr_out = {css_imm[11:5], rs2_full, 5'd2, 3'b010, css_imm[4:0], SType}; // C.SWSP + default: instr_out = NOP; + endcase + end + + default: instr_out = NOP; + endcase + end + +endmodule diff --git a/src/headers/params.svh b/src/headers/params.svh index b1a4c51..7041a2b 100644 --- a/src/headers/params.svh +++ b/src/headers/params.svh @@ -13,6 +13,7 @@ parameter UType_auipc = 7'b0010111; parameter UType_lui = 7'b0110111; parameter IType_jalr = 7'b1100111; parameter FENCE = 7'b0001111; +parameter SYSTEM = 7'b1110011; /* verilator lint_on UNUSEDPARAM */ //ALU Operation Control Codes: Implemented as ENUM in params.svh From af8d1cc625b7ca76e462c89db928218f4156db08 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 28 May 2026 02:10:12 -0400 Subject: [PATCH 2/4] Handle illegal instructions --- src/ext/c/Compressed_Decode.sv | 68 ++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/src/ext/c/Compressed_Decode.sv b/src/ext/c/Compressed_Decode.sv index d2326d8..659f5b5 100644 --- a/src/ext/c/Compressed_Decode.sv +++ b/src/ext/c/Compressed_Decode.sv @@ -5,6 +5,7 @@ module Compressed_Decode ( input wire [15:0] instr_c // Compressed input instruction , output reg [31:0] instr_out // Expanded instruction + , output reg is_illegal // Illegal or not implemented ); wire [1:0] quadrant = instr_c[1:0]; @@ -32,18 +33,23 @@ module Compressed_Decode localparam bit [31:0] NOP = 32'h00000013; - // TODO: add checks for illegal/reserved instructions (currently not handled) // Note: C.FLW, C.FSW, C.FLD, C.FSD, C.FLWSP, C.FLDSP, C.FSWSP, C.FSDSP should be added alongside future F/D extension support. always @(*) begin - case (quadrant) // Opcode (see https://docs.riscv.org/reference/isa/unpriv/c-st-ext.html) - 2'b11: instr_out = instr_c; // Not a compressed instruction, just pass through + instr_out = NOP; + is_illegal = 1'b0; + + case (quadrant) // Opcode + 2'b11: instr_out = {16'b0, instr_c}; // Not a compressed instruction, just pass through (should not actually happen i think?) 2'b00: begin // Quadrant 0 case (funct3) - 3'b000: instr_out = {ciw_imm, 5'd2, 3'b000, rd_prime, IType_logic}; // C.ADDI4SPN + 3'b000: begin + instr_out = {ciw_imm, 5'd2, 3'b000, rd_prime, IType_logic}; // C.ADDI4SPN + if (ciw_imm == 12'b0) is_illegal = 1'b1; + end 3'b010: instr_out = {cl_cs_imm, rs1_prime, 3'b010, rd_prime, IType_load}; // C.LW 3'b110: instr_out = {cl_cs_imm[11:5], rs2_prime, rs1_prime, 3'b010, cl_cs_imm[4:0], SType}; // C.SW - default: instr_out = NOP; + default: is_illegal = 1'b1; endcase end @@ -51,27 +57,39 @@ module Compressed_Decode case (funct3) 3'b000: instr_out = {ci_imm, rd_full, 3'b000, rd_full, IType_logic}; // C.ADDI // TODO C.JAL does not expand exactly to a base RVI instruction since the link address should be pc+2 instead of pc+4 - // Need to add support for offset of 2 bytes (add an is_compressed output?) + // Need to add support for offset of 2 bytes and e.g. preserve an is_compressed wire 3'b001: instr_out = {cj_imm[20], cj_imm[10:1], cj_imm[11], cj_imm[19:12], 5'd1, JType}; // C.JAL 3'b010: instr_out = {ci_imm, 5'd0, 3'b000, rd_full, IType_logic}; // C.LI 3'b011: begin case (instr_c[11:7]) - 5'd2: instr_out = {ci_sp_imm, 5'd2, 3'b000, 5'd2, IType_logic}; // C.ADDI16SP - default: instr_out = {ci_lui_imm, rd_full, UType_lui}; // C.LUI + 5'd2: begin + instr_out = {ci_sp_imm, 5'd2, 3'b000, 5'd2, IType_logic}; // C.ADDI16SP + if (ci_sp_imm == 12'b0) is_illegal = 1'b1; + end + default: begin + instr_out = {ci_lui_imm, rd_full, UType_lui}; // C.LUI + if (ci_lui_imm == 20'b0 ) is_illegal = 1'b1; + end endcase end 3'b100: begin case (instr_c[11:10]) - 2'b00: instr_out = {7'h00, instr_c[6:2], rs1_prime, 3'b101, rs1_prime, IType_logic}; // C.SRLI - 2'b01: instr_out = {7'h20, instr_c[6:2], rs1_prime, 3'b101, rs1_prime, IType_logic}; // C.SRAI + 2'b00: begin + instr_out = {7'h00, instr_c[6:2], rs1_prime, 3'b101, rs1_prime, IType_logic}; // C.SRLI + if (instr_c[12]) is_illegal = 1'b1; + end + 2'b01: begin + instr_out = {7'h20, instr_c[6:2], rs1_prime, 3'b101, rs1_prime, IType_logic}; // C.SRAI + if (instr_c[12]) is_illegal = 1'b1; + end 2'b10: instr_out = {ci_imm, rs1_prime, 3'b111, rs1_prime, IType_logic}; // C.ANDI 2'b11: begin + if (instr_c[12]) is_illegal = 1'b1; case (instr_c[6:5]) 2'b00: instr_out = {7'h20, rs2_prime, rs1_prime, 3'b000, rs1_prime, RType}; // C.SUB 2'b01: instr_out = {7'h00, rs2_prime, rs1_prime, 3'b100, rs1_prime, RType}; // C.XOR 2'b10: instr_out = {7'h00, rs2_prime, rs1_prime, 3'b110, rs1_prime, RType}; // C.OR 2'b11: instr_out = {7'h00, rs2_prime, rs1_prime, 3'b111, rs1_prime, RType}; // C.AND - default: instr_out = NOP; endcase end default: instr_out = NOP; @@ -80,31 +98,33 @@ module Compressed_Decode 3'b101: instr_out = {cj_imm[20], cj_imm[10:1], cj_imm[11], cj_imm[19:12], 5'd0, JType}; // C.J 3'b110: instr_out = {cb_imm[12], cb_imm[10:5], 5'd0, rs1_prime, 3'b000, cb_imm[4:1], cb_imm[11], BType}; // C.BEQZ 3'b111: instr_out = {cb_imm[12], cb_imm[10:5], 5'd0, rs1_prime, 3'b001, cb_imm[4:1], cb_imm[11], BType}; // C.BNEZ - default: instr_out = NOP; endcase end 2'b10: begin // Quadrant 2 case (funct3) - 3'b000: instr_out = {7'h00, shamt, rd_full, 3'b001, rd_full, IType_logic}; // C.SLLI - 3'b010: instr_out = {ci_lwsp_imm, 5'd2, 3'b010, rd_full, IType_load}; // C.LWSP + 3'b000: begin + instr_out = {7'h00, shamt, rd_full, 3'b001, rd_full, IType_logic}; // C.SLLI + if (instr_c[12]) is_illegal = 1'b1; + end + 3'b010: begin + instr_out = {ci_lwsp_imm, 5'd2, 3'b010, rd_full, IType_load}; // C.LWSP + if (rd_full == 5'd0) is_illegal = 1'b1; + end 3'b100: begin case ({instr_c[12], instr_c[11:7] != 5'd0, instr_c[6:2] != 5'd0}) - 3'b010: instr_out = {12'd0, rs1_full, 3'h0, 5'd0, IType_jalr}; // C.JR - 3'b011: instr_out = {7'h00, rs2_full, 5'd0, 3'h0, rd_full, RType}; // C.MV - 3'b100: instr_out = {12'h001, 5'd0, 3'h0, 5'd0, SYSTEM}; // C.EBREAK - // TODO see note on C.JAL - 3'b110: instr_out = {12'd0, rs1_full, 3'h0, 5'd1, IType_jalr}; // C.JALR - 3'b111: instr_out = {7'h00, rs2_full, rd_full, 3'h0, rd_full, RType}; // C.ADD - default: instr_out = NOP; + 3'b010: instr_out = {12'd0, rs1_full, 3'h0, 5'd0, IType_jalr}; // C.JR + 3'b011, 3'b001: instr_out = {7'h00, rs2_full, 5'd0, 3'h0, rd_full, RType}; // C.MV + 3'b100: instr_out = {12'h001, 5'd0, 3'h0, 5'd0, SYSTEM}; // C.EBREAK + 3'b110: instr_out = {12'd0, rs1_full, 3'h0, 5'd1, IType_jalr}; // C.JALR (TODO see note on C.JAL) + 3'b111, 3'b101: instr_out = {7'h00, rs2_full, rd_full, 3'h0, rd_full, RType}; // C.ADD + default: is_illegal = 1'b1; endcase end 3'b110: instr_out = {css_imm[11:5], rs2_full, 5'd2, 3'b010, css_imm[4:0], SType}; // C.SWSP - default: instr_out = NOP; + default: is_illegal = 1'b1; endcase end - - default: instr_out = NOP; endcase end From f68d9680ae507ee99373766138d202efad859dfd Mon Sep 17 00:00:00 2001 From: tandr3w Date: Sat, 13 Jun 2026 23:00:25 -0400 Subject: [PATCH 3/4] Add functions to build instructions --- src/ext/c/Compressed_Decode.sv | 121 ++++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 26 deletions(-) diff --git a/src/ext/c/Compressed_Decode.sv b/src/ext/c/Compressed_Decode.sv index 659f5b5..6fa120d 100644 --- a/src/ext/c/Compressed_Decode.sv +++ b/src/ext/c/Compressed_Decode.sv @@ -33,6 +33,75 @@ module Compressed_Decode localparam bit [31:0] NOP = 32'h00000013; + // Helpers to expand compressed instructions based on corresponding 32-bit instruction formats + function automatic logic [31:0] build_r_instr + ( input logic [6:0] funct7 + , input logic [4:0] rs2 + , input logic [4:0] rs1 + , input logic [2:0] funct3 + , input logic [4:0] rd + , input logic [6:0] opcode + ); + return {funct7, rs2, rs1, funct3, rd, opcode}; + endfunction + + function automatic logic [31:0] build_i_instr + ( input logic [11:0] imm + , input logic [4:0] rs1 + , input logic [2:0] funct3 + , input logic [4:0] rd + , input logic [6:0] opcode + ); + return {imm, rs1, funct3, rd, opcode}; + endfunction + + function automatic logic [31:0] build_i_shift_instr + ( input logic [6:0] funct7 + , input logic [4:0] shamt + , input logic [4:0] rs1 + , input logic [2:0] funct3 + , input logic [4:0] rd + , input logic [6:0] opcode + ); + return build_i_instr(.imm({funct7, shamt}), .rs1(rs1), .funct3(funct3), .rd(rd), .opcode(opcode)); + endfunction + + function automatic logic [31:0] build_s_instr + ( input logic [11:0] imm + , input logic [4:0] rs2 + , input logic [4:0] rs1 + , input logic [2:0] funct3 + , input logic [6:0] opcode + ); + return {imm[11:5], rs2, rs1, funct3, imm[4:0], opcode}; + endfunction + + function automatic logic [31:0] build_b_instr + ( input logic [12:0] imm + , input logic [4:0] rs2 + , input logic [4:0] rs1 + , input logic [2:0] funct3 + , input logic [6:0] opcode + ); + return {imm[12], imm[10:5], rs2, rs1, funct3, imm[4:1], imm[11], opcode}; + endfunction + + function automatic logic [31:0] build_u_instr + ( input logic [19:0] imm + , input logic [4:0] rd + , input logic [6:0] opcode + ); + return {imm, rd, opcode}; + endfunction + + function automatic logic [31:0] build_j_instr + ( input logic [20:0] imm + , input logic [4:0] rd + , input logic [6:0] opcode + ); + return {imm[20], imm[10:1], imm[11], imm[19:12], rd, opcode}; + endfunction + // Note: C.FLW, C.FSW, C.FLD, C.FSD, C.FLWSP, C.FLDSP, C.FSWSP, C.FSDSP should be added alongside future F/D extension support. always @(*) begin instr_out = NOP; @@ -44,30 +113,30 @@ module Compressed_Decode 2'b00: begin // Quadrant 0 case (funct3) 3'b000: begin - instr_out = {ciw_imm, 5'd2, 3'b000, rd_prime, IType_logic}; // C.ADDI4SPN + instr_out = build_i_instr(.imm(ciw_imm), .rs1(5'd2), .funct3(3'b000), .rd(rd_prime), .opcode(IType_logic)); // C.ADDI4SPN if (ciw_imm == 12'b0) is_illegal = 1'b1; end - 3'b010: instr_out = {cl_cs_imm, rs1_prime, 3'b010, rd_prime, IType_load}; // C.LW - 3'b110: instr_out = {cl_cs_imm[11:5], rs2_prime, rs1_prime, 3'b010, cl_cs_imm[4:0], SType}; // C.SW + 3'b010: instr_out = build_i_instr(.imm(cl_cs_imm), .rs1(rs1_prime), .funct3(3'b010), .rd(rd_prime), .opcode(IType_load)); // C.LW + 3'b110: instr_out = build_s_instr(.imm(cl_cs_imm), .rs2(rs2_prime), .rs1(rs1_prime), .funct3(3'b010), .opcode(SType)); // C.SW default: is_illegal = 1'b1; endcase end 2'b01: begin // Quadrant 1 case (funct3) - 3'b000: instr_out = {ci_imm, rd_full, 3'b000, rd_full, IType_logic}; // C.ADDI + 3'b000: instr_out = build_i_instr(.imm(ci_imm), .rs1(rd_full), .funct3(3'b000), .rd(rd_full), .opcode(IType_logic)); // C.ADDI // TODO C.JAL does not expand exactly to a base RVI instruction since the link address should be pc+2 instead of pc+4 // Need to add support for offset of 2 bytes and e.g. preserve an is_compressed wire - 3'b001: instr_out = {cj_imm[20], cj_imm[10:1], cj_imm[11], cj_imm[19:12], 5'd1, JType}; // C.JAL - 3'b010: instr_out = {ci_imm, 5'd0, 3'b000, rd_full, IType_logic}; // C.LI + 3'b001: instr_out = build_j_instr(.imm(cj_imm), .rd(5'd1), .opcode(JType)); // C.JAL + 3'b010: instr_out = build_i_instr(.imm(ci_imm), .rs1(5'd0), .funct3(3'b000), .rd(rd_full), .opcode(IType_logic)); // C.LI 3'b011: begin case (instr_c[11:7]) 5'd2: begin - instr_out = {ci_sp_imm, 5'd2, 3'b000, 5'd2, IType_logic}; // C.ADDI16SP + instr_out = build_i_instr(.imm(ci_sp_imm), .rs1(5'd2), .funct3(3'b000), .rd(5'd2), .opcode(IType_logic)); // C.ADDI16SP if (ci_sp_imm == 12'b0) is_illegal = 1'b1; end default: begin - instr_out = {ci_lui_imm, rd_full, UType_lui}; // C.LUI + instr_out = build_u_instr(.imm(ci_lui_imm), .rd(rd_full), .opcode(UType_lui)); // C.LUI if (ci_lui_imm == 20'b0 ) is_illegal = 1'b1; end endcase @@ -75,53 +144,53 @@ module Compressed_Decode 3'b100: begin case (instr_c[11:10]) 2'b00: begin - instr_out = {7'h00, instr_c[6:2], rs1_prime, 3'b101, rs1_prime, IType_logic}; // C.SRLI + instr_out = build_i_shift_instr(.funct7(7'h00), .shamt(shamt), .rs1(rs1_prime), .funct3(3'b101), .rd(rs1_prime), .opcode(IType_logic)); // C.SRLI if (instr_c[12]) is_illegal = 1'b1; end 2'b01: begin - instr_out = {7'h20, instr_c[6:2], rs1_prime, 3'b101, rs1_prime, IType_logic}; // C.SRAI + instr_out = build_i_shift_instr(.funct7(7'h20), .shamt(shamt), .rs1(rs1_prime), .funct3(3'b101), .rd(rs1_prime), .opcode(IType_logic)); // C.SRAI if (instr_c[12]) is_illegal = 1'b1; end - 2'b10: instr_out = {ci_imm, rs1_prime, 3'b111, rs1_prime, IType_logic}; // C.ANDI + 2'b10: instr_out = build_i_instr(.imm(ci_imm), .rs1(rs1_prime), .funct3(3'b111), .rd(rs1_prime), .opcode(IType_logic)); // C.ANDI 2'b11: begin if (instr_c[12]) is_illegal = 1'b1; case (instr_c[6:5]) - 2'b00: instr_out = {7'h20, rs2_prime, rs1_prime, 3'b000, rs1_prime, RType}; // C.SUB - 2'b01: instr_out = {7'h00, rs2_prime, rs1_prime, 3'b100, rs1_prime, RType}; // C.XOR - 2'b10: instr_out = {7'h00, rs2_prime, rs1_prime, 3'b110, rs1_prime, RType}; // C.OR - 2'b11: instr_out = {7'h00, rs2_prime, rs1_prime, 3'b111, rs1_prime, RType}; // C.AND + 2'b00: instr_out = build_r_instr(.funct7(7'h20), .rs2(rs2_prime), .rs1(rs1_prime), .funct3(3'b000), .rd(rs1_prime), .opcode(RType)); // C.SUB + 2'b01: instr_out = build_r_instr(.funct7(7'h00), .rs2(rs2_prime), .rs1(rs1_prime), .funct3(3'b100), .rd(rs1_prime), .opcode(RType)); // C.XOR + 2'b10: instr_out = build_r_instr(.funct7(7'h00), .rs2(rs2_prime), .rs1(rs1_prime), .funct3(3'b110), .rd(rs1_prime), .opcode(RType)); // C.OR + 2'b11: instr_out = build_r_instr(.funct7(7'h00), .rs2(rs2_prime), .rs1(rs1_prime), .funct3(3'b111), .rd(rs1_prime), .opcode(RType)); // C.AND endcase end default: instr_out = NOP; endcase end - 3'b101: instr_out = {cj_imm[20], cj_imm[10:1], cj_imm[11], cj_imm[19:12], 5'd0, JType}; // C.J - 3'b110: instr_out = {cb_imm[12], cb_imm[10:5], 5'd0, rs1_prime, 3'b000, cb_imm[4:1], cb_imm[11], BType}; // C.BEQZ - 3'b111: instr_out = {cb_imm[12], cb_imm[10:5], 5'd0, rs1_prime, 3'b001, cb_imm[4:1], cb_imm[11], BType}; // C.BNEZ + 3'b101: instr_out = build_j_instr(.imm(cj_imm), .rd(5'd0), .opcode(JType)); // C.J + 3'b110: instr_out = build_b_instr(.imm(cb_imm), .rs2(5'd0), .rs1(rs1_prime), .funct3(3'b000), .opcode(BType)); // C.BEQZ + 3'b111: instr_out = build_b_instr(.imm(cb_imm), .rs2(5'd0), .rs1(rs1_prime), .funct3(3'b001), .opcode(BType)); // C.BNEZ endcase end 2'b10: begin // Quadrant 2 case (funct3) 3'b000: begin - instr_out = {7'h00, shamt, rd_full, 3'b001, rd_full, IType_logic}; // C.SLLI + instr_out = build_i_shift_instr(.funct7(7'h00), .shamt(shamt), .rs1(rd_full), .funct3(3'b001), .rd(rd_full), .opcode(IType_logic)); // C.SLLI if (instr_c[12]) is_illegal = 1'b1; end 3'b010: begin - instr_out = {ci_lwsp_imm, 5'd2, 3'b010, rd_full, IType_load}; // C.LWSP + instr_out = build_i_instr(.imm(ci_lwsp_imm), .rs1(5'd2), .funct3(3'b010), .rd(rd_full), .opcode(IType_load)); // C.LWSP if (rd_full == 5'd0) is_illegal = 1'b1; end 3'b100: begin case ({instr_c[12], instr_c[11:7] != 5'd0, instr_c[6:2] != 5'd0}) - 3'b010: instr_out = {12'd0, rs1_full, 3'h0, 5'd0, IType_jalr}; // C.JR - 3'b011, 3'b001: instr_out = {7'h00, rs2_full, 5'd0, 3'h0, rd_full, RType}; // C.MV - 3'b100: instr_out = {12'h001, 5'd0, 3'h0, 5'd0, SYSTEM}; // C.EBREAK - 3'b110: instr_out = {12'd0, rs1_full, 3'h0, 5'd1, IType_jalr}; // C.JALR (TODO see note on C.JAL) - 3'b111, 3'b101: instr_out = {7'h00, rs2_full, rd_full, 3'h0, rd_full, RType}; // C.ADD + 3'b010: instr_out = build_i_instr(.imm(12'd0), .rs1(rs1_full), .funct3(3'h0), .rd(5'd0), .opcode(IType_jalr)); // C.JR + 3'b011, 3'b001: instr_out = build_r_instr(.funct7(7'h00), .rs2(rs2_full), .rs1(5'd0), .funct3(3'h0), .rd(rd_full), .opcode(RType)); // C.MV + 3'b100: instr_out = build_i_instr(.imm(12'h001), .rs1(5'd0), .funct3(3'h0), .rd(5'd0), .opcode(SYSTEM)); // C.EBREAK + 3'b110: instr_out = build_i_instr(.imm(12'd0), .rs1(rs1_full), .funct3(3'h0), .rd(5'd1), .opcode(IType_jalr)); // C.JALR (TODO see note on C.JAL) + 3'b111, 3'b101: instr_out = build_r_instr(.funct7(7'h00), .rs2(rs2_full), .rs1(rd_full), .funct3(3'h0), .rd(rd_full), .opcode(RType)); // C.ADD default: is_illegal = 1'b1; endcase end - 3'b110: instr_out = {css_imm[11:5], rs2_full, 5'd2, 3'b010, css_imm[4:0], SType}; // C.SWSP + 3'b110: instr_out = build_s_instr(.imm(css_imm), .rs2(rs2_full), .rs1(5'd2), .funct3(3'b010), .opcode(SType)); // C.SWSP default: is_illegal = 1'b1; endcase end From 6bc1d0a67a3c7d22f5524ca692d570097645d2e7 Mon Sep 17 00:00:00 2001 From: tandr3w Date: Sat, 13 Jun 2026 23:04:17 -0400 Subject: [PATCH 4/4] make instruction illegal if quadrant is 2'b11 --- src/ext/c/Compressed_Decode.sv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ext/c/Compressed_Decode.sv b/src/ext/c/Compressed_Decode.sv index 6fa120d..5b94514 100644 --- a/src/ext/c/Compressed_Decode.sv +++ b/src/ext/c/Compressed_Decode.sv @@ -108,8 +108,6 @@ module Compressed_Decode is_illegal = 1'b0; case (quadrant) // Opcode - 2'b11: instr_out = {16'b0, instr_c}; // Not a compressed instruction, just pass through (should not actually happen i think?) - 2'b00: begin // Quadrant 0 case (funct3) 3'b000: begin @@ -194,6 +192,8 @@ module Compressed_Decode default: is_illegal = 1'b1; endcase end + + 2'b11: is_illegal = 1'b1; // Not a compressed instruction endcase end