..
   Copyright (c) 2023 OpenHW Group
   Copyright (c) 2023 Thales

   SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1

.. Level 1
   =======

   Level 2
   -------

   Level 3
   ~~~~~~~

   Level 4
   ^^^^^^^

.. _cva6_riscv_instructions_RV32C:

*Applicability of this chapter to configurations:*

.. csv-table::
   :widths: auto
   :align: left
   :header: "Configuration", "Implementation"

   "CV32A60AX", "Implemented extension"
   "CV32A60X", "Implemented extension"
   "CV64A6_MMU", "Implemented extension"

**Note**: This chapter is specific to CV32A6 configurations. CV64A6 configurations implement as an option RV64C, that includes a different list of instructions.
   

RV32C Compressed Instructions
-----------------------------

RVC uses a simple compression scheme that offers shorter 16-bit versions of common 32-bit RISC-V
instructions when:

    • the immediate or address offset is small;
    • one of the registers is the zero register (x0), the ABI link register (x1), or the ABI stack pointer (x2);
    • the destination register and the first source register are identical;
    • the registers used are the 8 most popular ones.

The C extension is compatible with all other standard instruction extensions. The C extension
allows 16-bit instructions to be freely intermixed with 32-bit instructions, with the latter now able
to start on any 16-bit boundary. With the addition of the C extension, JAL and JALR instructions
will no longer raise an instruction misaligned exception.

Integer Computational Instructions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

- **C.LI**: Compressed Load Immediate

    **Format**: c.li rd, imm[5:0]

    **Description**: loads the sign-extended 6-bit immediate, imm, into register rd.

    **Pseudocode**: x[rd] = sext(imm[5:0])

    **Invalid values**: rd = x0

    **Exception raised**: NONE

- **C.LUI**: Compressed Load Upper Immediate

    **Format**: c.lui rd, nzimm[17:12]

    **Description**: loads the non-zero 6-bit immediate field into bits 17–12 of the destination register, clears the bottom 12 bits, and sign-extends bit 17 into all higher bits of the destination.

    **Pseudocode**: x[rd] = sext(nzimm[17:12] << 12)

    **Invalid values**: rd = x0 & rd = x2 & nzimm = 0

    **Exception raised**: NONE

- **C.ADDI**: Compressed Addition Immediate

    **Format**: c.addi rd, nzimm[5:0]

    **Description**: adds the non-zero sign-extended 6-bit immediate to the value in register rd then writes the result to rd.

    **Pseudocode**: x[rd] = x[rd] + sext(nzimm[5:0])

    **Invalid values**: rd = x0 & nzimm = 0

    **Exception raised**: NONE

- **C.ADDI16SP**: Addition Immediate Scaled by 16, to Stack Pointer

    **Format**: c.addi16sp nzimm[9:4]

    **Description**: adds the non-zero sign-extended 6-bit immediate to the value in the stack pointer (sp=x2), where the immediate is scaled to represent multiples of 16 in the range (-512,496). C.ADDI16SP is used to adjust the stack pointer in procedure prologues and epilogues. C.ADDI16SP shares the opcode with C.LUI, but has a destination field of x2.

    **Pseudocode**: x[2] = x[2] + sext(nzimm[9:4])

    **Invalid values**: rd != x2 & nzimm = 0

    **Exception raised**: NONE

- **C.ADDI4SPN**: Addition Immediate Scaled by 4, to Stack Pointer

    **Format**: c.addi4spn rd', nzimm[9:2]

    **Description**: adds a zero-extended non-zero immediate, scaled by 4, to the stack pointer, x2, and writes the result to rd'. This instruction is used to generate pointers to stack-allocated variables.

    **Pseudocode**: x[8 + rd'] = x[2] + zext(nzimm[9:2])

    **Invalid values**: nzimm = 0

    **Exception raised**: NONE

- **C.SLLI**: Compressed Shift Left Logic Immediate

    **Format**: c.slli rd, uimm[5:0]

    **Description**: performs a logical left shift (zeros are shifted into the lower bits).

    **Pseudocode**: x[rd] = x[rd] << uimm[5:0]

    **Invalid values**: rd = x0 & uimm[5] = 0

    **Exception raised**: NONE

- **C.SRLI**: Compressed Shift Right Logic Immediate

    **Format**: c.srli rd', uimm[5:0]

    **Description**: performs a logical right shift (zeros are shifted into the upper bits).

    **Pseudocode**: x[8 + rd'] = x[8 + rd'] >> uimm[5:0]

    **Invalid values**: uimm[5] = 0

    **Exception raised**: NONE

- **C.SRAI**: Compressed Shift Right Arithmetic Immediate

    **Format**: c.srai rd', uimm[5:0]

    **Description**: performs an arithmetic right shift (sign bits are shifted into the upper bits).

    **Pseudocode**: x[8 + rd'] = x[8 + rd'] >>s uimm[5:0]

    **Invalid values**: uimm[5] = 0

    **Exception raised**: NONE

- **C.ANDI**: Compressed AND Immediate

    **Format**: c.andi rd', imm[5:0]

    **Description**: computes the bitwise AND of the value in register rd', and the sign-extended 6-bit immediate, then writes the result to rd'.

    **Pseudocode**: x[8 + rd'] = x[8 + rd'] & sext(imm[5:0])

    **Invalid values**: NONE

    **Exception raised**: NONE

- **C.ADD**: Compressed Addition

    **Format**: c.add rd, rs2

    **Description**: adds the values in registers rd and rs2 and writes the result to register rd.

    **Pseudocode**: x[rd] = x[rd] + x[rs2]

    **Invalid values**: rd = x0 & rs2 = x0

    **Exception raised**: NONE

- **C.MV**: Move

    **Format**: c.mv rd, rs2

    **Description**: copies the value in register rs2 into register rd.

    **Pseudocode**: x[rd] = x[rs2]

    **Invalid values**: rd = x0 & rs2 = x0

    **Exception raised**: NONE

- **C.AND**: Compressed AND

    **Format**: c.and rd', rs2'

    **Description**: computes the bitwise AND of of the value in register rd', and register rs2', then writes the result to rd'.

    **Pseudocode**: x[8 + rd'] = x[8 + rd'] & x[8 + rs2']

    **Invalid values**: NONE

    **Exception raised**: NONE

- **C.OR**: Compressed OR

    **Format**: c.or rd', rs2'

    **Description**: computes the bitwise OR of of the value in register rd', and register rs2', then writes the result to rd'.

    **Pseudocode**: x[8 + rd'] = x[8 + rd'] | x[8 + rs2']

    **Invalid values**: NONE

    **Exception raised**: NONE

- **C.XOR**: Compressed XOR

    **Format**: c.and rd', rs2'

    **Description**: computes the bitwise XOR of of the value in register rd', and register rs2', then writes the result to rd'.

    **Pseudocode**: x[8 + rd'] = x[8 + rd'] ^ x[8 + rs2']

    **Invalid values**: NONE

    **Exception raised**: NONE

- **C.SUB**: Compressed Subtraction

    **Format**: c.sub rd', rs2'

    **Description**: subtracts the value in registers rs2' from value in rd' and writes the result to register rd'.

    **Pseudocode**: x[8 + rd'] = x[8 + rd'] - x[8 + rs2']

    **Invalid values**: NONE

    **Exception raised**: NONE

- **C.EBREAK**: Compressed Ebreak

    **Format**: c.ebreak

    **Description**: cause control to be transferred back to the debugging environment.

    **Pseudocode**: RaiseException(Breakpoint)

    **Invalid values**: NONE

    **Exception raised**: Raise a Breakpoint exception.

Control Transfer Instructions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

- **C.J**: Compressed Jump

    **Format**: c.j imm[11:1]

    **Description**: performs an unconditional control transfer. The offset is sign-extended and added to the pc to form the jump target address.

    **Pseudocode**: pc += sext(imm[11:1])

    **Invalid values**: NONE

    **Exception raised**: jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception.

- **C.JAL**: Compressed Jump and Link

    **Format**: c.jal imm[11:1]

    **Description**: performs the same operation as C.J, but additionally writes the address of the instruction following the jump (pc+2) to the link register, x1.

    **Pseudocode**: x[1] = pc+2; pc += sext(imm[11:1])

    **Invalid values**: NONE

    **Exception raised**: jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception.

- **C.JR**: Compressed Jump Register

    **Format**: c.jr rs1

    **Description**: performs an unconditional control transfer to the address in register rs1.

    **Pseudocode**: pc = x[rs1]

    **Invalid values**: rs1 = x0

    **Exception raised**: jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception.

- **C.JALR**: Compressed Jump and Link Register

    **Format**: c.jalr rs1

    **Description**: performs the same operation as C.JR, but additionally writes the address of the instruction following the jump (pc+2) to the link register, x1.

    **Pseudocode**: t = pc+2; pc = x[rs1]; x[1] = t

    **Invalid values**: rs1 = x0

    **Exception raised**: jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception.

- **C.BEQZ**: Branch if Equal Zero

    **Format**: c.beqz rs1', imm[8:1]

    **Description**: performs conditional control transfers. The offset is sign-extended and added to the pc to form the branch target address. C.BEQZ takes the branch if the value in register rs1' is zero.

    **Pseudocode**: if (x[8+rs1'] == 0) pc += sext(imm[8:1])

    **Invalid values**: NONE

    **Exception raised**: no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions.

- **C.BNEZ**: Branch if Not Equal Zero

    **Format**: c.bnez rs1', imm[8:1]

    **Description**: performs conditional control transfers. The offset is sign-extended and added to the pc to form the branch target address. C.BEQZ takes the branch if the value in register rs1' isn't zero.

    **Pseudocode**: if (x[8+rs1'] != 0) pc += sext(imm[8:1])

    **Invalid values**: NONE

    **Exception raised**: no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions.

Load and Store Instructions
^^^^^^^^^^^^^^^^^^^^^^^^^^^

- **C.LWSP**: Load Word Stack-Pointer

    **Format**: c.lwsp rd, uimm(x2)

    **Description**: loads a 32-bit value from memory into register rd. It computes an effective address by adding the zero-extended offset, scaled by 4, to the stack pointer, x2.

    **Pseudocode**: x[rd] = M[x[2] + zext(uimm[7:2])][31:0]

    **Invalid values**: rd = x0

    **Exception raised**: loads with a destination of x0 must still raise any exceptions, also an exception if the memory address isn't aligned (4-byte boundary).

- **C.SWSP**: Store Word Stack-Pointer

    **Format**: c.swsp rd, uimm(x2)

    **Description**: stores a 32-bit value in register rs2 to memory. It computes an effective address by adding the zero-extended offset, scaled by 4, to the stack pointer, x2.

    **Pseudocode**: M[x[2] + zext(uimm[7:2])][31:0] = x[rs2]

    **Invalid values**: NONE

    **Exception raised**: an exception raised if the memory address isn't aligned (4-byte boundary).

- **C.LW**: Compressed Load Word

    **Format**: c.lw rd', uimm(rs1')

    **Description**: loads a 32-bit value from memory into register rd'. It computes an effective address by adding the zero-extended offset, scaled by 4, to the base address in register rs1'.

    **Pseudocode**: x[8+rd'] = M[x[8+rs1'] + zext(uimm[6:2])][31:0])

    **Invalid values**: NONE

    **Exception raised**: an exception raised if the memory address isn't aligned (4-byte boundary).

- **C.SW**: Compressed Store Word

    **Format**: c.sw rs2', uimm(rs1')

    **Description**: stores a 32-bit value from memory into register rd'. It computes an effective address by adding the zero-extended offset, scaled by 4, to the base address in register rs1'.

    **Pseudocode**: M[x[8+rs1'] + zext(uimm[6:2])][31:0] = x[8+rs2']

    **Invalid values**: NONE

    **Exception raised**: an exception raised if the memory address isn't aligned (4-byte boundary).