nx_isa_s390x_gate.nx
buildroot/runtime/nx_isa_s390x_gate.nx
about
nx_isa_s390x_gate.nx -- THE s390x CONFORMANCE RULER.
WHY IT EXISTS: nx_isa_conform_gate measures rv64, mips64, arm64, riscv32 and
ppc64le and names s390x in its own output as UNMEASURED. An emulator nobody
runs machine code through is a claim, not a capability. This organ decides
"we emulate IBM z/Architecture" by RUNNING s390x machine code, in process,
against values taken FROM THE z/ARCHITECTURE PRINCIPLES OF OPERATION -- never
from nx_emu_s390x.nx itself, which would calibrate the ruler to its subject.
SEPARATE ORGAN, NOT A PATCH TO THE INCUMBENT: five other ISA lanes are
editing the estate at the same time, and concurrent edits to one file
silently clobber each other here. The SHAPE is copied from
nx_isa_conform_gate (word emitters, five-way classification, a value-printing
report, negative controls, a fixture-reached tooth, a good-when-higher
ratchet); nothing is imported from it, so neither can break the other.
FIVE OUTCOMES, NEVER ONE:
PASS ran and matched the manual-derived expectation
WRONG-ANSWER ran to completion and computed the wrong value
UNSUPPORTED hit an instruction class the emulator does not implement
RAN-OFF-END the interpreter loop ended without an exit syscall
FAULT bad pc, out-of-range access, or the step budget
Collapsing these into FAIL is what makes a gap unactionable: an unimplemented
instruction class and a miscomputed result need OPPOSITE fixes.
WHAT MAKES s390x DIFFERENT FROM EVERY OTHER LANE ON THIS BOARD: it is the
only VARIABLE-LENGTH ISA here. The instruction length comes from the top two
bits of byte 0 (00 -> 2 bytes, 01/10 -> 4, 11 -> 6), so the emitter cannot be
a single put_word helper and every branch displacement is a HALFWORD count,
not a byte count. A fixture that assumed a fixed width would mis-place every
label and the resulting garbage would read as the emulator being incomplete.
So there is an explicit tooth asserting the emitter really returns 2, 4 and 6.
BIG-ENDIAN. Every field below is written most-significant byte first. Getting
this wrong is the silent-fixture defect: the decoder reads garbage, reports
UNSUPPORTED, and the FIXTURE's bug wears the emulator's name.
THE TWO NEGATIVE CONTROLS THAT ARE NOT DECORATION: nx_emu_s390x used to set
its "handled" flag for a whole opcode family BEFORE looking at the extended
opcode, so an unimplemented member of that family executed as a silent
dependencies 3 imports · 0 importers
imports: nx_gate_verdict.nxnx_syscalls.nxnx_emu_s390x.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 64 | const SX_GUEST_BYTES: i64 = 1048576 // 1 MiB guest image |
| 65 | const SX_ENTRY: i64 = 0 // KAT code is loaded at guest vaddr 0 |
| 66 | const SX_SP: i64 = 983040 // 960 KiB: above the code, inside the image |
| 67 | const SX_SCRATCH: i64 = 512 // load/store KATs use this guest address |
| 68 | const SX_MODE_FILE: i64 = 420 // 0644. 420 and 0x1a4 are the SAME constant |
| 75 | const SX_UNSUPPORTED: i64 = -1 |
| 76 | const SX_RANOFF: i64 = -2 |
| 77 | const SX_FAULT: i64 = -3 |
| 80 | const SX_O_PASS: i64 = 0 |
| 81 | const SX_O_WRONG: i64 = 1 |
| 82 | const SX_O_UNSUP: i64 = 2 |
| 83 | const SX_O_FAULT: i64 = 3 |
| 84 | const SX_O_RANOFF: i64 = 4 |
| 87 | const SX_OP_BCR: i64 = 0x07 |
| 88 | const SX_OP_SVC: i64 = 0x0A |
| 89 | const SX_OP_RI: i64 = 0xA7 |
| 90 | const SX_OP_RRE: i64 = 0xB9 |
| 91 | const SX_OP_LA: i64 = 0x41 |
| 92 | const SX_OP_RXY: i64 = 0xE3 |
| 93 | const SX_OP_RSY: i64 = 0xEB |
| 94 | const SX_OP_RIL: i64 = 0xC0 |
| 99 | const SX_RI_BRC: i64 = 0x4 |
| 100 | const SX_RI_BRAS: i64 = 0x5 |
| 101 | const SX_RI_BRCT: i64 = 0x6 |
| 102 | const SX_RI_BRCTG: i64 = 0x7 |
| 103 | const SX_RI_LHI: i64 = 0x8 |
| 104 | const SX_RI_LGHI: i64 = 0x9 |
| 105 | const SX_RI_AHI: i64 = 0xA |
| 106 | const SX_RI_AGHI: i64 = 0xB |
| 107 | const SX_RI_MGHI: i64 = 0xD |
| 108 | const SX_RI_CHI: i64 = 0xE |
| 109 | const SX_RI_CGHI: i64 = 0xF |
| 112 | const SX_RRE_LGR: i64 = 0x04 |
| 113 | const SX_RRE_AGR: i64 = 0x08 |
| 114 | const SX_RRE_SGR: i64 = 0x09 |
| 115 | const SX_RRE_MSGR: i64 = 0x0C |
| 116 | const SX_RRE_CGR: i64 = 0x20 |
| 117 | const SX_RRE_CLGR: i64 = 0x21 |
| 118 | const SX_RRE_NGR: i64 = 0x80 |
| 119 | const SX_RRE_OGR: i64 = 0x81 |
| 120 | const SX_RRE_XGR: i64 = 0x82 |
| 123 | const SX_RRE_LRVGR: i64 = 0x0F |
| 126 | const SX_RXY_LG: i64 = 0x04 |
| 127 | const SX_RXY_STG: i64 = 0x24 |
| 128 | const SX_RSY_SRAG: i64 = 0x0A |
| 129 | const SX_RSY_SRLG: i64 = 0x0C |
| 130 | const SX_RSY_SLLG: i64 = 0x0D |
| 133 | const SX_RIL_BRCL: i64 = 0x4 |
| 134 | const SX_RIL_BRASL: i64 = 0x5 |
| 137 | const SX_M_ALWAYS: i64 = 15 |
| 138 | const SX_M_EQ: i64 = 8 |
| 139 | const SX_M_NE: i64 = 7 |
| 140 | const SX_M_LOW: i64 = 4 |
| 141 | const SX_M_HIGH: i64 = 2 |
| 144 | const SX_SVC_EXIT: i64 = 1 |
| 145 | const SX_SVC_UNKNOWN: i64 = 99 // deliberately not implemented |
| 148 | const SX_R0: i64 = 0 |
| 149 | const SX_R2: i64 = 2 // the exit-status register on Linux s390x |
| 150 | const SX_R3: i64 = 3 |
| 151 | const SX_R4: i64 = 4 |
| 152 | const SX_R5: i64 = 5 |
| 153 | const SX_R14: i64 = 14 // the architected return-address register |
| 157 | const SX_LEN_RR: i64 = 2 |
| 158 | const SX_LEN_RI: i64 = 4 |
| 159 | const SX_LEN_RIL: i64 = 6 |
| 164 | const SX_NB_BYTES: i64 = 2048 |
| 165 | const SX_NB_OFF: i64 = 0 |
| 166 | const SX_NB_PTR: i64 = 1 |
| 167 | const SX_NB_ROW_MAX: i64 = 256 |
| 168 | const SX_BOX_BYTES: i64 = 32 |
| 170 | const SX_NL: i64 = 10 |
| 171 | const SX_SPACE: i64 = 32 |
| 172 | const SX_DIG_LO: i64 = 48 |
| 173 | const SX_DIG_HI: i64 = 57 |
| 174 | const SX_UNSEEDED: i64 = -1 |
| 176 | const SX_RATCHET: *u8 = "knowledge/status/isa_s390x.ratchet" |
functions
| 180 | func sx_nl() -> i64 |
| 187 | func sx_guest() -> *u8 { return sys_mmap(SX_GUEST_BYTES) } called by 19: sx_k_imm_arithsx_k_aghi_opcodesx_k_subsx_k_mulsx_k_logicsx_k_branch_loop+13 calls 1: sys_mmap |
| 196 | func sx_rr(c: *u8, off: i64, op: i64, r1: i64, r2: i64) -> i64 |
| 203 | func sx_svc(c: *u8, off: i64, imm: i64) -> i64 |
| 210 | func sx_ri(c: *u8, off: i64, r1: i64, op2: i64, i2: i64) -> i64 |
| 219 | func sx_rre(c: *u8, off: i64, op2: i64, r1: i64, r2: i64) -> i64 |
| 228 | func sx_rx(c: *u8, off: i64, r1: i64, x2: i64, b2: i64, d2: i64) -> i64 called by 1: sx_k_base_zero |
| 237 | func sx_rxy(c: *u8, off: i64, r1: i64, x2: i64, b2: i64, d2: i64, op2: i64) -> i64 called by 1: sx_k_load_store |
| 248 | func sx_rsy(c: *u8, off: i64, r1: i64, r3: i64, b2: i64, d2: i64, op2: i64) -> i64 |
| 260 | func sx_ril(c: *u8, off: i64, r1: i64, op2: i64, i2: i64) -> i64 |
| 270 | func sx_run(m: *u8) -> i64 { return emu_s390x_run_mem(m, SX_GUEST_BYTES, SX_ENTRY, SX_SP) } called by 18: sx_k_imm_arithsx_k_aghi_opcodesx_k_subsx_k_mulsx_k_logicsx_k_branch_loop+12 calls 1: emu_s390x_run_mem |
| 274 | func sx_classify(got: i64, want: i64) -> i64 |
| 282 | func sx_outcome_name(o: i64) -> *u8 |
| 292 | func sx_report(kat: *u8, got: i64, want: i64, bx: *i64) -> i64 |
| 331 | func sx_k_imm_arith() -> i64 |
| 344 | func sx_k_aghi_opcode() -> i64 |
| 355 | func sx_k_sub() -> i64 |
| 365 | func sx_k_mul() -> i64 |
| 377 | func sx_k_logic() -> i64 |
| 396 | func sx_k_branch_loop() -> i64 |
| 415 | func sx_k_brctg_loop() -> i64 |
| 431 | func sx_k_load_store() -> i64 |
| 446 | func sx_k_base_zero() -> i64 |
| 460 | func sx_k_shift_logical() -> i64 |
| 469 | func sx_k_shift_arith() -> i64 |
| 491 | func sx_k_ahi_is_32bit() -> i64 |
| 510 | func sx_k_brcl_cond() -> i64 |
| 528 | func sx_k_call_return() -> i64 |
| 545 | func sx_k_bcr_zero_is_nop() -> i64 |
| 564 | func sx_k_clgr_unsigned() -> i64 |
| 587 | func sx_nc_unimplemented_subopcode() -> i64 |
| 598 | func sx_nc_unknown_svc() -> i64 |
| 614 | func sx_match_at(buf: *u8, n: i64, p: i64, s: *u8) -> i64 called by 1: sx_ratchet_read |
| 628 | func sx_digits_at(buf: *u8, n: i64, p0: i64) -> i64 called by 1: sx_ratchet_read |
| 652 | func sx_ratchet_read() -> i64 |
| 684 | func sx_ratchet_write(passed: i64) -> i64 |
| 701 | func main(argc: i64, argv: *i64) -> i64 |