code wiki / (root) / nx_emu_loongarch64.nx

nx_emu_loongarch64.nx source

↩ module page · 532 lines · 22674 B

1// nx_emu_loongarch64.nx -- sovereign LoongArch64 (LA64) interpreter (NX-EMU). 2// Flat 32 GPRs (r0==zero), little-endian, NO register windows, NO delay 3// slots. Decode/execute pure NishiLang per the LoongArch Reference 4// Manual Volume 1 (v1.10) -- NO qemu (qemu-loongarch64 stays a 5// differential BENCHMARK that must agree, never a dependency). How 6// Nishi CARRIES loongarch64 execution (operator: nishi carries; 7// externals = bench). 8// 9// --------------------------------------------------------------------- 10// 2026-09-03, ISA LANE. WHAT THIS GENERATION ADDS AND WHY. 11// 12// The previous generation decoded ELEVEN 3R ops, THREE 2RI12 ops, jirl, 13// bl and syscall -- and NOT ONE CONDITIONAL BRANCH. An interpreter with 14// no conditional branch cannot run a loop, cannot run an if, and cannot 15// run any program a compiler would emit; it could only ever execute 16// straight-line arithmetic. That is the same gap the mips64 sibling 17// carried until 2026-09-03, named by nx_isa_conform_gate and closed the 18// same day, and it is the highest-value thing missing here. 19// 20// ADDED (each encoding taken from the manual instruction tables, not 21// from any emulator behaviour): 22// branches beq bne blt bge bltu bgeu (2RI16) | beqz bnez (1RI21) | b (I26) 23// compare slt sltu slti sltui 24// logic nor andn orn andi ori xori maskeqz masknez 25// shift-imm slli.w slli.d srli.w srli.d srai.w srai.d 26// 32-bit add.w sub.w mul.w sll.w srl.w sra.w addi.w 27// const lu12i.w lu32i.d pcaddi pcaddu12i pcalau12i 28// memory ld.b ld.h ld.w st.b st.h st.w ld.bu ld.hu ld.wu 29// 30// FIXED, a real defect the ruler caught: SRL.D was implemented with 31// the NishiLang >> operator which is ARITHMETIC, so srl.d and sra.d 32// were the SAME instruction. It is invisible on every non-negative 33// value -- the exact shape of a test that cannot fail -- and shows up 34// only on a negative operand shifted far enough that the sign copies 35// reach the low byte. Logical right shift now goes through la_srl, 36// mirroring the rv64 sibling emu_srl, which carries the same comment 37// for the same reason. 38// 39// ALSO FIXED: (1) memory accesses are BOUNDS-CHECKED against mem_size 40// instead of trusting the guest -- an out-of-range guest address used 41// to read or write OUTSIDE the interpreter own arena, which is a host 42// memory-safety hole reachable from guest bytes. (2) a third 43// non-completion state, LAE_RANOFF, so "the step budget ran out / no 44// exit syscall" is distinguishable from "bad pc" -- collapsing them 45// made a structural non-completion read as a fault. (3) DIV.D of the 46// most-negative value by -1 is defined rather than handed to the host 47// divide instruction, which would fault the interpreter itself. 48// 49// Encodings (LoongArch Reference Manual Vol 1, instruction tables; 50// cross-checked against objdump of the nxc2 la64 backend output): 51// 3R opcode in bits 31..15 (w & 0xFFFF8000), rk[14:10] rj[9:5] rd[4:0] 52// 3RI6 shift-immediate .d forms, opcode in bits 31..16, ui6[15:10] 53// 2RI12 opcode in bits 31..22 (w & 0xFFC00000), si12/ui12[21:10] 54// 1RI20 opcode in bits 31..25 (w & 0xFE000000), si20[24:5] 55// 2RI16 opcode in bits 31..26 (w & 0xFC000000), offs16[25:10] 56// 1RI21 opcode in bits 31..26, offs[15:0] at [25:10], offs[20:16] at [4:0] 57// I26 opcode in bits 31..26, offs[15:0] at [25:10], offs[25:16] at [9:0] 58// syscall (w & 0xFFFF8000) == 0x002B0000 (a7=r11 holds the number, 59// a0=r4.. hold the args; Linux exit = 93) 60// Every branch target is PC + SignExtend(offs << 2): LoongArch has no 61// delay slot, so the offset is measured from the branch itself. 62// 63// license_tier: ORIGINAL 64 65import "nx_syscalls_x86_64.nx" 66 67const LA_MAGIC_200000000: i64 = 200000000 68 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 74 75// Three NAMED non-completion states. A single negative word for "it 76// did not finish" cannot say which of two opposite fixes is owed. 77const LAE_UNSUPPORTED: i64 = -1 78const LAE_RANOFF: i64 = -2 79const LAE_FAULT: i64 = -3 80 81const LA_ALL_ONES: i64 = -1 82const LA_NEG_ONE: i64 = -1 83 84// Sign-extension moduli, named for the field width they close over. 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 91 92// ---- 3R opcodes (bits 31..15) ---- 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 118 119// ---- shift-immediate opcodes ---- 120// The .w forms carry a 5-bit ui5 in bits 14..10, so their opcode field 121// is the 17-bit 3R field; the .d forms carry a 6-bit ui6 in bits 15..10, 122// so their opcode field is one bit SHORTER. Two masks, not one -- 123// masking a .d form with the 3R mask splits it across two values. 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 130 131// ---- 2RI12 opcodes (bits 31..22) ---- 132// SLTI/SLTUI/ADDI/LD/ST take a SIGN-extended si12; ANDI/ORI/XORI take a 133// ZERO-extended ui12. Using one extension for both is the classic 134// LoongArch decoder bug and it is silent for small positive immediates. 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 153 154// ---- 1RI20 opcodes (bits 31..25) ---- 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 160 161// ---- branch / jump opcodes (bits 31..26) ---- 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 173 174// ---- decode masks ---- 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 180 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 189 190// ===== primitives ================================================== 191 192func la_g_ld(mem: *u8, va: i64, width: i64) -> i64 { // little-endian, zero-fill 193 var v: i64 = 0 194 var i: i64 = 0 195 while i < width { 196 v = v | ((mem[va + i] & 0xff) << (i * 8)) 197 i = i + 1 198 } 199 return v 200} 201 202func la_g_ld_s(mem: *u8, va: i64, width: i64) -> i64 { // little-endian, sign-extended 203 var v: i64 = la_g_ld(mem, va, width) 204 if width < 8 { 205 let sign: i64 = 1 << (width * 8 - 1) 206 if (v & sign) != 0 { v = v - (1 << (width * 8)) } 207 } 208 return v 209} 210 211func la_g_st(mem: *u8, va: i64, width: i64, val: i64) -> i64 { 212 var i: i64 = 0 213 while i < width { 214 mem[va + i] = (val >> (i * 8)) & 0xff 215 i = i + 1 216 } 217 return 0 218} 219 220// A guest address is UNTRUSTED input. Without this the guest could 221// make the interpreter read or write outside its own arena. 222func la_ea_ok(ea: i64, width: i64, mem_size: i64) -> i64 { 223 if ea < 0 { return 0 } 224 if (ea + width) > mem_size { return 0 } 225 return 1 226} 227 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 } 230 231// The NishiLang >> operator is ARITHMETIC. Logical right shift has to 232// mask the sign copies away, or srl.d silently becomes sra.d. 233func la_srl(v: i64, n: i64) -> i64 { 234 if n == 0 { return v } 235 let mask: i64 = (1 << (64 - n)) - 1 236 return (v >> n) & mask 237} 238 239// unsigned a < b (flip the sign bit, then compare signed) 240func la_ltu(a: i64, b: i64) -> i64 { 241 let m: i64 = 1 << 63 242 if (a ^ m) < (b ^ m) { return 1 } 243 return 0 244} 245 246func la_sext32(v: i64) -> i64 { 247 let lo: i64 = v & 0xffffffff 248 if (lo & 0x80000000) != 0 { return lo - LA_POW32 } 249 return lo 250} 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 } 256 257// ===== the interpreter ============================================= 258 259func emu_loongarch64_run_mem(mem: *u8, mem_size: i64, entry: i64, sp0: i64) -> i64 { 260 let r: *i64 = sys_mmap(LA_REG_BYTES) as *i64 261 var i: i64 = 0 262 while i < LA_REG_COUNT { r[i] = 0; i = i + 1 } 263 r[LA_REG_SP] = sp0 264 var pc: i64 = entry 265 var steps: i64 = 0 266 var halted: i64 = 0 267 // RANOFF, not FAULT: falling out of the loop with no exit syscall is 268 // a structural non-completion, not a bad address. 269 var result: i64 = LAE_RANOFF 270 let la_min: i64 = 1 << 63 271 272 while halted == 0 && steps < LA_MAGIC_200000000 { 273 if pc < 0 { halted = 1; result = LAE_FAULT } 274 if pc + 4 > mem_size { halted = 1; result = LAE_FAULT } 275 if halted == 0 { 276 let w: i64 = la_g_ld(mem, pc, 4) 277 let rd: i64 = w & 0x1F 278 let rj: i64 = (w >> 5) & 0x1F 279 let rk: i64 = (w >> 10) & 0x1F 280 let va: i64 = la_rd(r, rj) 281 let vb: i64 = la_rd(r, rk) 282 let vd: i64 = la_rd(r, rd) 283 var next: i64 = pc + 4 284 var handled: i64 = 0 285 286 // ---- 3R ------------------------------------------------ 287 let o3: i64 = w & LA_MASK_3R 288 if o3 == LA_OP_ADD_W { handled = 1; la_wr(r, rd, la_sext32(va + vb)) } 289 if o3 == LA_OP_ADD_D { handled = 1; la_wr(r, rd, va + vb) } 290 if o3 == LA_OP_SUB_W { handled = 1; la_wr(r, rd, la_sext32(va - vb)) } 291 if o3 == LA_OP_SUB_D { handled = 1; la_wr(r, rd, va - vb) } 292 if o3 == LA_OP_SLT { 293 handled = 1 294 var s_lt: i64 = 0 295 if va < vb { s_lt = 1 } 296 la_wr(r, rd, s_lt) 297 } 298 if o3 == LA_OP_SLTU { handled = 1; la_wr(r, rd, la_ltu(va, vb)) } 299 if o3 == LA_OP_MASKEQZ { 300 handled = 1 301 var m_eq: i64 = va 302 if vb == 0 { m_eq = 0 } 303 la_wr(r, rd, m_eq) 304 } 305 if o3 == LA_OP_MASKNEZ { 306 handled = 1 307 var m_ne: i64 = 0 308 if vb == 0 { m_ne = va } 309 la_wr(r, rd, m_ne) 310 } 311 if o3 == LA_OP_NOR { handled = 1; la_wr(r, rd, LA_ALL_ONES ^ (va | vb)) } 312 if o3 == LA_OP_AND { handled = 1; la_wr(r, rd, va & vb) } 313 if o3 == LA_OP_OR { handled = 1; la_wr(r, rd, va | vb) } 314 if o3 == LA_OP_XOR { handled = 1; la_wr(r, rd, va ^ vb) } 315 if o3 == LA_OP_ORN { handled = 1; la_wr(r, rd, va | (LA_ALL_ONES ^ vb)) } 316 if o3 == LA_OP_ANDN { handled = 1; la_wr(r, rd, va & (LA_ALL_ONES ^ vb)) } 317 if o3 == LA_OP_SLL_W { handled = 1; la_wr(r, rd, la_sext32((va & 0xffffffff) << (vb & 0x1f))) } 318 if o3 == LA_OP_SRL_W { handled = 1; la_wr(r, rd, la_sext32(la_srl(va & 0xffffffff, vb & 0x1f))) } 319 if o3 == LA_OP_SRA_W { handled = 1; la_wr(r, rd, la_sext32(la_sext32(va) >> (vb & 0x1f))) } 320 if o3 == LA_OP_SLL_D { handled = 1; la_wr(r, rd, va << (vb & 0x3f)) } 321 if o3 == LA_OP_SRL_D { handled = 1; la_wr(r, rd, la_srl(va, vb & 0x3f)) } 322 if o3 == LA_OP_SRA_D { handled = 1; la_wr(r, rd, va >> (vb & 0x3f)) } 323 if o3 == LA_OP_MUL_W { handled = 1; la_wr(r, rd, la_sext32(va * vb)) } 324 if o3 == LA_OP_MUL_D { handled = 1; la_wr(r, rd, va * vb) } 325 if o3 == LA_OP_DIV_D { 326 handled = 1 327 if vb != 0 { 328 var d_q: i64 = 0 329 if va == la_min { 330 if vb == LA_NEG_ONE { d_q = la_min } else { d_q = va / vb } 331 } else { 332 d_q = va / vb 333 } 334 la_wr(r, rd, d_q) 335 } 336 } 337 if o3 == LA_OP_MOD_D { 338 handled = 1 339 if vb != 0 { 340 var d_m: i64 = 0 341 if va == la_min { 342 if vb == LA_NEG_ONE { d_m = 0 } else { d_m = va - (va / vb) * vb } 343 } else { 344 d_m = va - (va / vb) * vb 345 } 346 la_wr(r, rd, d_m) 347 } 348 } 349 350 // ---- shift immediate ------------------------------------ 351 let ui5: i64 = (w >> 10) & 0x1F 352 let ui6: i64 = (w >> 10) & 0x3F 353 let osd: i64 = w & LA_MASK_3RI6 354 if o3 == LA_OP_SLLI_W { handled = 1; la_wr(r, rd, la_sext32((va & 0xffffffff) << ui5)) } 355 if o3 == LA_OP_SRLI_W { handled = 1; la_wr(r, rd, la_sext32(la_srl(va & 0xffffffff, ui5))) } 356 if o3 == LA_OP_SRAI_W { handled = 1; la_wr(r, rd, la_sext32(la_sext32(va) >> ui5)) } 357 if osd == LA_OP_SLLI_D { handled = 1; la_wr(r, rd, va << ui6) } 358 if osd == LA_OP_SRLI_D { handled = 1; la_wr(r, rd, la_srl(va, ui6)) } 359 if osd == LA_OP_SRAI_D { handled = 1; la_wr(r, rd, va >> ui6) } 360 361 // ---- 2RI12 ---------------------------------------------- 362 let o2: i64 = w & LA_MASK_2RI12 363 let ui12: i64 = (w >> 10) & 0xFFF 364 let si12: i64 = la_sext12(ui12) 365 if o2 == LA_OP_ADDI_D { handled = 1; la_wr(r, rd, va + si12) } 366 if o2 == LA_OP_ADDI_W { handled = 1; la_wr(r, rd, la_sext32(va + si12)) } 367 if o2 == LA_OP_SLTI { 368 handled = 1 369 var i_lt: i64 = 0 370 if va < si12 { i_lt = 1 } 371 la_wr(r, rd, i_lt) 372 } 373 if o2 == LA_OP_SLTUI { handled = 1; la_wr(r, rd, la_ltu(va, si12)) } 374 if o2 == LA_OP_ANDI { handled = 1; la_wr(r, rd, va & ui12) } 375 if o2 == LA_OP_ORI { handled = 1; la_wr(r, rd, va | ui12) } 376 if o2 == LA_OP_XORI { handled = 1; la_wr(r, rd, va ^ ui12) } 377 378 // ---- 2RI12 memory --------------------------------------- 379 var mw: i64 = 0 // access width, 0 means not a memory op 380 var msigned: i64 = 0 381 var mstore: i64 = 0 382 if o2 == LA_OP_LD_B { mw = 1; msigned = 1 } 383 if o2 == LA_OP_LD_H { mw = 2; msigned = 1 } 384 if o2 == LA_OP_LD_W { mw = 4; msigned = 1 } 385 if o2 == LA_OP_LD_D { mw = 8 } 386 if o2 == LA_OP_LD_BU { mw = 1 } 387 if o2 == LA_OP_LD_HU { mw = 2 } 388 if o2 == LA_OP_LD_WU { mw = 4 } 389 if o2 == LA_OP_ST_B { mw = 1; mstore = 1 } 390 if o2 == LA_OP_ST_H { mw = 2; mstore = 1 } 391 if o2 == LA_OP_ST_W { mw = 4; mstore = 1 } 392 if o2 == LA_OP_ST_D { mw = 8; mstore = 1 } 393 if mw > 0 { 394 handled = 1 395 let ea: i64 = va + si12 396 if la_ea_ok(ea, mw, mem_size) == 0 { 397 result = LAE_FAULT 398 halted = 1 399 } else { 400 if mstore == 1 { 401 la_g_st(mem, ea, mw, vd) 402 } else { 403 if msigned == 1 { 404 la_wr(r, rd, la_g_ld_s(mem, ea, mw)) 405 } else { 406 la_wr(r, rd, la_g_ld(mem, ea, mw)) 407 } 408 } 409 } 410 } 411 412 // ---- 1RI20 constant / pc-relative ----------------------- 413 let o1: i64 = w & LA_MASK_1RI20 414 let si20: i64 = (w >> 5) & 0xFFFFF 415 if o1 == LA_OP_LU12I_W { handled = 1; la_wr(r, rd, la_sext32(si20 << 12)) } 416 if o1 == LA_OP_LU32I_D { handled = 1; la_wr(r, rd, (la_sext20(si20) << 32) | (vd & 0xffffffff)) } 417 if o1 == LA_OP_PCADDI { handled = 1; la_wr(r, rd, pc + (la_sext20(si20) << 2)) } 418 if o1 == LA_OP_PCADDU12I { handled = 1; la_wr(r, rd, pc + (la_sext20(si20) << 12)) } 419 if o1 == LA_OP_PCALAU12I { 420 handled = 1 421 let pa: i64 = pc + (la_sext20(si20) << 12) 422 la_wr(r, rd, pa - (pa & 0xFFF)) 423 } 424 425 // ---- branches and jumps --------------------------------- 426 // LoongArch has NO delay slot: the target is measured from 427 // the branch instruction itself, target = pc + sext(off<<2). 428 let op6: i64 = w & LA_MASK_OP6 429 let off16: i64 = la_sext16((w >> 10) & 0xFFFF) 430 431 if op6 == LA_OP_JIRL { 432 handled = 1 433 let jt: i64 = va + (off16 << 2) // read rj BEFORE writing rd 434 la_wr(r, rd, pc + 4) 435 next = jt 436 } 437 if op6 == LA_OP_BL { 438 handled = 1 439 let o26b: i64 = ((w & 0x3FF) << 16) | ((w >> 10) & 0xFFFF) 440 r[LA_REG_RA] = pc + 4 441 next = pc + (la_sext26(o26b) << 2) 442 } 443 if op6 == LA_OP_B { 444 handled = 1 445 let o26u: i64 = ((w & 0x3FF) << 16) | ((w >> 10) & 0xFFFF) 446 next = pc + (la_sext26(o26u) << 2) 447 } 448 449 var isb2: i64 = 0 450 var take2: i64 = 0 451 if op6 == LA_OP_BEQ { isb2 = 1; if va == vd { take2 = 1 } } 452 if op6 == LA_OP_BNE { isb2 = 1; if va != vd { take2 = 1 } } 453 if op6 == LA_OP_BLT { isb2 = 1; if va < vd { take2 = 1 } } 454 if op6 == LA_OP_BGE { isb2 = 1; if va >= vd { take2 = 1 } } 455 if op6 == LA_OP_BLTU { isb2 = 1; take2 = la_ltu(va, vd) } 456 if op6 == LA_OP_BGEU { 457 isb2 = 1 458 if la_ltu(va, vd) == 0 { take2 = 1 } 459 } 460 if isb2 == 1 { 461 handled = 1 462 if take2 == 1 { next = pc + (off16 << 2) } 463 } 464 465 var isb1: i64 = 0 466 var take1: i64 = 0 467 if op6 == LA_OP_BEQZ { isb1 = 1; if va == 0 { take1 = 1 } } 468 if op6 == LA_OP_BNEZ { isb1 = 1; if va != 0 { take1 = 1 } } 469 if isb1 == 1 { 470 handled = 1 471 if take1 == 1 { 472 let o21: i64 = ((w >> 10) & 0xFFFF) | ((w & 0x1F) << 16) 473 next = pc + (la_sext21(o21) << 2) 474 } 475 } 476 477 // ---- syscall (a7 = r11 holds the number) ----------------- 478 if o3 == LA_INSN_SYSCALL { 479 handled = 1 480 let nr: i64 = r[LA_REG_A7] 481 if nr == LA_SYS_EXIT { result = r[LA_REG_A0] & 0xff; halted = 1 } 482 if nr == LA_SYS_EXITG { result = r[LA_REG_A0] & 0xff; halted = 1 } 483 if nr == LA_SYS_WRITE { 484 if la_ea_ok(r[LA_REG_A1], r[LA_REG_A2], mem_size) == 1 { 485 r[LA_REG_A0] = sys_write(r[LA_REG_A0], ((mem as i64) + r[LA_REG_A1]) as *u8, r[LA_REG_A2]) 486 } else { 487 result = LAE_FAULT 488 halted = 1 489 } 490 } 491 if nr == LA_SYS_READ { 492 if la_ea_ok(r[LA_REG_A1], r[LA_REG_A2], mem_size) == 1 { 493 r[LA_REG_A0] = sys_read(r[LA_REG_A0], ((mem as i64) + r[LA_REG_A1]) as *u8, r[LA_REG_A2]) 494 } else { 495 result = LAE_FAULT 496 halted = 1 497 } 498 } 499 } 500 501 if handled == 0 { result = LAE_UNSUPPORTED; halted = 1 } 502 pc = next 503 steps = steps + 1 504 } 505 } 506 return result 507} 508 509func emu_loongarch64_load_elf(buf: *u8, len: i64) -> i64 { 510 if len < 64 { return LAE_FAULT } 511 let e_entry: i64 = la_g_ld(buf, 24, 8) 512 let e_phoff: i64 = la_g_ld(buf, 32, 8) 513 let e_phnum: i64 = la_g_ld(buf, 56, 2) 514 let e_phent: i64 = la_g_ld(buf, 54, 2) 515 let mem: *u8 = sys_mmap(LA_GUEST_SIZE) 516 var idx: i64 = 0 517 while idx < e_phnum { 518 let ph: i64 = e_phoff + idx * e_phent 519 if la_g_ld(buf, ph, 4) == 1 { 520 let p_off: i64 = la_g_ld(buf, ph + 8, 8) 521 let p_va: i64 = la_g_ld(buf, ph + 16, 8) 522 let p_fs: i64 = la_g_ld(buf, ph + 32, 8) 523 var k: i64 = 0 524 while k < p_fs { 525 if (p_va + k) < LA_GUEST_SIZE { mem[p_va + k] = buf[p_off + k] } 526 k = k + 1 527 } 528 } 529 idx = idx + 1 530 } 531 return emu_loongarch64_run_mem(mem, LA_GUEST_SIZE, e_entry, 0x00F00000) 532}