Applicability of this chapter to configurations:

Configuration

Implementation

CV32A60X

Implemented extension

Note: Zcmp is primarily targeted at embedded class CPUs due to implementation complexity. Additionally, it is not compatible with architecture class profiles.

RVZcmp Code Size Reduction Instructions

Zcmp belongs to group of extensions called RISC-V Code Size Reduction Extension (Zc*). Zc* has become the superset of Standard C extension adding more 16-bit instructions to the ISA. Zcmp includes 16-bit macro instructions, PUSH/POP and double move, which reuse the encoding for c.fsdsp instruction. All the Zcmp instructions require at least C extension support with Zcd extension disabled as pre-requisite.

  • CM.PUSH: Compressed Push

    Format: cm.push {reg_list}, -stack_adj

    Description: This instruction pushes (stores) the registers in reg_list to the memory below the stack pointer, and then creates the stack frame by decrementing the stack pointer by stack_adj, including any additional stack space requested by the value of spimm.

    Pseudocode: if (XLEN==32) bytes=4; else bytes=8;

    addr=sp-bytes; for(i in 27,26,25,24,23,22,21,20,19,18,9,8,1) {

    if (xreg_list[i]) {
    switch(bytes) {

    4: asm(“sw x[i], 0(addr)”); 8: asm(“sd x[i], 0(addr)”);

    } addr-=bytes;

    }

    } sp-=stack_adj;

    Invalid values: reg_list not in [ {ra}, {ra, s0}, {ra, s0-s1}, {ra, s0-s2}, …, {ra, s0-s8}, {ra, s0-s9}, {ra, s0-s11} ], stack_adj not in [ 16, 32, 48, 64, 80, 96, 112 ] and [ 16, 32, 48, 64, 80, 96, 112, 128, 144, 160 ] for RV32 and RV64 respectively.

    Exception raised: NONE

  • CM.POP: Compressed Pop

    Format: cm.pop {reg_list}, stack_abj

    Description: Destroy stack frame: load ra and 0 to 12 saved registers from the stack frame, deallocate the stack frame.

    Pseudocode: if (XLEN==32) bytes=4; else bytes=8;

    addr=sp+stack_adj-bytes; for(i in 27,26,25,24,23,22,21,20,19,18,9,8,1) {

    if (xreg_list[i]) {
    switch(bytes) {

    4: asm(“lw x[i], 0(addr)”); 8: asm(“ld x[i], 0(addr)”);

    } addr-=bytes;

    }

    } sp+=stack_adj;

    Invalid values: reg_list not in [ {ra}, {ra, s0}, {ra, s0-s1}, {ra, s0-s2}, …, {ra, s0-s8}, {ra, s0-s9}, {ra, s0-s11} ], stack_adj not in [ 16, 32, 48, 64, 80, 96, 112 ] and [ 16, 32, 48, 64, 80, 96, 112, 128, 144, 160 ] for RV32 and RV64 respectively.

    Exception raised: NONE

  • CM.POPRETZ: Compressed Pop return zero

    Format: cm.popretz {reg_list}, stack_adj

    Description: Destroy stack frame: load ra and 0 to 12 saved registers from the stack frame, deallocate the stack frame, move zero into a0, return to ra.

    Pseudocode: if (XLEN==32) bytes=4; else bytes=8;

    addr=sp+stack_adj-bytes; for(i in 27,26,25,24,23,22,21,20,19,18,9,8,1) {

    if (xreg_list[i]) {
    switch(bytes) {

    4: asm(“lw x[i], 0(addr)”); 8: asm(“ld x[i], 0(addr)”);

    } addr-=bytes;

    }

    } asm(“li a0, 0”); sp+=stack_adj; asm(“ret”);

    Invalid values: reg_list not in [ {ra}, {ra, s0}, {ra, s0-s1}, {ra, s0-s2}, …, {ra, s0-s8}, {ra, s0-s9}, {ra, s0-s11} ], stack_adj not in [ 16, 32, 48, 64, 80, 96, 112 ] and [ 16, 32, 48, 64, 80, 96, 112, 128, 144, 160 ] for RV32 and RV64 respectively.

    Exception raised: NONE

  • CM.POPRET: Compressed Pop return

    Format: cm.popret {reg_list}, stack_adj

    Description: Destroy stack frame: load ra and 0 to 12 saved registers from the stack frame, deallocate the stack frame, return to ra.

    Pseudocode: if (XLEN==32) bytes=4; else bytes=8;

    addr=sp+stack_adj-bytes; for(i in 27,26,25,24,23,22,21,20,19,18,9,8,1) {

    if (xreg_list[i]) {
    switch(bytes) {

    4: asm(“lw x[i], 0(addr)”); 8: asm(“ld x[i], 0(addr)”);

    } addr-=bytes;

    }

    } sp+=stack_adj; asm(“ret”);

    Invalid values: reg_list not in [ {ra}, {ra, s0}, {ra, s0-s1}, {ra, s0-s2}, …, {ra, s0-s8}, {ra, s0-s9}, {ra, s0-s11} ], stack_adj not in [ 16, 32, 48, 64, 80, 96, 112 ] and [ 16, 32, 48, 64, 80, 96, 112, 128, 144, 160 ] for RV32 and RV64 respectively.

    Exception raised: NONE

  • CM.MVSA01: Compressed move argument registers into save registers

    Format: cm.mvsa01 r1s’, r2s’

    Description: This instruction moves a0 into r1s’ and a1 into r2s’. r1s’ and r2s’ must be different. The execution is atomic, so it is not possible to observe state where only one of r1s’ or r2s’ has been updated.

    Pseudocode: if (RV32E && (r1sc>1 || r2sc>1)) {

    reserved();

    } xreg1 = {r1sc[2:1]>0,r1sc[2:1]==0,r1sc[2:0]}; xreg2 = {r2sc[2:1]>0,r2sc[2:1]==0,r2sc[2:0]}; X[xreg1] = X[10]; X[xreg2] = X[11];

    Invalid values: r1s’ = r2s’

    Exception raised: NONE

  • CM.MVA01S: Compressed move save registers into argument registers

    Format: cm.mva01s r1s’, r2s’

    Description: This instruction moves r1s’ into a0 and r2s’ into a1. The execution is atomic, so it is not possible to observe state where only one of a0 or a1 have been updated.

    Pseudocode: if (RV32E && (r1sc>1 || r2sc>1)) {

    reserved();

    } xreg1 = {r1sc[2:1]>0,r1sc[2:1]==0,r1sc[2:0]}; xreg2 = {r2sc[2:1]>0,r2sc[2:1]==0,r2sc[2:0]}; X[10] = X[xreg1]; X[11] = X[xreg2];

    Invalid values: NONE

    Exception raised: NONE