2021-01-15 04:37:51 +00:00
|
|
|
///////////////////////////////////////////
|
2021-01-28 05:22:05 +00:00
|
|
|
// decompress.sv
|
2021-01-15 04:37:51 +00:00
|
|
|
//
|
2023-01-19 00:26:51 +00:00
|
|
|
// Written: David_Harris@hmc.edu
|
|
|
|
// Created: 9 January 2021
|
|
|
|
// Modified: 18 January 2023
|
2021-01-15 04:37:51 +00:00
|
|
|
//
|
|
|
|
// Purpose: Expand 16-bit compressed instructions to 32 bits
|
|
|
|
//
|
2023-01-11 23:15:08 +00:00
|
|
|
// A component of the CORE-V-WALLY configurable RISC-V project.
|
2024-01-29 13:38:11 +00:00
|
|
|
// https://github.com/openhwgroup/cvw
|
2021-01-15 04:37:51 +00:00
|
|
|
//
|
2023-01-10 19:35:20 +00:00
|
|
|
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
|
2021-01-15 04:37:51 +00:00
|
|
|
//
|
2023-01-10 19:35:20 +00:00
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
2021-01-15 04:37:51 +00:00
|
|
|
//
|
2023-01-10 19:35:20 +00:00
|
|
|
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
|
|
|
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
|
|
|
// may obtain a copy of the License at
|
2021-01-15 04:37:51 +00:00
|
|
|
//
|
2023-01-10 19:35:20 +00:00
|
|
|
// https://solderpad.org/licenses/SHL-2.1/
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
|
|
|
// 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.
|
2022-01-07 12:58:40 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
2021-01-15 04:37:51 +00:00
|
|
|
|
|
|
|
|
2023-10-04 19:28:12 +00:00
|
|
|
module decompress import cvw::*; #(parameter cvw_t P) (
|
2023-03-22 13:29:30 +00:00
|
|
|
input logic [31:0] InstrRawD, // 32-bit instruction or raw compressed 16-bit instruction in bottom half
|
2023-01-19 00:26:51 +00:00
|
|
|
output logic [31:0] InstrD, // Decompressed instruction
|
|
|
|
output logic IllegalCompInstrD // Invalid decompressed instruction
|
|
|
|
);
|
2024-07-18 15:26:58 +00:00
|
|
|
|
|
|
|
logic [32:0] LInstrD; // decompressed instruction with illegal flag in [32]
|
2021-10-27 19:43:55 +00:00
|
|
|
logic [15:0] instr16;
|
|
|
|
logic [4:0] rds1, rs2, rs1p, rs2p, rds1p, rdp;
|
|
|
|
logic [11:0] immCILSP, immCILSPD, immCSS, immCSSD, immCL, immCLD, immCI, immCS, immCSD, immCB, immCIASP, immCIW;
|
|
|
|
logic [19:0] immCJ, immCILUI;
|
|
|
|
logic [5:0] immSH;
|
|
|
|
logic [1:0] op;
|
2024-07-19 05:01:43 +00:00
|
|
|
logic LegalCompInstrD;
|
2021-01-15 04:37:51 +00:00
|
|
|
|
2023-04-13 23:54:15 +00:00
|
|
|
// Extract op and register source/destination fields
|
2023-01-07 13:51:47 +00:00
|
|
|
assign instr16 = InstrRawD[15:0]; // instruction is already aligned
|
|
|
|
assign op = instr16[1:0];
|
|
|
|
assign rds1 = instr16[11:7];
|
|
|
|
assign rs2 = instr16[6:2];
|
|
|
|
assign rs1p = {2'b01, instr16[9:7]};
|
|
|
|
assign rds1p = {2'b01, instr16[9:7]};
|
|
|
|
assign rs2p = {2'b01, instr16[4:2]};
|
|
|
|
assign rdp = {2'b01, instr16[4:2]};
|
|
|
|
|
2023-01-07 14:06:54 +00:00
|
|
|
// extract compressed immediate formats
|
2023-01-07 13:51:47 +00:00
|
|
|
assign immCILSP = {4'b0000, instr16[3:2], instr16[12], instr16[6:4], 2'b00};
|
|
|
|
assign immCILSPD = {3'b000, instr16[4:2], instr16[12], instr16[6:5], 3'b000};
|
|
|
|
assign immCSS = {4'b0000, instr16[8:7], instr16[12:9], 2'b00};
|
|
|
|
assign immCSSD = {3'b000, instr16[9:7], instr16[12:10], 3'b000};
|
|
|
|
assign immCL = {5'b0, instr16[5], instr16[12:10], instr16[6], 2'b00};
|
|
|
|
assign immCLD = {4'b0, instr16[6:5], instr16[12:10], 3'b000};
|
|
|
|
assign immCS = {5'b0, instr16[5], instr16[12:10], instr16[6], 2'b00};
|
|
|
|
assign immCSD = {4'b0, instr16[6:5], instr16[12:10], 3'b000};
|
|
|
|
assign immCJ = {instr16[12], instr16[8], instr16[10:9], instr16[6], instr16[7], instr16[2], instr16[11], instr16[5:3], {9{instr16[12]}}};
|
|
|
|
assign immCB = {{4{instr16[12]}}, instr16[6:5], instr16[2], instr16[11:10], instr16[4:3], instr16[12]};
|
|
|
|
assign immCI = {{7{instr16[12]}}, instr16[6:2]};
|
|
|
|
assign immCILUI = {{15{instr16[12]}}, instr16[6:2]};
|
|
|
|
assign immCIASP = {{3{instr16[12]}}, instr16[4:3], instr16[5], instr16[2], instr16[6], 4'b0000};
|
|
|
|
assign immCIW = {2'b00, instr16[10:7], instr16[12:11], instr16[5], instr16[6], 2'b00};
|
|
|
|
assign immSH = {instr16[12], instr16[6:2]};
|
2021-01-15 04:37:51 +00:00
|
|
|
|
|
|
|
// only for RV128
|
|
|
|
// assign immCILSPQ = {2{instr16[5]}, instr16[5:2], instr16[12], instr16[6], 4'b0000};
|
|
|
|
// assign immCSSQ = {2{instr16[10]}, instr16[10:7], instr16[12:11], 4'b0000};
|
|
|
|
// assign immCLQ = {4{instr16[10]}, instr16[6:5], instr16[12:11], 4'b0000};
|
|
|
|
// assign immCSQ = {4{instr16[10]}, instr16[6:5], instr16[12:11], 4'b0000};
|
2023-01-07 13:51:47 +00:00
|
|
|
|
|
|
|
always_comb
|
|
|
|
if (op == 2'b11) begin // noncompressed instruction
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b1, InstrRawD};
|
2023-01-07 13:51:47 +00:00
|
|
|
end else begin // convert compressed instruction into uncompressed
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b0, 16'b0, instr16}; // if a legal instruction is not decoded, default to illegal and preserve 16-bit value for mtval
|
2023-01-07 13:51:47 +00:00
|
|
|
case ({op, instr16[15:13]})
|
2024-07-19 05:01:43 +00:00
|
|
|
5'b00000: if (immCIW != 0) LInstrD = {1'b1, immCIW, 5'b00010, 3'b000, rdp, 7'b0010011}; // c.addi4spn
|
|
|
|
5'b00001: if (P.ZCD_SUPPORTED) LInstrD = {1'b1, immCLD, rs1p, 3'b011, rdp, 7'b0000111}; // c.fld
|
|
|
|
5'b00010: LInstrD = {1'b1, immCL, rs1p, 3'b010, rdp, 7'b0000011}; // c.lw
|
2024-07-18 15:26:58 +00:00
|
|
|
5'b00011: if (P.XLEN==32) begin
|
2024-07-19 05:01:43 +00:00
|
|
|
if (P.ZCF_SUPPORTED) LInstrD = {1'b1, immCL, rs1p, 3'b010, rdp, 7'b0000111}; // c.flw
|
|
|
|
end else LInstrD = {1'b1, immCLD, rs1p, 3'b011, rdp, 7'b0000011}; // c.ld
|
2023-10-04 19:28:12 +00:00
|
|
|
5'b00100: if (P.ZCB_SUPPORTED)
|
2024-07-19 05:01:43 +00:00
|
|
|
if (instr16[12:10] == 3'b000) LInstrD = {1'b1, 10'b0, instr16[5], instr16[6], rs1p, 3'b100, rdp, 7'b0000011}; // c.lbu
|
2023-10-04 19:28:12 +00:00
|
|
|
else if (instr16[12:10] == 3'b001) begin
|
2024-07-19 05:01:43 +00:00
|
|
|
if (instr16[6]) LInstrD = {1'b1, 10'b0, instr16[5], 1'b0, rs1p, 3'b001, rdp, 7'b0000011}; // c.lh
|
|
|
|
else LInstrD = {1'b1, 10'b0, instr16[5], 1'b0, rs1p, 3'b101, rdp, 7'b0000011}; // c.lhu
|
2023-10-04 19:28:12 +00:00
|
|
|
end else if (instr16[12:10] == 3'b010)
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b1, 7'b0, rs2p, rs1p, 3'b000, 3'b000, instr16[5], instr16[6], 7'b0100011}; // c.sb
|
2023-10-04 19:28:12 +00:00
|
|
|
else if (instr16[12:10] == 3'b011 & instr16[6] == 1'b0)
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b1, 7'b0, rs2p, rs1p, 3'b001, 3'b000, instr16[5], 1'b0, 7'b0100011}; // c.sh
|
|
|
|
5'b00101: if (P.ZCD_SUPPORTED) LInstrD = {1'b1, immCSD[11:5], rs2p, rs1p, 3'b011, immCSD[4:0], 7'b0100111}; // c.fsd
|
|
|
|
5'b00110: LInstrD = {1'b1, immCS[11:5], rs2p, rs1p, 3'b010, immCS[4:0], 7'b0100011}; // c.sw
|
2024-07-18 15:26:58 +00:00
|
|
|
5'b00111: if (P.XLEN==32) begin
|
2024-07-19 05:01:43 +00:00
|
|
|
if (P.ZCF_SUPPORTED) LInstrD = {1'b1, immCS[11:5], rs2p, rs1p, 3'b010, immCS[4:0], 7'b0100111}; // c.fsw
|
|
|
|
end else LInstrD = {1'b1, immCSD[11:5], rs2p, rs1p, 3'b011, immCSD[4:0], 7'b0100011}; //c.sd
|
2024-07-19 04:38:17 +00:00
|
|
|
5'b01000: if (rds1 != 5'b0)
|
2024-07-19 05:01:43 +00:00
|
|
|
if (immCI[5:0] != 0) LInstrD = {1'b1, immCI, rds1, 3'b000, rds1, 7'b0010011}; // c.addi
|
|
|
|
else LInstrD = {1'b1, 25'b0, 7'b0010011}; // c.addi with imm = 0 is a HINT, treated as nop
|
|
|
|
else if (immCI[5:0] == 6'b0) LInstrD = {1'b1, 25'b0, 7'b0010011}; // c.nop
|
|
|
|
else LInstrD = {1'b1, 25'b0, 7'b0010011}; // c.nop with imm != 0 is a HINT, treated as nop
|
|
|
|
5'b01001: if (P.XLEN==32) LInstrD = {1'b1, immCJ, 5'b00001, 7'b1101111}; // c.jal
|
|
|
|
else if (rds1 != 5'b0) LInstrD = {1'b1, immCI, rds1, 3'b000, rds1, 7'b0011011}; // c.addiw
|
|
|
|
5'b01010: if (rds1 != 5'b0) LInstrD = {1'b1, immCI, 5'b00000, 3'b000, rds1, 7'b0010011}; // c.li
|
|
|
|
else LInstrD = {1'b1, 25'b0, 7'b0010011}; // c.li with rd = 0 is a HINT, treated as nop
|
|
|
|
5'b01011: if (rds1 == 5'b00010) LInstrD = {1'b1, immCIASP, rds1, 3'b000, rds1, 7'b0010011}; // c.addi16sp
|
|
|
|
else if (rds1 != 5'b0) LInstrD = {1'b1, immCILUI, rds1, 7'b0110111}; // c.lui
|
|
|
|
else if (immCILUI[5:0] != 0) LInstrD = {1'b1, 25'b0, 7'b0010011}; // c.lui with rd = 0, imm!=0 is a HINT, treated as nop
|
2024-07-19 04:38:17 +00:00
|
|
|
5'b01100: if (instr16[11:10] == 2'b00) begin
|
2024-07-19 05:01:43 +00:00
|
|
|
if (P.XLEN > 32 | ~immSH[5]) LInstrD = {1'b1, 6'b000000, immSH, rds1p, 3'b101, rds1p, 7'b0010011}; // c.srli; shamt[5] must be 0 in RV32C
|
2024-07-19 04:38:17 +00:00
|
|
|
end else if (instr16[11:10] == 2'b01) begin
|
2024-07-19 05:01:43 +00:00
|
|
|
if (P.XLEN > 32 | ~immSH[5]) LInstrD = {1'b1, 6'b010000, immSH, rds1p, 3'b101, rds1p, 7'b0010011}; // c.srai; shamt[5] must be 0 in RV32C
|
|
|
|
end else if (instr16[11:10] == 2'b10) LInstrD = {1'b1, immCI, rds1p, 3'b111, rds1p, 7'b0010011}; // c.andi
|
|
|
|
else if (instr16[12:10] == 3'b011) begin
|
|
|
|
if (instr16[6:5] == 2'b00) LInstrD = {1'b1, 7'b0100000, rs2p, rds1p, 3'b000, rds1p, 7'b0110011}; // c.sub
|
|
|
|
else if (instr16[6:5] == 2'b01) LInstrD = {1'b1, 7'b0000000, rs2p, rds1p, 3'b100, rds1p, 7'b0110011}; // c.xor
|
|
|
|
else if (instr16[6:5] == 2'b10) LInstrD = {1'b1, 7'b0000000, rs2p, rds1p, 3'b110, rds1p, 7'b0110011}; // c.or
|
|
|
|
else LInstrD = {1'b1, 7'b0000000, rs2p, rds1p, 3'b111, rds1p, 7'b0110011}; // c.and
|
|
|
|
end else begin // (instr16[12:10] == 3'b111)
|
2023-10-04 19:28:12 +00:00
|
|
|
if (instr16[6:5] == 2'b00 & P.XLEN > 32)
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b1, 7'b0100000, rs2p, rds1p, 3'b000, rds1p, 7'b0111011}; // c.subw
|
2023-10-04 19:28:12 +00:00
|
|
|
else if (instr16[6:5] == 2'b01 & P.XLEN > 32)
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b1, 7'b0000000, rs2p, rds1p, 3'b000, rds1p, 7'b0111011}; // c.addw
|
2023-10-04 19:28:12 +00:00
|
|
|
else if (instr16[6:2] == 5'b11000 & P.ZCB_SUPPORTED)
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b1, 12'b000011111111, rds1p, 3'b111, rds1p, 7'b0010011}; // c.zext.b = andi rd, rs1, 255
|
2024-05-16 02:16:43 +00:00
|
|
|
else if (instr16[6:2] == 5'b11001 & P.ZCB_SUPPORTED & P.ZBB_SUPPORTED)
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b1, 12'b011000000100, rds1p, 3'b001, rds1p, 7'b0010011}; // c.sext.b
|
2024-05-16 02:16:43 +00:00
|
|
|
else if (instr16[6:2] == 5'b11010 & P.ZCB_SUPPORTED & P.ZBB_SUPPORTED)
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b1, 7'b0000100, 5'b00000, rds1p, 3'b100, rds1p, 3'b011, P.XLEN > 32, 3'b011}; // c.zext.h
|
2024-05-16 02:16:43 +00:00
|
|
|
else if (instr16[6:2] == 5'b11011 & P.ZCB_SUPPORTED & P.ZBB_SUPPORTED)
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b1, 12'b011000000101, rds1p, 3'b001, rds1p, 7'b0010011}; // c.sext.h
|
2023-10-04 19:28:12 +00:00
|
|
|
else if (instr16[6:2] == 5'b11101 & P.ZCB_SUPPORTED)
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b1, 12'b111111111111, rds1p, 3'b100, rds1p, 7'b0010011}; // c.not = xori
|
2024-05-16 02:16:43 +00:00
|
|
|
else if (instr16[6:2] == 5'b11100 & P.ZCB_SUPPORTED & P.ZBA_SUPPORTED & P.XLEN > 32)
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b1, 7'b0000100, 5'b00000, rds1p, 3'b000, rds1p, 7'b0111011}; // c.zext.w = add.uw rd, rs1, 0
|
2024-05-16 02:16:43 +00:00
|
|
|
else if (instr16[6:5] == 2'b10 & P.ZCB_SUPPORTED & P.ZMMUL_SUPPORTED)
|
2024-07-19 05:01:43 +00:00
|
|
|
LInstrD = {1'b1, 7'b0000001, rs2p, rds1p, 3'b000, rds1p, 7'b0110011}; // c.mul
|
2023-01-07 13:51:47 +00:00
|
|
|
end
|
2024-07-19 05:01:43 +00:00
|
|
|
5'b01101: LInstrD = {1'b1, immCJ, 5'b00000, 7'b1101111}; // c.j
|
|
|
|
5'b01110: LInstrD = {1'b1, immCB[11:5], 5'b00000, rs1p, 3'b000, immCB[4:0], 7'b1100011}; // c.beqz
|
|
|
|
5'b01111: LInstrD = {1'b1, immCB[11:5], 5'b00000, rs1p, 3'b001, immCB[4:0], 7'b1100011}; // c.bnez
|
2024-07-19 04:38:17 +00:00
|
|
|
5'b10000: if (rds1 != 5'b0) begin
|
2024-07-19 05:01:43 +00:00
|
|
|
if (P.XLEN > 32 | ~immSH[5]) LInstrD = {1'b1, 6'b000000, immSH, rds1, 3'b001, rds1, 7'b0010011}; // c.slli; shamt[5] must be 0 in RV32C
|
|
|
|
end else if (immSH != 0) LInstrD = {1'b1, 25'b0, 7'b0010011}; // c.slli with rd = 0, immm != 0 is a HINT, treated as nop
|
2024-05-14 13:49:18 +00:00
|
|
|
5'b10001: if (P.ZCD_SUPPORTED)
|
2024-07-19 05:01:43 +00:00
|
|
|
if (rds1 != 5'b0) LInstrD = {1'b1, immCILSPD, 5'b00010, 3'b011, rds1, 7'b0000111}; // c.fldsp
|
|
|
|
5'b10010: if (rds1 != 5'b0) LInstrD = {1'b1, immCILSP, 5'b00010, 3'b010, rds1, 7'b0000011}; // c.lwsp
|
2024-07-18 15:26:58 +00:00
|
|
|
5'b10011: if (P.XLEN == 32) begin
|
2024-07-19 05:01:43 +00:00
|
|
|
if (P.ZCF_SUPPORTED) LInstrD = {1'b1, immCILSP, 5'b00010, 3'b010, rds1, 7'b0000111}; // c.flwsp
|
|
|
|
end else if (rds1 != 5'b0) LInstrD = {1'b1, immCILSPD, 5'b00010, 3'b011, rds1, 7'b0000011}; // c.ldsp
|
2023-01-07 13:51:47 +00:00
|
|
|
5'b10100: if (instr16[12] == 0)
|
2024-07-19 04:38:17 +00:00
|
|
|
if (rs2 == 5'b00000) begin
|
2024-07-19 05:01:43 +00:00
|
|
|
if (rds1 != 5'b0) LInstrD = {1'b1, 7'b0000000, 5'b00000, rds1, 3'b000, 5'b00000, 7'b1100111}; // c.jr
|
2024-07-18 16:30:16 +00:00
|
|
|
end else
|
2024-07-19 05:01:43 +00:00
|
|
|
if (rds1 != 5'b0) LInstrD = {1'b1, 7'b0000000, rs2, 5'b00000, 3'b000, rds1, 7'b0110011}; // c.mv
|
|
|
|
else LInstrD = {1'b1, 25'b0, 7'b0010011}; // c.mv with rd = 0 is a HINT, treated as nop
|
2023-01-07 13:51:47 +00:00
|
|
|
else
|
2024-07-18 16:30:16 +00:00
|
|
|
if (rs2 == 5'b00000) begin
|
2024-07-19 05:01:43 +00:00
|
|
|
if (rds1 == 5'b00000) LInstrD = {1'b1, 12'b1, 5'b00000, 3'b000, 5'b00000, 7'b1110011}; // c.ebreak
|
|
|
|
else if (rds1 != 5'b0) LInstrD = {1'b1, 12'b0, rds1, 3'b000, 5'b00001, 7'b1100111}; // c.jalr
|
2024-07-18 16:30:16 +00:00
|
|
|
end else
|
2024-07-19 05:01:43 +00:00
|
|
|
if (rds1 != 0) LInstrD = {1'b1, 7'b0000000, rs2, rds1, 3'b000, rds1, 7'b0110011}; // c.add
|
|
|
|
else LInstrD = {1'b1, 25'b0, 7'b0010011}; // c.add with rd = 0 is a HINT, treated as nop, even if it is a C.NTL
|
|
|
|
5'b10101: if (P.ZCD_SUPPORTED) LInstrD = {1'b1, immCSSD[11:5], rs2, 5'b00010, 3'b011, immCSSD[4:0], 7'b0100111}; // c.fsdsp
|
|
|
|
5'b10110: LInstrD = {1'b1, immCSS[11:5], rs2, 5'b00010, 3'b010, immCSS[4:0], 7'b0100011}; // c.swsp
|
2024-07-18 15:26:58 +00:00
|
|
|
5'b10111: if (P.XLEN==32) begin
|
2024-07-19 05:01:43 +00:00
|
|
|
if (P.ZCF_SUPPORTED) LInstrD = {1'b1, immCSS[11:5], rs2, 5'b00010, 3'b010, immCSS[4:0], 7'b0100111}; // c.fswsp
|
|
|
|
end else LInstrD = {1'b1, immCSSD[11:5], rs2, 5'b00010, 3'b011, immCSSD[4:0], 7'b0100011}; // c.sdsp
|
2024-07-18 15:26:58 +00:00
|
|
|
default: ; // illegal instruction
|
2023-01-07 13:51:47 +00:00
|
|
|
endcase
|
2022-01-05 14:35:25 +00:00
|
|
|
end
|
2024-07-18 15:26:58 +00:00
|
|
|
|
|
|
|
// extract instruction and illegal from LInstrD
|
2024-07-19 05:01:43 +00:00
|
|
|
assign {LegalCompInstrD, InstrD} = LInstrD;
|
|
|
|
assign IllegalCompInstrD = ~LegalCompInstrD;
|
2024-07-18 15:26:58 +00:00
|
|
|
|
2021-01-15 04:37:51 +00:00
|
|
|
endmodule
|