// Copyright 2017 ETH Zurich and University of Bologna. // Copyright and related rights are licensed under the Solderpad Hardware // License, Version 0.51 (the “License”); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law // or agreed to in writing, software, hardware and materials distributed under // this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. //////////////////////////////////////////////////////////////////////////////// // // // Engineer: Sven Stucki - svstucki@student.ethz.ch // // // // Design Name: Compressed instruction decoder // // Project Name: zero-riscy // // Language: SystemVerilog // // // // Description: Decodes RISC-V compressed instructions into their RV32 // // equivalent. This module is fully combinatorial. // // // //////////////////////////////////////////////////////////////////////////////// import zeroriscy_defines::*; module zeroriscy_compressed_decoder ( input logic [31:0] instr_i, output logic [31:0] instr_o, output logic is_compressed_o, output logic illegal_instr_o ); ////////////////////////////////////////////////////////////////////////////////////////////////////// // ____ _ ____ _ // // / ___|___ _ __ ___ _ __ _ __ ___ ___ ___ ___ __| | | _ \ ___ ___ ___ __| | ___ _ __ // // | | / _ \| '_ ` _ \| '_ \| '__/ _ \/ __/ __|/ _ \/ _` | | | | |/ _ \/ __/ _ \ / _` |/ _ \ '__| // // | |__| (_) | | | | | | |_) | | | __/\__ \__ \ __/ (_| | | |_| | __/ (_| (_) | (_| | __/ | // // \____\___/|_| |_| |_| .__/|_| \___||___/___/\___|\__,_| |____/ \___|\___\___/ \__,_|\___|_| // // |_| // ////////////////////////////////////////////////////////////////////////////////////////////////////// always_comb begin illegal_instr_o = 1'b0; instr_o = '0; unique case (instr_i[1:0]) // C0 2'b00: begin unique case (instr_i[15:13]) 3'b000: begin // c.addi4spn -> addi rd', x2, imm instr_o = {2'b0, instr_i[10:7], instr_i[12:11], instr_i[5], instr_i[6], 2'b00, 5'h02, 3'b000, 2'b01, instr_i[4:2], OPCODE_OPIMM}; if (instr_i[12:5] == 8'b0) illegal_instr_o = 1'b1; end 3'b010: begin // c.lw -> lw rd', imm(rs1') instr_o = {5'b0, instr_i[5], instr_i[12:10], instr_i[6], 2'b00, 2'b01, instr_i[9:7], 3'b010, 2'b01, instr_i[4:2], OPCODE_LOAD}; end 3'b110: begin // c.sw -> sw rs2', imm(rs1') instr_o = {5'b0, instr_i[5], instr_i[12], 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b010, instr_i[11:10], instr_i[6], 2'b00, OPCODE_STORE}; end default: begin illegal_instr_o = 1'b1; end endcase end // C1 2'b01: begin unique case (instr_i[15:13]) 3'b000: begin // c.addi -> addi rd, rd, nzimm // c.nop instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], instr_i[11:7], 3'b0, instr_i[11:7], OPCODE_OPIMM}; end 3'b001, 3'b101: begin // 001: c.jal -> jal x1, imm // 101: c.j -> jal x0, imm instr_o = {instr_i[12], instr_i[8], instr_i[10:9], instr_i[6], instr_i[7], instr_i[2], instr_i[11], instr_i[5:3], {9 {instr_i[12]}}, 4'b0, ~instr_i[15], OPCODE_JAL}; end 3'b010: begin // c.li -> addi rd, x0, nzimm instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], 5'b0, 3'b0, instr_i[11:7], OPCODE_OPIMM}; if (instr_i[11:7] == 5'b0) illegal_instr_o = 1'b1; end 3'b011: begin // c.lui -> lui rd, imm instr_o = {{15 {instr_i[12]}}, instr_i[6:2], instr_i[11:7], OPCODE_LUI}; if (instr_i[11:7] == 5'h02) begin // c.addi16sp -> addi x2, x2, nzimm instr_o = {{3 {instr_i[12]}}, instr_i[4:3], instr_i[5], instr_i[2], instr_i[6], 4'b0, 5'h02, 3'b000, 5'h02, OPCODE_OPIMM}; end else if (instr_i[11:7] == 5'b0) begin illegal_instr_o = 1'b1; end if ({instr_i[12], instr_i[6:2]} == 6'b0) illegal_instr_o = 1'b1; end 3'b100: begin unique case (instr_i[11:10]) 2'b00, 2'b01: begin // 00: c.srli -> srli rd, rd, shamt // 01: c.srai -> srai rd, rd, shamt instr_o = {1'b0, instr_i[10], 5'b0, instr_i[6:2], 2'b01, instr_i[9:7], 3'b101, 2'b01, instr_i[9:7], OPCODE_OPIMM}; if (instr_i[12] == 1'b1) illegal_instr_o = 1'b1; if (instr_i[6:2] == 5'b0) illegal_instr_o = 1'b1; end 2'b10: begin // c.andi -> andi rd, rd, imm instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], 2'b01, instr_i[9:7], 3'b111, 2'b01, instr_i[9:7], OPCODE_OPIMM}; end 2'b11: begin unique case ({instr_i[12], instr_i[6:5]}) 3'b000: begin // c.sub -> sub rd', rd', rs2' instr_o = {2'b01, 5'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b000, 2'b01, instr_i[9:7], OPCODE_OP}; end 3'b001: begin // c.xor -> xor rd', rd', rs2' instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b100, 2'b01, instr_i[9:7], OPCODE_OP}; end 3'b010: begin // c.or -> or rd', rd', rs2' instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b110, 2'b01, instr_i[9:7], OPCODE_OP}; end 3'b011: begin // c.and -> and rd', rd', rs2' instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b111, 2'b01, instr_i[9:7], OPCODE_OP}; end 3'b100, 3'b101, 3'b110, 3'b111: begin // 100: c.subw // 101: c.addw illegal_instr_o = 1'b1; end endcase end endcase end 3'b110, 3'b111: begin // 0: c.beqz -> beq rs1', x0, imm // 1: c.bnez -> bne rs1', x0, imm instr_o = {{4 {instr_i[12]}}, instr_i[6:5], instr_i[2], 5'b0, 2'b01, instr_i[9:7], 2'b00, instr_i[13], instr_i[11:10], instr_i[4:3], instr_i[12], OPCODE_BRANCH}; end default: begin illegal_instr_o = 1'b1; end endcase end // C2 2'b10: begin unique case (instr_i[15:13]) 3'b000: begin // c.slli -> slli rd, rd, shamt instr_o = {7'b0, instr_i[6:2], instr_i[11:7], 3'b001, instr_i[11:7], OPCODE_OPIMM}; if (instr_i[11:7] == 5'b0) illegal_instr_o = 1'b1; if (instr_i[12] == 1'b1 || instr_i[6:2] == 5'b0) illegal_instr_o = 1'b1; end 3'b010: begin // c.lwsp -> lw rd, imm(x2) instr_o = {4'b0, instr_i[3:2], instr_i[12], instr_i[6:4], 2'b00, 5'h02, 3'b010, instr_i[11:7], OPCODE_LOAD}; if (instr_i[11:7] == 5'b0) illegal_instr_o = 1'b1; end 3'b100: begin if (instr_i[12] == 1'b0) begin // c.mv -> add rd/rs1, x0, rs2 instr_o = {7'b0, instr_i[6:2], 5'b0, 3'b0, instr_i[11:7], OPCODE_OP}; if (instr_i[6:2] == 5'b0) begin // c.jr -> jalr x0, rd/rs1, 0 instr_o = {12'b0, instr_i[11:7], 3'b0, 5'b0, OPCODE_JALR}; end end else begin // c.add -> add rd, rd, rs2 instr_o = {7'b0, instr_i[6:2], instr_i[11:7], 3'b0, instr_i[11:7], OPCODE_OP}; if (instr_i[11:7] == 5'b0) begin // c.ebreak -> ebreak instr_o = {32'h00_10_00_73}; if (instr_i[6:2] != 5'b0) illegal_instr_o = 1'b1; end else if (instr_i[6:2] == 5'b0) begin // c.jalr -> jalr x1, rs1, 0 instr_o = {12'b0, instr_i[11:7], 3'b000, 5'b00001, OPCODE_JALR}; end end end 3'b110: begin // c.swsp -> sw rs2, imm(x2) instr_o = {4'b0, instr_i[8:7], instr_i[12], instr_i[6:2], 5'h02, 3'b010, instr_i[11:9], 2'b00, OPCODE_STORE}; end default: begin illegal_instr_o = 1'b1; end endcase end default: begin // 32 bit (or more) instruction instr_o = instr_i; end endcase end assign is_compressed_o = (instr_i[1:0] != 2'b11); endmodule