29.13.6-7Zcmp: PUSH Examples & the cm.push Encoding

Part I Linux boot: optional Vol. I (Unprivileged) pp. 191–197 · ~3 min read

  • urlist/spimm

With the semantics fixed (previous page), this page pins down the bits: how register lists and stack adjustments pack into 16 bits, and exactly what a cm.push expands to.

Worked expansions (RV32)

cm.push {ra, s0-s2}, -64 — encoding rlist=7, spimm=3:

sw   s2,  -4(sp)      # s-registers descend from just below old sp
sw   s1,  -8(sp)
sw   s0, -12(sp)
sw   ra, -16(sp)      # ra lowest
addi sp, sp, -64      # 16 bytes of registers + 3×16 extra

cm.pop {ra}, 16 — rlist=4, spimm=0:

lw   ra, 12(sp)       # loads mirror the layout, top of frame
addi sp, sp, 16

The frame layout is canonical — s11 sits nearest the old sp, ra lowest — because debuggers and unwinders must parse these frames; only the access order/grouping is implementation-loose.

The CMPP encoding

101151311000128rlist74spimm321010cm.push
Click a field for its role.
rlist → register list (UABI mapping) and RV32I/RV64 stack_adj_base
reg_listbase (RV32I)base (RV64)
rlist 4{ra}1616
rlist 5{ra, s0}1616
rlist 6{ra, s0-s1}1632
rlist 7{ra, s0-s2}1632
rlist 8{ra, s0-s3}3248
rlist 9{ra, s0-s4}3248
rlist 10{ra, s0-s5}3264
rlist 11{ra, s0-s6}3264
rlist 12{ra, s0-s7}4880
rlist 13{ra, s0-s8}4880
rlist 14{ra, s0-s9}4896
rlist 15{ra, s0-s11}64112
Dotted-underlined cells have explanations — click one.

stack_adj = stack_adj_base + spimm × 16 — the base is the register storage rounded up to a 16-byte multiple (the UABI keeps sp 16-byte aligned), spimm buys up to 48 bytes of locals, and anything bigger chains a c.addi16sp. On RV32E only rlist 4–6 exist and the base is always 16.

Hardware Designer Notes

Implementation sketch: rlist → a 13-bit register bitmap (via a 12-entry ROM), then a µop sequencer walks the bitmap descending, addr starting at sp − bytes. The stack_adj adder needs only the base ROM (per XLEN) plus spimm≪4. The following pages cover cm.pop/popret[z] (same skeleton, loads + tail group) and the mv-pair helpers.

Minimal Linux-boot hart MUST

  • Generate the canonical frame layout (s11 highest, ra lowest) — unwinders depend on it
  • Treat rlist 0-3 as reserved (future EABI), and respect the missing {ra,s0-s10} list
  • Compute stack_adj_base per-XLEN (the RV64 table differs: 8-byte slots)

MAY simplify / trap-and-emulate

  • Emit the stores in any order/grouping — only the layout and the atomic sp tail are contractual

Check yourself — cm.push encoding

1.cm.push {ra, s0-s2}, -64 on RV32 encodes rlist=7, spimm=3. Reconstruct the math.

2.Why do rlist values 0-3 not encode {}, {ra} variants… what are they?

3.In what order does cm.push store, per the pseudocode?

3 questions