code wiki / (root) / nx_emu_loongarch64.nx

nx_emu_loongarch64.nx

buildroot/runtime/nx_emu_loongarch64.nx

22674 B532 linesdepth 3pulls 3 transitivereach 2 importersview sourcekind librarytopic emu
docsdependenciesstructsconstsfunctions

about

nx_emu_loongarch64.nx -- sovereign LoongArch64 (LA64) interpreter (NX-EMU). Flat 32 GPRs (r0==zero), little-endian, NO register windows, NO delay slots. Decode/execute pure NishiLang per the LoongArch Reference Manual Volume 1 (v1.10) -- NO qemu (qemu-loongarch64 stays a differential BENCHMARK that must agree, never a dependency). How Nishi CARRIES loongarch64 execution (operator: nishi carries; externals = bench). --------------------------------------------------------------------- 2026-09-03, ISA LANE. WHAT THIS GENERATION ADDS AND WHY. The previous generation decoded ELEVEN 3R ops, THREE 2RI12 ops, jirl, bl and syscall -- and NOT ONE CONDITIONAL BRANCH. An interpreter with no conditional branch cannot run a loop, cannot run an if, and cannot run any program a compiler would emit; it could only ever execute straight-line arithmetic. That is the same gap the mips64 sibling carried until 2026-09-03, named by nx_isa_conform_gate and closed the same day, and it is the highest-value thing missing here. ADDED (each encoding taken from the manual instruction tables, not from any emulator behaviour): branches beq bne blt bge bltu bgeu (2RI16) | beqz bnez (1RI21) | b (I26) compare slt sltu slti sltui logic nor andn orn andi ori xori maskeqz masknez shift-imm slli.w slli.d srli.w srli.d srai.w srai.d 32-bit add.w sub.w mul.w sll.w srl.w sra.w addi.w const lu12i.w lu32i.d pcaddi pcaddu12i pcalau12i memory ld.b ld.h ld.w st.b st.h st.w ld.bu ld.hu ld.wu FIXED, a real defect the ruler caught: SRL.D was implemented with the NishiLang >> operator which is ARITHMETIC, so srl.d and sra.d were the SAME instruction. It is invisible on every non-negative value -- the exact shape of a test that cannot fail -- and shows up only on a negative operand shifted far enough that the sign copies reach the low byte. Logical right shift now goes through la_srl, mirroring the rv64 sibling emu_srl, which carries the same comment for the same reason. ALSO FIXED: (1) memory accesses are BOUNDS-CHECKED against mem_size instead of trusting the guest -- an out-of-range guest address used

dependencies 1 imports · 2 importers

nx_syscalls_x86_64.nx nx_emu_loongarch64.nx nx_emu_loongarch64_main.nx nx_isa_loongarch64_gate.nx

imports: nx_syscalls_x86_64.nx

imported by: nx_emu_loongarch64_main.nxnx_isa_loongarch64_gate.nx

structs

none

consts

67const LA_MAGIC_200000000: i64 = 200000000
69const LA_GUEST_SIZE: i64 = 16777216
70const LA_SYS_READ: i64 = 63
71const LA_SYS_WRITE: i64 = 64
72const LA_SYS_EXIT: i64 = 93
73const LA_SYS_EXITG: i64 = 94
77const LAE_UNSUPPORTED: i64 = -1
78const LAE_RANOFF: i64 = -2
79const LAE_FAULT: i64 = -3
81const LA_ALL_ONES: i64 = -1
82const LA_NEG_ONE: i64 = -1
85const LA_POW12: i64 = 4096
86const LA_POW16: i64 = 65536
87const LA_POW20: i64 = 1048576
88const LA_POW21: i64 = 2097152
89const LA_POW26: i64 = 67108864
90const LA_POW32: i64 = 4294967296
93const LA_OP_ADD_W: i64 = 0x00100000
94const LA_OP_ADD_D: i64 = 0x00108000
95const LA_OP_SUB_W: i64 = 0x00110000
96const LA_OP_SUB_D: i64 = 0x00118000
97const LA_OP_SLT: i64 = 0x00120000
98const LA_OP_SLTU: i64 = 0x00128000
99const LA_OP_MASKEQZ: i64 = 0x00130000
100const LA_OP_MASKNEZ: i64 = 0x00138000
101const LA_OP_NOR: i64 = 0x00140000
102const LA_OP_AND: i64 = 0x00148000
103const LA_OP_OR: i64 = 0x00150000
104const LA_OP_XOR: i64 = 0x00158000
105const LA_OP_ORN: i64 = 0x00160000
106const LA_OP_ANDN: i64 = 0x00168000
107const LA_OP_SLL_W: i64 = 0x00170000
108const LA_OP_SRL_W: i64 = 0x00178000
109const LA_OP_SRA_W: i64 = 0x00180000
110const LA_OP_SLL_D: i64 = 0x00188000
111const LA_OP_SRL_D: i64 = 0x00190000
112const LA_OP_SRA_D: i64 = 0x00198000
113const LA_OP_MUL_W: i64 = 0x001c0000
114const LA_OP_MUL_D: i64 = 0x001d8000
115const LA_OP_DIV_D: i64 = 0x00220000
116const LA_OP_MOD_D: i64 = 0x00228000
117const LA_INSN_SYSCALL: i64 = 0x002B0000
124const LA_OP_SLLI_W: i64 = 0x00408000
125const LA_OP_SRLI_W: i64 = 0x00448000
126const LA_OP_SRAI_W: i64 = 0x00488000
127const LA_OP_SLLI_D: i64 = 0x00410000
128const LA_OP_SRLI_D: i64 = 0x00450000
129const LA_OP_SRAI_D: i64 = 0x00490000
135const LA_OP_SLTI: i64 = 0x02000000
136const LA_OP_SLTUI: i64 = 0x02400000
137const LA_OP_ADDI_W: i64 = 0x02800000
138const LA_OP_ADDI_D: i64 = 0x02c00000
139const LA_OP_ANDI: i64 = 0x03400000
140const LA_OP_ORI: i64 = 0x03800000
141const LA_OP_XORI: i64 = 0x03c00000
142const LA_OP_LD_B: i64 = 0x28000000
143const LA_OP_LD_H: i64 = 0x28400000
144const LA_OP_LD_W: i64 = 0x28800000
145const LA_OP_LD_D: i64 = 0x28c00000
146const LA_OP_ST_B: i64 = 0x29000000
147const LA_OP_ST_H: i64 = 0x29400000
148const LA_OP_ST_W: i64 = 0x29800000
149const LA_OP_ST_D: i64 = 0x29c00000
150const LA_OP_LD_BU: i64 = 0x2a000000
151const LA_OP_LD_HU: i64 = 0x2a400000
152const LA_OP_LD_WU: i64 = 0x2a800000
155const LA_OP_LU12I_W: i64 = 0x14000000
156const LA_OP_LU32I_D: i64 = 0x16000000
157const LA_OP_PCADDI: i64 = 0x18000000
158const LA_OP_PCALAU12I: i64 = 0x1a000000
159const LA_OP_PCADDU12I: i64 = 0x1c000000
162const LA_OP_BEQZ: i64 = 0x40000000
163const LA_OP_BNEZ: i64 = 0x44000000
164const LA_OP_JIRL: i64 = 0x4c000000
165const LA_OP_B: i64 = 0x50000000
166const LA_OP_BL: i64 = 0x54000000
167const LA_OP_BEQ: i64 = 0x58000000
168const LA_OP_BNE: i64 = 0x5c000000
169const LA_OP_BLT: i64 = 0x60000000
170const LA_OP_BGE: i64 = 0x64000000
171const LA_OP_BLTU: i64 = 0x68000000
172const LA_OP_BGEU: i64 = 0x6c000000
175const LA_MASK_3R: i64 = 0xFFFF8000
176const LA_MASK_3RI6: i64 = 0xFFFF0000
177const LA_MASK_2RI12: i64 = 0xFFC00000
178const LA_MASK_1RI20: i64 = 0xFE000000
179const LA_MASK_OP6: i64 = 0xFC000000
181const LA_REG_COUNT: i64 = 32
182const LA_REG_BYTES: i64 = 256 // 32 registers of 8 bytes
183const LA_REG_SP: i64 = 3 // sp is r3
184const LA_REG_RA: i64 = 1 // ra is r1
185const LA_REG_A0: i64 = 4 // a0 is r4
186const LA_REG_A1: i64 = 5
187const LA_REG_A2: i64 = 6
188const LA_REG_A7: i64 = 11 // a7 is r11, it carries the syscall number

functions

192func la_g_ld(mem: *u8, va: i64, width: i64) -> i64 { // little-endian, zero-fill
202func la_g_ld_s(mem: *u8, va: i64, width: i64) -> i64 { // little-endian, sign-extended
called by 1: emu_loongarch64_run_mem calls 1: la_g_ld
211func la_g_st(mem: *u8, va: i64, width: i64, val: i64) -> i64
222func la_ea_ok(ea: i64, width: i64, mem_size: i64) -> i64
228func la_rd(r: *i64, n: i64) -> i64 { if n == 0 { return 0 } return r[n] }
229func la_wr(r: *i64, n: i64, v: i64) -> i64 { if n != 0 { r[n] = v } return 0 }
233func la_srl(v: i64, n: i64) -> i64
240func la_ltu(a: i64, b: i64) -> i64
246func la_sext32(v: i64) -> i64
251func la_sext12(v: i64) -> i64 { if (v & 0x800) != 0 { return v - LA_POW12 } return v }
252func la_sext16(v: i64) -> i64 { if (v & 0x8000) != 0 { return v - LA_POW16 } return v }
253func la_sext20(v: i64) -> i64 { if (v & 0x80000) != 0 { return v - LA_POW20 } return v }
254func la_sext21(v: i64) -> i64 { if (v & 0x100000) != 0 { return v - LA_POW21 } return v }
255func la_sext26(v: i64) -> i64 { if (v & 0x2000000) != 0 { return v - LA_POW26 } return v }
259func emu_loongarch64_run_mem(mem: *u8, mem_size: i64, entry: i64, sp0: i64) -> i64
509func emu_loongarch64_load_elf(buf: *u8, len: i64) -> i64
called by 1: main calls 2: la_g_ldemu_loongarch64_run_mem