29.14Zcmt: Table Jumps & the jvt CSR

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

  • table jump
  • jvt

Zcmt is dictionary compression for call sites: cm.jt / cm.jalt replace 32-bit j/jal and 64-bit auipc+jr/auipc+jalr sequences with a 16-bit index into a 256-entry, XLEN-wide function-address table. The linker builds the table; each call site shrinks to two bytes.

10115130001210index921010cm.jt/jalt
Click a field for its role.

Target computation: entry_addr = jvt.base + index × (XLEN/8), fetch the XLEN-wide entry, clear bit 0, jump. Entries follow data endianness (unlike normal instruction fetch, which is always little-endian).

The jvt CSR

jvt (0x017, URW)

base[XLEN-1:6]636mode50
WPRI/RO WLRL WARL RW
Click a field for semantics, reset state, and the minimal-implementation note.

Fault handling: the second fetch

Executing a table jump is two implicit instruction fetches — the 16-bit instruction, then the table entry, which the spec declares “an extension of the instruction itself”:

  • Both require execute permission; read permission is irrelevant.
  • A fault on either fetch reports xEPC = the table jump’s PC, xTVAL = the faulting fetch address, xCAUSE per the fault type.
  • Debug triggers/breakpoints should ignore the second fetch.
  • Writes to a table need fence.i before table jumps may observe them (ch. I·5’s rule — this is instruction memory). Switching jvt between tables that were already fenced needs no barrier.

Hardware Designer Notes

The table-entry fetch is the interesting RTL: it reuses the fetch path’s translation/PMP checks (execute, not read!) mid-execute-stage — closer to how Vol II’s SFENCE/translation machinery will feel than anything else in Volume I. If you build it, budget a dedicated fetch-like port or a stall into the icache path, and remember the entry is data-endian: on a bi-endian core the byte-swap mux keys off the DATA endianness control, not the fetch one.

Minimal Linux-boot hart MUST

  • Check execute permission on the table-entry fetch and attribute its faults to the table-jump PC (xTVAL = table address)
  • Fetch entries with DATA endianness; clear bit 0 of the target
  • Implement jvt.mode 0 and WARL-readback discovery; keep jvt.base 64-byte aligned
  • Honor fence.i as the table-update barrier

MAY simplify / trap-and-emulate

  • Hardwire jvt if a fixed table serves your firmware use case
  • Push the RAS on cm.jalt exactly as for jal ra
  • Skip Zcmt on application-class cores — same profile exclusion as Zcmp

Check yourself — table jumps

1.A cm.jalt's table-entry fetch takes a page fault. What does the trap frame show?

2.How does one 8-bit index field encode both cm.jt and cm.jalt?

3.After the kernel updates a jump table in memory, what must happen before table jumps use it?

4.Why must jvt be saved/restored on context switches?

4 questions