The computational half of RVC is a lesson in encoding frugality: nearly every “spare” operand combination — x0 destinations, zero immediates, special registers — is recycled into another instruction, a HINT, or reserved space. Decode is therefore a cascade of field checks, and this page is the map.
28.5 Computational instructions and their recycled code points
| Expands to | Code-point fine print | |
|---|---|---|
| C.LI (CI) | addi rd, x0, imm6 | rd=0 → HINT |
| C.LUI (CI) | lui rd, nzimm (bits 17:12) | rd∉{0,2}, imm≠0 |
| C.ADDI16SP | addi x2, x2, nzimm×16 | Range [−512, 496]; nzimm=0 reserved |
| C.ADDI4SPN (CIW) | addi rd′, x2, nzuimm×4 | nzuimm=0 reserved — pointers into the stack frame |
| C.ADDI (CI) | addi rd, rd, nzimm | rd=0 → C.NOP (its imm≠0 points are HINTs); imm=0 (rd≠0) → HINT |
| C.ADDIW (CI, RV64) | addiw rd, rd, imm | imm MAY be 0 (= sext.w); rd=0 reserved. Same code point is C.JAL on RV32 |
| C.SLLI (CI) | slli rd, rd, shamt | Full 5-bit rd; RV32: shamt[5]=1 → custom space; rd=0 or shamt=0 → HINT |
| C.SRLI / C.SRAI / C.ANDI (CB) | srli/srai/andi rd′, rd′, imm | Prime registers; shifts: shamt=0 HINT, RV32 shamt[5] custom |
| C.MV (CR) | add rd, x0, rs2 | rs2=0 → C.JR; rd=0 → HINT |
| C.ADD (CR) | add rd, rd, rs2 | rs2=0 → C.JALR (rd≠0) or C.EBREAK (rd=0); rd=0 → HINT/C.NTL.* |
| C.AND/OR/XOR/SUB (CA) | and/or/xor/sub rd′, rd′, rs2′ | Prime registers, funct2 selects |
| C.ADDW / C.SUBW (CA, RV64) | addw/subw rd′, rd′, rs2′ | RV32: reserved |
Three special citizens: the all-zero 16-bit encoding is permanently
illegal (traps jumps into zeroed memory — never redefine it, even in
custom extensions); C.NOP = addi x0, x0, 0’s compressed twin;
C.EBREAK hides in C.ADD’s rd=rs2=0 corner.
28.6 LR/SC loops, compressed
Constrained LR/SC loops (ch. I·13) may use the compressed forms of the permitted instructions. Claiming A and C means your eventuality guarantee holds for 16-bit-encoded loops too.
28.7 RVC HINTs
Same architecture as base HINTs (no state change but pc/counters,
executed as dead ops), one twist: RVC HINT code points need not map to
the corresponding RVI HINTs — the scarce space goes to popular,
fusible hints instead. Already assigned: C.NTL.* = C.ADD x0, x2–x5
(Table 38: ~78% future-standard, custom rows in the degenerate
shift/C.SLLI points).
28.8 The quadrant map
op[1:0] picks the quadrant rvc quadrant map op[1:0] selects the quadrant: 00 (loads/stores + ADDI4SPN), 01 (immediates/jumps/branches/CA-arith), 10 (SLLI, SP-relative loads/stores, JR/MV/ADD/EBREAK); 11 = wider-than-16-bit instructions. defined in ch. I·28 — open in glossary ; funct3 (bits 15:13) picks the row (Table 39):
| Quadrant 00 | Quadrant 01 | Quadrant 10 | |
|---|---|---|---|
| 000 | ADDI4SPN | ADDI | SLLI |
| 001 | FLD | JAL (RV32) / ADDIW (RV64) | FLDSP |
| 010 | LW | LI | LWSP |
| 011 | FLW (RV32) / LD (RV64) | LUI / ADDI16SP | FLWSP (RV32) / LDSP (RV64) |
| 100 | Reserved | MISC-ALU (SRLI/SRAI/ANDI/SUB/XOR/OR/AND/SUBW/ADDW) | J[AL]R / MV / ADD / EBREAK |
| 101 | FSD | J | FSDSP |
| 110 | SW | BEQZ | SWSP |
| 111 | FSW (RV32) / SD (RV64) | BNEZ | FSWSP (RV32) / SDSP (RV64) |
(Quadrant 11 = anything ≥ 32 bits — the base ISA’s world.)
Hardware Designer Notes
The decode cascade for quadrant 1’s funct3=011 and quadrant 2’s funct3=100 rows is where RVC decoders grow their bugs — write the truth table (rd=0? rd=2? rs2=0? bit 12?) directly from Figures 4/5 and let your DV cross every RES/HINT corner against a reference decoder. The listings’ RES points are your documented-choice space; the HINT points are not (they must execute).
Minimal Linux-boot hart MUST
- Trap the all-zero 16-bit encoding as illegal — never recycle it
- Decode the recycled corners exactly: C.LUI rd=2 → ADDI16SP; C.MV rs2=0 → JR; C.ADD rs2=0 → JALR/EBREAK
- Execute RVC HINT points as dead ops (never trap); implement C.NTL.* only if you implement NTL
- Honor LR/SC eventuality for compressed constrained loops if you claim A+C
MAY simplify / trap-and-emulate
- Expand C.MV to the canonical MV (ADDI) instead of ADD when your rename stage pattern-matches moves
- Ignore all HINTs; use the custom HINT rows (degenerate shifts) for your own hints
Check yourself — RVC computation & code points
1.How does the decoder tell C.LUI from C.ADDI16SP? They share funct3=011 in quadrant 1.
2.C.MV expands to ADD rd, x0, rs2 — not to ADDI rd, rs2, 0 (the canonical MV). Why does the spec call this out?
3.Must C.ADD x0, a0 behave identically to the RVI HINT ADD x0, x0, a0?
4.Your A+C core runs a constrained LR/SC loop written with compressed instructions. Does the forward-progress guarantee apply?