cva6/core/compressed_decoder.sv
Farhan Ali Shah 542fe39adc
Some checks are pending
bender-up-to-date / bender-up-to-date (push) Waiting to run
ci / build-riscv-tests (push) Waiting to run
ci / execute-riscv64-tests (push) Blocked by required conditions
ci / execute-riscv32-tests (push) Blocked by required conditions
Adding support for ZCMT Extension for Code-Size Reduction in CVA6 (#2659)
## Introduction
This PR implements the ZCMT extension in the CVA6 core, targeting the 32-bit embedded-class platforms. ZCMT is a code-size reduction feature that utilizes compressed table jump instructions (cm.jt and cm.jalt) to reduce code size for embedded systems
**Note:** Due to implementation complexity, ZCMT extension is primarily targeted at embedded class CPUs. Additionally, it is not compatible with architecture class profiles.(Ref. [Unprivilege spec 27.20](https://drive.google.com/file/d/1uviu1nH-tScFfgrovvFCrj7Omv8tFtkp/view))

## Key additions

- Added zcmt_decoder module for compressed table jump instructions: cm.jt (jump table) and cm.jalt (jump-and-link table)

- Implemented the Jump Vector Table (JVT) CSR to store the base address of the jump table in csr_reg module

- Implemented a return address stack, enabling cm.jalt to behave equivalently to jal ra (jump-and-link with return address), by pushing the return address onto the stack in zcmt_decoder module

## Implementation in CVA6
The implementation of the ZCMT extension involves the following major modifications:

### compressed decoder 
The compressed decoder scans and identifies the cm.jt and cm.jalt instructions, and generates signals indicating that the instruction is both compressed and a ZCMT instruction.

### zcmt_decoder
A new zcmt_decoder module was introduced to decode the cm.jt and cm.jalt instructions, fetch the base address of the JVT table from JVT CSR, extract the index and construct jump instructions to ensure efficient integration of the ZCMT extension in embedded platforms. Table.1 shows the IO port connection of zcmt_decoder module. High-level block diagram of zcmt implementation in CVA6 is shown in Figure 1.

_Table. 1 IO port connection with zcmt_decoder module_
Signals | IO | Description | Connection | Type
-- | -- | -- | -- | --
clk_i | in | Subsystem Clock | SUBSYSTEM | logic
rst_ni | in | Asynchronous reset active low | SUBSYSTEM | logic
instr_i | in | Instruction in | compressed_decoder | logic [31:0]
pc_i | in | Current PC | PC from FRONTEND | logic [CVA6Cfg.VLEN-1:0]
is_zcmt_instr_i | in | Is instruction a zcmt instruction | compressed_decoder | logic
illegal_instr_i | in | Is instruction a illegal instruction | compressed_decoder | logic
is_compressed_i | in | Is instruction a compressed instruction | compressed_decoder | logic
jvt_i | in | JVT struct from CSR | CSR | jvt_t
req_port_i | in | Handshake between CACHE and FRONTEND (fetch) | Cache | dcache_req_o_t
instr_o | out | Instruction out | cvxif_compressed_if_driver | logic [31:0]
illegal_instr_o | out | Is the instruction is illegal | cvxif_compressed_if_driver | logic
is_compressed_o | out | Is the instruction is compressed | cvxif_compressed_if_driver | logic
fetch_stall_o | out | Stall siganl | cvxif_compressed_if_driver | logic
req_port_o | out | Handshake between CACHE and FRONTEND (fetch) | Cache | dcache_req_i_t

### branch unit condition
A condition is implemented in the branch unit to ensure that ZCMT instructions always cause a misprediction, forcing the program to jump to the calculated address of the newly constructed jump instruction.

### JVT CSR
A new JVT csr is implemented in csr_reg which holds the base address of the JVT table. The base address is fetched from the JVT CSR, and combined with the index value to calculate the effective address.

### No MMU
Embedded platform does not utilize the MMU, so zcmt_decoder is connected with cache through port 0 of the Dcache module for implicit read access from the memory.

![zcmt_block drawio](https://github.com/user-attachments/assets/ac7bba75-4f56-42f4-9f5e-0c18f00d4dae)
_Figure. 1 High level block diagram of ZCMT extension implementation_

## Known Limitations
The implementation targets 32-bit instructions for embedded-class platforms without an MMU. Since the core does not utilize an MMU, it is leveraged to connect the zcmt_decoder to the cache via port 0.

## Testing and Verification

- Developed directed test cases to validate cm.jt and cm.jalt instruction functionality
- Verified correct initialization and updates of JVT CSR

### Test Plan 
A test plan is developed to test the functionality of ZCMT extension along with JVT CSR. Directed Assembly test executed to check the functionality. 

_Table. 2 Test plan_
S.no | Features | Description | Pass/Fail Criteria | Test Type | Test status
-- | -- | -- | -- | ---- | --
1 | cm.jt | Simple assembly test to validate the working of cm.jt instruction in  CV32A60x. | Check against Spike's ref. model | Directed | Pass
2 | cm.jalt | Simple assembly test to validate the working of cm.jalt instruction in both CV32A60x. | Check against Spike's ref. model | Directed | Pass
3 | cm.jalt with return address stack | Simple assembly test to validate the working of cm.jalt instruction with return address stack in both CV32A60x. It works as jump and link ( j ra, imm) | Check against Spike's ref. model | Directed | Pass
4 | JVT CSR | Read and write base address of Jump table to JVT CSR | Check against Spike's ref. model | Directed | Pass


**Note**: Please find the test under CVA6_REPO_DIR/verif/tests/custom/zcmt"
2025-01-27 13:23:26 +01:00

947 lines
28 KiB
Systemverilog

// Copyright 2018 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. //
//
// Author: Florian Zaruba - zarubaf@iis.ee.ethz.ch
// 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.
module compressed_decoder #(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty
) (
// Input instruction coming from fetch stage - FRONTEND
input logic [31:0] instr_i,
// Output instruction in uncompressed format - decoder
output logic [31:0] instr_o,
// Input instruction is illegal - decoder
output logic illegal_instr_o,
// Output instruction is macro - decoder
output logic is_macro_instr_o,
// Output instruction is compressed - decoder
output logic is_compressed_o,
// Output instruction is macro - decoder
output logic is_zcmt_instr_o
);
// -------------------
// Compressed Decoder
// -------------------
always_comb begin
illegal_instr_o = 1'b0;
is_compressed_o = 1'b1;
instr_o = instr_i;
is_macro_instr_o = 0;
is_zcmt_instr_o = 1'b0;
// I: | imm[11:0] | rs1 | funct3 | rd | opcode |
// S: | imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode |
unique case (instr_i[1:0])
// C0
riscv::OpcodeC0: begin
unique case (instr_i[15:13])
riscv::OpcodeC0Addi4spn: 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],
riscv::OpcodeOpImm
};
if (instr_i[12:5] == 8'b0) illegal_instr_o = 1'b1;
end
riscv::OpcodeC0Fld: begin
if (CVA6Cfg.FpPresent) begin
// c.fld -> fld rd', imm(rs1')
// CLD: | funct3 | imm[5:3] | rs1' | imm[7:6] | rd' | C0 |
instr_o = {
4'b0,
instr_i[6:5],
instr_i[12:10],
3'b000,
2'b01,
instr_i[9:7],
3'b011,
2'b01,
instr_i[4:2],
riscv::OpcodeLoadFp
};
end else begin
illegal_instr_o = 1'b1;
end
end
riscv::OpcodeC0Lw: 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],
riscv::OpcodeLoad
};
end
riscv::OpcodeC0Ld: begin
// RV64
// c.ld -> ld rd', imm(rs1')
// RV32
// c.flw -> flw fprd', imm(rs1')
if (CVA6Cfg.IS_XLEN64) begin
// CLD: | funct3 | imm[5:3] | rs1' | imm[7:6] | rd' | C0 |
instr_o = {
4'b0,
instr_i[6:5],
instr_i[12:10],
3'b000,
2'b01,
instr_i[9:7],
3'b011,
2'b01,
instr_i[4:2],
riscv::OpcodeLoad
};
end else begin
if (CVA6Cfg.FpPresent) begin
// CFLW: | funct3 (change to LW) | imm[5:3] | rs1' | imm[2|6] | rd' | C0 |
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],
riscv::OpcodeLoadFp
};
end else begin
illegal_instr_o = 1'b1;
end
end
end
riscv::OpcodeC0Zcb: begin
if (CVA6Cfg.RVZCB) begin
unique case (instr_i[12:10])
3'b000: begin
// c.lbu -> lbu rd', uimm(rs1')
instr_o = {
10'b0,
instr_i[5],
instr_i[6],
2'b01,
instr_i[9:7],
3'b100,
2'b01,
instr_i[4:2],
riscv::OpcodeLoad
};
end
3'b001: begin
if (instr_i[6]) begin
// c.lh -> lh rd', uimm(rs1')
instr_o = {
10'b0,
instr_i[5],
1'b0,
2'b01,
instr_i[9:7],
3'b001,
2'b01,
instr_i[4:2],
riscv::OpcodeLoad
};
end else begin
// c.lhu -> lhu rd', uimm(rs1')
instr_o = {
10'b0,
instr_i[5],
1'b0,
2'b01,
instr_i[9:7],
3'b101,
2'b01,
instr_i[4:2],
riscv::OpcodeLoad
};
end
end
3'b010: begin
// c.sb -> sb rs2', uimm(rs1')
instr_o = {
7'b0,
2'b01,
instr_i[4:2],
2'b01,
instr_i[9:7],
3'b000,
3'b0,
instr_i[5],
instr_i[6],
riscv::OpcodeStore
};
end
3'b011: begin
// c.sh -> sh rs2', uimm(rs1')
instr_o = {
7'b0,
2'b01,
instr_i[4:2],
2'b01,
instr_i[9:7],
3'b001,
3'b0,
instr_i[5],
1'b0,
riscv::OpcodeStore
};
end
default: begin
illegal_instr_o = 1'b1;
end
endcase
end else begin
instr_o = instr_i;
illegal_instr_o = 1'b1;
end
end
riscv::OpcodeC0Fsd: begin
if (CVA6Cfg.FpPresent) begin
// c.fsd -> fsd rs2', imm(rs1')
instr_o = {
4'b0,
instr_i[6:5],
instr_i[12],
2'b01,
instr_i[4:2],
2'b01,
instr_i[9:7],
3'b011,
instr_i[11:10],
3'b000,
riscv::OpcodeStoreFp
};
end else begin
illegal_instr_o = 1'b1;
end
end
riscv::OpcodeC0Sw: 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,
riscv::OpcodeStore
};
end
riscv::OpcodeC0Sd: begin
// RV64
// c.sd -> sd rs2', imm(rs1')
// RV32
// c.fsw -> fsw fprs2', imm(rs1')
if (CVA6Cfg.IS_XLEN64) begin
instr_o = {
4'b0,
instr_i[6:5],
instr_i[12],
2'b01,
instr_i[4:2],
2'b01,
instr_i[9:7],
3'b011,
instr_i[11:10],
3'b000,
riscv::OpcodeStore
};
end else begin
if (CVA6Cfg.FpPresent) begin
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,
riscv::OpcodeStoreFp
};
end else begin
illegal_instr_o = 1'b1;
end
end
end
default: begin
illegal_instr_o = 1'b1;
end
endcase
end
// C1
riscv::OpcodeC1: begin
unique case (instr_i[15:13])
riscv::OpcodeC1Addi: begin
// c.addi -> addi rd, rd, nzimm
// c.nop -> addi 0, 0, 0
instr_o = {
{6{instr_i[12]}},
instr_i[12],
instr_i[6:2],
instr_i[11:7],
3'b0,
instr_i[11:7],
riscv::OpcodeOpImm
};
end
riscv::OpcodeC1Addiw: begin // or riscv::OpcodeC1Jal for RV32IC
if (CVA6Cfg.IS_XLEN64) begin
// c.addiw -> addiw rd, rd, nzimm for RV64IC
if (instr_i[11:7] != 5'h0) begin // only valid if the destination is not r0
instr_o = {
{6{instr_i[12]}},
instr_i[12],
instr_i[6:2],
instr_i[11:7],
3'b0,
instr_i[11:7],
riscv::OpcodeOpImm32
};
end else begin
illegal_instr_o = 1'b1;
end
end else begin
// c.jal -> jal x1, imm for RV32IC only
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]}},
5'b1,
riscv::OpcodeJal
};
end
end
riscv::OpcodeC1Li: 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],
riscv::OpcodeOpImm
};
end
riscv::OpcodeC1LuiAddi16sp: begin
// c.lui -> lui rd, imm
instr_o = {{15{instr_i[12]}}, instr_i[6:2], instr_i[11:7], riscv::OpcodeLui};
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,
riscv::OpcodeOpImm
};
end
if ({instr_i[12], instr_i[6:2]} == 6'b0) illegal_instr_o = 1'b1;
end
riscv::OpcodeC1MiscAlu: 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],
4'b0,
instr_i[12],
instr_i[6:2],
2'b01,
instr_i[9:7],
3'b101,
2'b01,
instr_i[9:7],
riscv::OpcodeOpImm
};
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],
riscv::OpcodeOpImm
};
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],
riscv::OpcodeOp
};
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],
riscv::OpcodeOp
};
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],
riscv::OpcodeOp
};
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],
riscv::OpcodeOp
};
end
3'b100: begin
if (CVA6Cfg.IS_XLEN64) begin
// c.subw -> subw 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],
riscv::OpcodeOp32
};
end else begin
illegal_instr_o = 1'b1;
end
end
3'b101: begin
if (CVA6Cfg.IS_XLEN64) begin
// c.addw -> addw rd', rd', rs2'
instr_o = {
2'b00,
5'b0,
2'b01,
instr_i[4:2],
2'b01,
instr_i[9:7],
3'b000,
2'b01,
instr_i[9:7],
riscv::OpcodeOp32
};
end else begin
illegal_instr_o = 1'b1;
end
end
3'b110: begin
if (CVA6Cfg.RVZCB) begin
// c.mul -> mul rd', rd', rs2'
instr_o = {
6'b0,
1'b1,
2'b01,
instr_i[4:2],
2'b01,
instr_i[9:7],
3'b000,
2'b01,
instr_i[9:7],
riscv::OpcodeOp
};
end else begin
instr_o = instr_i;
illegal_instr_o = 1'b1;
end
end
3'b111: begin
if (CVA6Cfg.RVZCB) begin
unique case (instr_i[4:2])
3'b000: begin
// c.zext.b -> andi rd', rd', 0xff
instr_o = {
4'b0,
8'hFF,
2'b01,
instr_i[9:7],
3'b111,
2'b01,
instr_i[9:7],
riscv::OpcodeOpImm
};
end
3'b001: begin
if (CVA6Cfg.RVB) begin
// c.sext.b -> sext.b rd', rd'
instr_o = {
7'h30,
5'h4,
2'b01,
instr_i[9:7],
3'b001,
2'b01,
instr_i[9:7],
riscv::OpcodeOpImm
};
end else illegal_instr_o = 1'b1;
end
3'b010: begin
if (CVA6Cfg.RVB) begin
// c.zext.h -> zext.h rd', rd'
if (CVA6Cfg.IS_XLEN64) begin
instr_o = {
7'h4,
5'h0,
2'b01,
instr_i[9:7],
3'b100,
2'b01,
instr_i[9:7],
riscv::OpcodeOp32
};
end else begin
instr_o = {
7'h4,
5'h0,
2'b01,
instr_i[9:7],
3'b100,
2'b01,
instr_i[9:7],
riscv::OpcodeOp
};
end
end else illegal_instr_o = 1'b1;
end
3'b011: begin
if (CVA6Cfg.RVB) begin
// c.sext.h -> sext.h rd', rd'
instr_o = {
7'h30,
5'h5,
2'b01,
instr_i[9:7],
3'b001,
2'b01,
instr_i[9:7],
riscv::OpcodeOpImm
};
end else illegal_instr_o = 1'b1;
end
3'b100: begin
if (CVA6Cfg.RVB) begin
// c.zext.w -> add.uw
if (CVA6Cfg.IS_XLEN64) begin
instr_o = {
7'h4,
5'h0,
2'b01,
instr_i[9:7],
3'b000,
2'b01,
instr_i[9:7],
riscv::OpcodeOp32
};
end else begin
illegal_instr_o = 1'b1;
end
end else illegal_instr_o = 1'b1;
end
3'b101: begin
// c.not -> xori rd', rd', -1
instr_o = {
12'hFFF,
2'b01,
instr_i[9:7],
3'b100,
2'b01,
instr_i[9:7],
riscv::OpcodeOpImm
};
end
default: begin
instr_o = instr_i;
illegal_instr_o = 1;
end
endcase
end
end
endcase
end
endcase
end
riscv::OpcodeC1J: begin
// 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],
riscv::OpcodeJal
};
end
riscv::OpcodeC1Beqz, riscv::OpcodeC1Bnez: 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],
riscv::OpcodeBranch
};
end
endcase
end
// C2
riscv::OpcodeC2: begin
unique case (instr_i[15:13])
riscv::OpcodeC2Slli: begin
// c.slli -> slli rd, rd, shamt
instr_o = {
6'b0,
instr_i[12],
instr_i[6:2],
instr_i[11:7],
3'b001,
instr_i[11:7],
riscv::OpcodeOpImm
};
end
riscv::OpcodeC2Fldsp: begin
if (CVA6Cfg.FpPresent) begin
// c.fldsp -> fld rd, imm(x2)
instr_o = {
3'b0,
instr_i[4:2],
instr_i[12],
instr_i[6:5],
3'b000,
5'h02,
3'b011,
instr_i[11:7],
riscv::OpcodeLoadFp
};
end else begin
illegal_instr_o = 1'b1;
end
end
riscv::OpcodeC2Lwsp: 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],
riscv::OpcodeLoad
};
if (instr_i[11:7] == 5'b0) illegal_instr_o = 1'b1;
end
riscv::OpcodeC2Ldsp: begin
// RV64
// c.ldsp -> ld rd, imm(x2)
// RV32
// c.flwsp -> flw fprd, imm(x2)
if (CVA6Cfg.IS_XLEN64) begin
instr_o = {
3'b0,
instr_i[4:2],
instr_i[12],
instr_i[6:5],
3'b000,
5'h02,
3'b011,
instr_i[11:7],
riscv::OpcodeLoad
};
if (instr_i[11:7] == 5'b0) illegal_instr_o = 1'b1;
end else begin
if (CVA6Cfg.FpPresent) begin
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],
riscv::OpcodeLoadFp
};
end else begin
illegal_instr_o = 1'b1;
end
end
end
riscv::OpcodeC2JalrMvAdd: 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], riscv::OpcodeOp};
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, riscv::OpcodeJalr};
// rs1 != 0
illegal_instr_o = (instr_i[11:7] != '0) ? 1'b0 : 1'b1;
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], riscv::OpcodeOp};
if (instr_i[6:2] == 5'b0) begin
if (instr_i[11:7] == 5'b0) begin
// c.ebreak -> ebreak
instr_o = {32'h00_10_00_73};
end else begin
// c.jalr -> jalr x1, rs1, 0
instr_o = {12'b0, instr_i[11:7], 3'b000, 5'b00001, riscv::OpcodeJalr};
end
end
end
end
riscv::OpcodeC2Fsdsp: begin
if (CVA6Cfg.FpPresent) begin
// c.fsdsp -> fsd rs2, imm(x2)
instr_o = {
3'b0,
instr_i[9:7],
instr_i[12],
instr_i[6:2],
5'h02,
3'b011,
instr_i[11:10],
3'b000,
riscv::OpcodeStoreFp
};
end else if (CVA6Cfg.RVZCMP && (instr_i[12:10] == 3'b110 || instr_i[12:10] == 3'b111 || instr_i[12:10] == 3'b011)) begin
is_macro_instr_o = 1;
instr_o = instr_i;
end else if (CVA6Cfg.RVZCMT && (instr_i[12:10] == 3'b000)) //jt/jalt instruction
is_zcmt_instr_o = 1'b1;
else illegal_instr_o = 1'b1;
end
riscv::OpcodeC2Swsp: 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,
riscv::OpcodeStore
};
end
riscv::OpcodeC2Sdsp: begin
// RV64
// c.sdsp -> sd rs2, imm(x2)
// RV32
// c.fswsp -> fsw fprs2, imm(x2)
if (CVA6Cfg.IS_XLEN64) begin
instr_o = {
3'b0,
instr_i[9:7],
instr_i[12],
instr_i[6:2],
5'h02,
3'b011,
instr_i[11:10],
3'b000,
riscv::OpcodeStore
};
end else begin
if (CVA6Cfg.FpPresent) begin
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,
riscv::OpcodeStoreFp
};
end else begin
illegal_instr_o = 1'b1;
end
end
end
default: begin
illegal_instr_o = 1'b1;
end
endcase
end
// normal instruction
default: is_compressed_o = 1'b0;
endcase
// Check if the instruction was illegal, if it was then output the offending instruction (zero-extended)
if (illegal_instr_o) begin
instr_o = instr_i;
end
end
endmodule