nx_emu_s390x.nx
buildroot/runtime/nx_emu_s390x.nx
about
nx_emu_s390x.nx -- sovereign IBM Z (s390x) interpreter (NX-EMU).
64-bit big-endian, 16 GPRs, VARIABLE-LENGTH instructions (length from the top 2
bits of byte0: 00->2, 01/10->4, 11->6). z/Architecture is the only variable
length ISA on the estate board, so the fetch width is decoded, never assumed.
Linux s390x: svc <imm> = syscall number, args r2.., exit = 1 (code in r2).
NO qemu. license_tier: ORIGINAL
DECODED TODAY, by family:
RR 07 BCR (all 16 masks, and R2=0 is the architected no-operation)
RR 0A SVC (1 = exit; every other number is an honest UNSUPPORTED)
RI A7 x4 BRC x5 BRAS x6 BRCT x7 BRCTG x8 LHI x9 LGHI
xA AHI xB AGHI xD MGHI xE CHI xF CGHI
RRE B9 04 LGR 08 AGR 09 SGR 0C MSGR 20 CGR 21 CLGR
80 NGR 81 OGR 82 XGR
RX 41 LA
RXY E3 04 LG 08 AG 09 SG 24 STG
RSY EB 04 LMG 0A SRAG 0C SRLG 0D SLLG 24 STMG
RIL C0 x0 LARL x1 LGFI x4 BRCL x5 BRASL
SEVEN DEFECTS THIS GENERATION FIXES, each found by reading the z/Architecture
Principles of Operation extended-opcode tables rather than the source:
1. AGHI WAS DECODED AT THE WRONG EXTENDED OPCODE. The RI table is
A7x8 LHI, A7x9 LGHI, A7xA AHI, A7xB AGHI. The previous generation
implemented A7xA as a 64-bit add labelled aghi and had NO A7xB case, so
a real AGHI executed as a SILENT NO-OP and a real AHI executed with the
wrong width. Both are wrong-answer generators that still run to exit.
2. AN UNKNOWN EXTENDED OPCODE SILENTLY DID NOTHING. handled was set for the
whole A7 / B9 / E3 / EB / C0 family before the sub-opcode was examined, so
every unimplemented member of those families no-opped and the program ran
on with wrong data. That converts UNSUPPORTED into WRONG-ANSWER, which is
the one collapse an ISA ruler exists to refuse: a missing instruction and
a miscomputed one need OPPOSITE fixes. Each family now carries a subok flag (one per family).
3. THERE WAS NO CONDITION CODE AND NO CONDITIONAL BRANCH AT ALL, so no loop
and no if could run. BCR honoured only mask 15. Added: a cc register set
by the arithmetic, compare and logic classes, plus BRC, BRCL, BRCT, BRCTG
and the full 16-way BCR mask.
4. BASE REGISTER 0 WAS TREATED AS A REAL REGISTER. PoP: a zero in the B or X
field means THE ABSENCE OF A BASE, not the contents of general register 0.
The old code honoured that for X and not for B, so any program that keeps
a live value in r0 addressed the wrong storage.
dependencies 1 imports · 1 importers
imports: nx_syscalls_x86_64.nx
imported by: nx_isa_s390x_gate.nx
structs
| none |
consts
| 62 | const SZ_GUEST: i64 = 16777216 |
| 63 | const SZ_SYS_EXIT: i64 = 1 |
| 68 | const SZ_UNSUPPORTED: i64 = -1 |
| 69 | const SZ_RANOFF: i64 = -2 |
| 70 | const SZ_FAULT: i64 = -3 |
| 72 | const SZ_STEP_BUDGET: i64 = 5000000 |
| 73 | const SZ_EXIT_MASK: i64 = 255 |
| 74 | const SZ_NREG: i64 = 16 |
| 75 | const SZ_REGBYTES: i64 = 8 |
| 76 | const SZ_MAXILEN: i64 = 6 |
| 77 | const SZ_SHIFT_MASK: i64 = 63 |
| 78 | const SZ_WORD: i64 = 8 |
| 83 | const SZ_LO32: i64 = 4294967295 |
| 84 | const SZ_SIGN32: i64 = 2147483648 |
| 85 | const SZ_2P32: i64 = 4294967296 |
| 88 | const SZ_D20_SIGN: i64 = 524288 |
| 89 | const SZ_D20_MOD: i64 = 1048576 |
| 93 | const SZ_CC_EQ: i64 = 0 |
| 94 | const SZ_CC_LO: i64 = 1 |
| 95 | const SZ_CC_HI: i64 = 2 |
| 96 | const SZ_CC_MASK_TOP: i64 = 8 |
functions
| 98 | func sz_ld(mem: *u8, va: i64, width: i64) -> i64 { var v: i64 = 0; var i: i64 = 0; while i < width { v = (v << 8) | (mem[va + i] & 0xff); i = i + 1 } return v } // big-endian called by 1: emu_s390x_run_mem |
| 99 | func sz_st(mem: *u8, va: i64, width: i64, val: i64) -> i64 { var i: i64 = 0; while i < width { mem[va + (width - 1 - i)] = (val >> (i * 8)) & 0xff; i = i + 1 } return 0 } called by 1: emu_s390x_run_mem |
| 100 | func sz_sx(v: i64, bits: i64) -> i64 { let m: i64 = 1 << (bits - 1); if (v & m) != 0 { return v - (1 << bits) } return v } called by 1: emu_s390x_run_mem |
| 104 | func sz_put32(old: i64, lo: i64) -> i64 { return (old - (old & SZ_LO32)) + (lo & SZ_LO32) } called by 1: emu_s390x_run_mem |
| 107 | func sz_s32(v: i64) -> i64 called by 1: emu_s390x_run_mem |
| 115 | func sz_ltu(a: i64, b: i64) -> i64 called by 1: emu_s390x_run_mem |
| 122 | func sz_srl(v: i64, n: i64) -> i64 called by 1: emu_s390x_run_mem |
| 129 | func sz_cc_of(v: i64) -> i64 called by 1: emu_s390x_run_mem |
| 136 | func sz_cc_cmp(a: i64, b: i64) -> i64 called by 1: emu_s390x_run_mem |
| 145 | func sz_cc_logic(v: i64) -> i64 called by 1: emu_s390x_run_mem |
| 151 | func sz_bad(ea: i64, width: i64, mem_size: i64) -> i64 called by 1: emu_s390x_run_mem |
| 157 | func emu_s390x_run_mem(mem: *u8, mem_size: i64, entry: i64, sp0: i64) -> i64 |
| 398 | func emu_s390x_run(code: *u8, code_len: i64) -> i64 calls 1: emu_s390x_run_mem |