code wiki / _hdl_build / nx_rv64_atomic_gate.nx

nx_rv64_atomic_gate.nx

buildroot/runtime/_hdl_build/nx_rv64_atomic_gate.nx

19764 B363 linesdepth 9pulls 41 transitivereach 0 importersview sourcekind gate/prooftopic rv64
docsdependenciesstructsconstsfunctions

about

nx_rv64_atomic_gate.nx -- LN34 REFEREE (lang.plan): the IR atomic family on the rv64 lane, from the byte up. ONE FAMILY, THREE LOWERINGS: __atomic_load/store/cas/faa_i64 + __atomic_fence (nx_atom.nx wraps them) lower to OP_ATOMIC_* in the IR; x86-64 lowers those to LOCK instructions (pre-existing), the wasm lane to the 0xFE family (nx_wasm_threads_gate), and -- proven HERE -- the rv64 backend (nx_riscv.nx) to RV64A: amoadd.d.aqrl, an lr.d/sc.d.aqrl compare-and-swap loop, and the ISA manual's sequentially-consistent fence mappings. FOUR LEGS, each composed IN-PROCESS so nothing is trusted by name: A. the sovereign text assembler (nx_rv64_asm) encodes every new mnemonic to the word an independent field-layout encoder predicts (funct5<<27 | aq<<26 | rl<<25 | rs2<<20 | rs1<<15 | funct3<<12 | rd<<7 | 0x2F; fence = pred<<24 | succ<<20 | 0x0F), refuses a malformed fence, and now admits `.L<name>:` labels while still skipping `.globl`-style directives; B. the behavioural sim (rv64im_min_sim, the same instance the A-extension conformance gate drives) executes the assembled program with the hand-computed register and memory results; C. the compiler backend, driven exactly as nx_nxc drives it (lex -> parse -> opt -> regalloc -> emit_function), lowers a fixture carrying every atomic op to those mnemonics and leaves no `# unhandled op`, while a plain fixture carries none of them (the neutrality neg-control); D. END TO END: the backend's emitted `tick` function is assembled by leg A's assembler and RUN on leg B's sim with a0/a1 as arguments and ra pointing at a self-loop sentinel, and the sim's a0 equals the tick count. nx_rv64_atomic_gate license_tier: ORIGINAL No hw writes (Rule 26).

dependencies 21 imports · 0 importers

nx_syscalls.nx nx_gate_verdict.nx nishi_hdl_primitives.nx rv64im_min_decoder.nx rv64im_min_alu.nx rv64im_min_regfile.nx rv64im_min_csr.nx rv64im_min_clint.nx rv64im_min_uart.nx rv64im_min_virtio.nx nx_rv64_atomic_gate.nx

diagram shows first 10 each side; +11 more imports, +0 more importers in the complete lists below.

imports: nx_syscalls.nxnx_gate_verdict.nxnishi_hdl_primitives.nxrv64im_min_decoder.nxrv64im_min_alu.nxrv64im_min_regfile.nxrv64im_min_csr.nxrv64im_min_clint.nxrv64im_min_uart.nxrv64im_min_virtio.nxrv64im_min_sim.nxnx_rv64_asm.nxnx_types.nxnx_lex_kinds.nxnx_outbuf.nxnx_ir.nxnx_tokenizer.nxnx_parse.nxnx_opt.nxnx_regalloc.nxnx_riscv.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main gv_ctr sys_mmap nxa_die sys_write sys_exit nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ gv_head gv_puts sys_write ↻ sys_mmap ↻ rvasm_assemble_str rvasm_assemble sys_mmap ↻ ra_isws ra_is_directive ra_isws ↻ ra_encode sys_mmap ↻ ra_afterword ra_isws ↻ ra_word_is ra_isws ↻ ra_reg ra_skipsep ra_isws ↻ ra_num ra_isdig ra_imm ra_skipsep ↻

structs

133struct GaSim

consts

43const GA_MEMB: i64 = 0x80000000
44const GA_MEMS: i64 = 65536
45const GA_CODE_CAP: i64 = 16384 // assembled words for one fixture function
46const GA_SCR_OFF: i64 = 0x2000 // the atomic cell, inside the sim memory
47const GA_SENTINEL_OFF: i64 = 0x3000 // `j .` the end-to-end run returns into
48const GA_STACK_OFF: i64 = 0xF000 // sp for the end-to-end run (grows down, well above code and cell)
49const GA_STEP_BUDGET: i64 = 200000 // instruction budget for the end-to-end run (a loop that never returns)
50const GA_TICKS: i64 = 1000
51const GA_TOKS: i64 = 262144
52const GA_ASM_CAP: i64 = 1048576
53const GA_FN_STRIDE: i64 = 176 // sizeof(Function), the stride nx_nxc walks with
54const GA_LOCS_STRIDE: i64 = 24
55const GA_FRAME_ALIGN: i64 = 16 // the two frame parameters nx_nxc passes to emit_function
56const GA_RA_SLOT: i64 = 8
58const GA_X_RA: i64 = 1
59const GA_X_SP: i64 = 2
60const GA_X_A0: i64 = 10
61const GA_X_A1: i64 = 11
62const GA_X_A7: i64 = 17
63const GA_X_T4: i64 = 29
64const GA_X_T5: i64 = 30
65const GA_X_T6: i64 = 31
67const GA_OP_AMO: i64 = 0x2F
68const GA_OP_FENCE: i64 = 0x0F
69const GA_F5_ADD: i64 = 0
70const GA_F5_SWAP: i64 = 1
71const GA_F5_LR: i64 = 2
72const GA_F5_SC: i64 = 3
73const GA_F3_D: i64 = 3
74const GA_F3_W: i64 = 2
75const GA_SH_F5: i64 = 27
76const GA_SH_AQ: i64 = 26
77const GA_SH_RL: i64 = 25
78const GA_SH_RS2: i64 = 20
79const GA_SH_RS1: i64 = 15
80const GA_SH_F3: i64 = 12
81const GA_SH_RD: i64 = 7
82const GA_SH_PRED: i64 = 24
83const GA_SH_SUCC: i64 = 20
84const GA_IORW: i64 = 15
85const GA_RW: i64 = 3
86const GA_R: i64 = 2
87const GA_W: i64 = 1
89const GA_CELL_INIT: i64 = 5
90const GA_ADDEND: i64 = 3
91const GA_EXP_T6_AFTER_ADD: i64 = 5
92const GA_EXP_A7_AFTER_LR: i64 = 8
93const GA_EXP_CELL_FINAL: i64 = 8
94const GA_EXP_SC_FAIL: i64 = 1
95const GA_EXP_CAS: i64 = 1009
96const GA_JAL_SELF: i64 = 0x6F // jal x0, 0 -- a self-loop the end-to-end run returns into
98const GA_FX_ATOMIC: *u8 = "const MO: i64 = 5\nfunc tick(p: i64, n: i64) -> i64 {\n let c: *i64 = p as *i64\n var i: i64 = 0\n while i < n { __atomic_faa_i64(c, 1, MO); i = i + 1 }\n return __atomic_load_i64(c, MO)\n}\nfunc probe_cas(p: i64) -> i64 {\n let c: *i64 = p as *i64\n let s: i64 = __atomic_store_i64(c, 7, MO)\n let a: i64 = __atomic_cas_i64(c, 7, 9, MO)\n let b: i64 = __atomic_cas_i64(c, 7, 11, MO)\n let f: i64 = __atomic_fence(MO)\n let v: i64 = __atomic_load_i64(c, MO)\n return a * 1000 + b * 100 + v + s + f\n}\n"
99const GA_FX_PLAIN: *u8 = "func plain(a: i64, b: i64) -> i64 { return a + b }\n"
100const GA_PROG_B: *u8 = "amoadd.d.aqrl t6, t5, (t4)\nlr.d.aqrl a7, (t4)\nsc.d.aqrl t5, t6, (t4)\nfence rw, rw\namoswap.d.aqrl t6, a7, (t4)\nsc.d.aqrl t5, t6, (t4)\n"
101const GA_PROG_B_N: i64 = 6
102const GA_PROG_LABELS: *u8 = ".globl top\ntop:\n.Lloop_bb0:\n addi t5, t5, -1\n bne t5, zero, .Lloop_bb0\n ret\n"
103const GA_PROG_LABELS_N: i64 = 3
104const GA_PROG_BADFENCE: *u8 = "fence rw\n"

functions

106func ga_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
called by 2: ga_hasga_label_off
107func ga_has(buf: *u8, n: i64, needle: *u8) -> i64
called by 1: main calls 1: ga_slen
121func ga_word(buf: *u8, off: i64) -> i64
called by 1: main
124func ga_wr64(mem: *u8, off: i64, v: i64) -> i64 { var i: i64 = 0; while i < 8 { mem[off + i] = ((v >> (i * 8)) & 0xff) as u8; i = i + 1 } return 0 }
called by 1: main
125func ga_rd64(mem: *u8, off: i64) -> i64 { var v: i64 = 0; var i: i64 = 0; while i < 8 { v = v | ((mem[off + i] as i64) << (i * 8)); i = i + 1 } return v }
called by 1: main
127func ga_amo(f5: i64, aq: i64, rl: i64, rs2: i64, rs1: i64, f3: i64, rd: i64) -> i64
called by 1: main
130func ga_fence(pred: i64, succ: i64) -> i64 { return (pred << GA_SH_PRED) | (succ << GA_SH_SUCC) | GA_OP_FENCE }
called by 1: main
138func ga_sim_new() -> *GaSim
called by 1: main calls 1: sys_mmap
160func ga_compile(src: *u8, o: *OutBuf) -> i64
183func ga_label_off(txt: *u8, n: i64, name: *u8) -> i64
called by 1: ga_label_addr calls 1: ga_slen
201func ga_label_addr(txt: *u8, n: i64, name: *u8) -> i64
231func ga_puti(v: i64) -> i64
called by 1: main calls 2: sys_mmapsys_write
245func main(argc: i64, argv: *i64) -> i64