code wiki / _hdl_build / nx_geneal_energy_sov.nx
nx_geneal_energy_sov.nx source
↩ module page · 314 lines · 17752 B
1// nx_geneal_energy_sov.nx -- ENERGY as a recorded genealogy FEATURE of descendants.
2//
3// Operator: the genealogist must record ENERGY USE per descendant, alongside "can we generate the
4// code", its capability, and cost -- so we can compare our family's member against another family's
5// member for the SAME capability. This builds that feature and a MEASURED cross-family comparison.
6//
7// SOVEREIGN measurement (per the system-not-person rule): the cost is the instruction count the
8// program retires on the genesis sim (sim.steps) -- the system measuring its OWN cost, deterministic,
9// never a host stopwatch. Instructions-retired is the standard architectural ENERGY PROXY
10// (energy ~ instructions x energy-per-instruction); it is a proxy, not joules, and it is directly
11// comparable across family members on the same ISA.
12//
13// Demonstration: capability C = f(a)=a*a, expressible by two implementation FAMILIES --
14// - NAIVE family: a loop, acc=0;i=a;while i>0{acc+=a;i--} -> O(a) instructions
15// - DISCOVERED family: a straight-line program the team DERIVES by search -> O(1) instructions
16// We record both as genealogy descendants {family, capability NN/NN, generatable, energy_total,
17// energy@small, energy@large, scaling} and emit the measured comparison. Honesty controls: the
18// numbers must be REAL -- naive cost must GROW with input, discovered cost must stay FLAT, else RED.
19// license_tier: ORIGINAL
20import "nx_syscalls.nx"
21import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
22import "nishi_hdl_primitives.nx"
23import "rv64im_min_decoder.nx"
24import "rv64im_min_alu.nx"
25import "rv64im_min_regfile.nx"
26import "rv64im_min_csr.nx"
27import "rv64im_min_clint.nx"
28import "rv64im_min_uart.nx"
29import "rv64im_min_sim.nx"
30const EVO_MAGIC_2862933555777941757: i64 = 2862933555777941757
31const EVO_MAGIC_3037000493: i64 = 3037000493
32const EVO_MAGIC_1000000000000: i64 = 1000000000000
33const EVO_MAGIC_10000000000000: i64 = 10000000000000
34const EVO_MAGIC_1000000000: i64 = 1000000000
35const EVO_MAGIC_20260615: i64 = 20260615
36
37const GLEN: i64 = 5 // straight-line genome: [op1, r1, r2, op2, r3]
38const EVO_P: i64 = 256
39const EVO_G: i64 = 600
40const EVO_T: i64 = 5
41const NTRAIN: i64 = 8
42const NHELD: i64 = 12
43
44const IR_MEM_BASE: i64 = 0x80000000
45const IR_MEM_SIZE: i64 = 8192
46const IR_TX_CAP: i64 = 256
47const RES_OFF: i64 = 0x700
48
49func ge_rand(s: *i64) -> i64 { s[0] = s[0] * EVO_MAGIC_2862933555777941757 + EVO_MAGIC_3037000493; return (s[0] >> 17) & 0x3fffffff }
50func ge_abs(x: i64) -> i64 { if x < 0 { return 0 - x } return x }
51func ge_ha(i: i64) -> i64 { if i==0 {return 3} if i==1 {return 8} if i==2 {return 11} if i==3 {return 2} if i==4 {return 10} if i==5 {return 13} if i==6 {return 7} if i==7 {return 4} if i==8 {return 12} if i==9 {return 6} if i==10 {return 9} return 5 }
52func ge_hb(i: i64) -> i64 { if i==0 {return 5} if i==1 {return 2} if i==2 {return 7} if i==3 {return 11} if i==4 {return 4} if i==5 {return 3} if i==6 {return 9} if i==7 {return 8} if i==8 {return 2} if i==9 {return 13} if i==10 {return 6} return 10 }
53
54// the capability to be implemented by both families: f(a,b) = a*a.
55func ge_target(a: i64, b: i64) -> i64 { return a * a }
56
57// ---- interpreter (straight-line; guides the search for the discovered family) ----
58func ge_aluop(op: i64, x: i64, y: i64) -> i64 {
59 if (op % 3) == 0 { return x + y }
60 if (op % 3) == 1 { return x - y }
61 return x * y
62}
63func ge_reg(idx: i64, a: i64, b: i64) -> i64 { if idx == 0 { return 0 } if idx == 1 { return a } if idx == 2 { return b } return a }
64func ge_eval_s(g: *i64, base: i64, a: i64, b: i64) -> i64 {
65 let t: i64 = ge_aluop(g[base], ge_reg(g[base+1], a, b), ge_reg(g[base+2], a, b))
66 return ge_aluop(g[base+3], t, ge_reg(g[base+4], a, b))
67}
68
69// ---- RV64 encoders (verified in the trilogy) ----
70func rv_addi(rd: i64, rs1: i64, imm: i64) -> i64 { return ((imm & 0xFFF) << 20) | (rs1 << 15) | (rd << 7) | 0x13 }
71func rv_lui(rd: i64, imm20: i64) -> i64 { return ((imm20 & 0xFFFFF) << 12) | (rd << 7) | 0x37 }
72func rv_rtype(f7: i64, rs2: i64, rs1: i64, f3: i64, rd: i64) -> i64 { return (f7 << 25) | (rs2 << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | 0x33 }
73func rv_store_imm(rs2: i64, rs1: i64, f3: i64, imm: i64) -> i64 { return (((imm >> 5) & 0x7f) << 25) | (rs2 << 20) | (rs1 << 15) | (f3 << 12) | ((imm & 0x1f) << 7) | 0x23 }
74func rv_branch(f3: i64, rs1: i64, rs2: i64, imm: i64) -> i64 { return (((imm >> 12) & 1) << 31) | (((imm >> 5) & 0x3f) << 25) | (rs2 << 20) | (rs1 << 15) | (f3 << 12) | (((imm >> 1) & 0xf) << 8) | (((imm >> 11) & 1) << 7) | 0x63 }
75func rv_jal(rd: i64, imm: i64) -> i64 { return (((imm >> 20) & 1) << 31) | (((imm >> 1) & 0x3ff) << 21) | (((imm >> 11) & 1) << 20) | (((imm >> 12) & 0xff) << 12) | (rd << 7) | 0x6f }
76func ge_f7(op: i64) -> i64 { if (op % 3) == 1 { return 0x20 } if (op % 3) == 2 { return 0x01 } return 0x00 }
77func ge_regx(idx: i64) -> i64 { if idx == 0 { return 0 } if idx == 1 { return 1 } if idx == 2 { return 2 } return 1 }
78func rv_w32(buf: *u8, off: i64, w: i64) -> i64 {
79 buf[off] = (w & 0xff) as u8
80 buf[off+1] = ((w >> 8) & 0xff) as u8
81 buf[off+2] = ((w >> 16) & 0xff) as u8
82 buf[off+3] = ((w >> 24) & 0xff) as u8
83 return off + 4
84}
85func ge_tail(mem: *u8, o: i64) -> i64 {
86 var p: i64 = o
87 p = rv_w32(mem, p, rv_store_imm(3, 5, 3, RES_OFF))
88 p = rv_w32(mem, p, rv_lui(7, 0x100))
89 p = rv_w32(mem, p, rv_lui(6, 0x5))
90 p = rv_w32(mem, p, rv_addi(6, 6, 0x555))
91 p = rv_w32(mem, p, rv_store_imm(6, 7, 2, 0))
92 p = rv_w32(mem, p, 0x6F)
93 return 0
94}
95// DISCOVERED family: straight-line genome -> RV64 (O(1) instructions).
96func ge_emit_straight(mem: *u8, g: *i64, a: i64, b: i64) -> i64 {
97 rv_w32(mem, 0, rv_addi(1, 0, a))
98 rv_w32(mem, 4, rv_addi(2, 0, b))
99 rv_w32(mem, 8, rv_lui(5, 0x80000))
100 rv_w32(mem, 12, rv_rtype(ge_f7(g[0]), ge_regx(g[2]), ge_regx(g[1]), 0, 6))
101 rv_w32(mem, 16, rv_rtype(ge_f7(g[3]), ge_regx(g[4]), 6, 0, 3))
102 ge_tail(mem, 20)
103 return 0
104}
105// NAIVE family: a loop acc=0;i=a;while i>0{acc+=a;i--} = a*a (O(a) instructions).
106func ge_emit_loop(mem: *u8, a: i64, b: i64) -> i64 {
107 rv_w32(mem, 0, rv_addi(1, 0, a))
108 rv_w32(mem, 4, rv_addi(2, 0, b))
109 rv_w32(mem, 8, rv_lui(5, 0x80000))
110 rv_w32(mem, 12, rv_addi(3, 0, 0)) // acc=0
111 rv_w32(mem, 16, rv_addi(4, 1, 0)) // i=a
112 rv_w32(mem, 20, rv_branch(0, 4, 0, 16)) // beq x4,x0,+16 -> EXIT(36)
113 rv_w32(mem, 24, rv_rtype(0x00, 1, 3, 0, 3)) // acc += a (x3 = x3 + x1)
114 rv_w32(mem, 28, rv_addi(4, 4, 0 - 1)) // i--
115 rv_w32(mem, 32, rv_jal(0, 0 - 12)) // -> LOOP_TOP(20)
116 ge_tail(mem, 36)
117 return 0
118}
119func ge_read_i64(mem: *u8, off: i64) -> i64 {
120 var v: i64 = 0; var i: i64 = 0
121 while i < 8 { v = v | ((mem[off + i] as i64) << (i * 8)); i = i + 1 }
122 return v
123}
124// run on god; return result; set steps[0] = sim.steps (the SOVEREIGN energy proxy). which: 0 straight,1 loop.
125func ge_run(which: i64, g: *i64, a: i64, b: i64, steps: *i64) -> i64 {
126 let rf_storage: *i64 = (sys_mmap(8 * NX_RV64IM_RF_N_REGS)) as *i64
127 let csr_storage: *i64 = (sys_mmap(8 * NX_CSR_SLOT_N)) as *i64
128 let clint_storage: *i64 = (sys_mmap(8 * NX_CLINT_SLOT_N)) as *i64
129 let uart_storage: *i64 = (sys_mmap(8 * NX_UART_SLOT_N)) as *i64
130 let mem: *u8 = sys_mmap(IR_MEM_SIZE)
131 let tx_buf: *u8 = sys_mmap(IR_TX_CAP)
132 let rf: *NxRv64imRegfile = (sys_mmap(64)) as *NxRv64imRegfile
133 let csr: *NxRv64imCsrFile = (sys_mmap(64)) as *NxRv64imCsrFile
134 let clint: *NxClint = (sys_mmap(64)) as *NxClint
135 let uart: *NxUart = (sys_mmap(64)) as *NxUart
136 let sim: *NxRv64imSim = (sys_mmap(128)) as *NxRv64imSim
137 nx_rv64im_rf_init(rf, rf_storage)
138 nx_rv64im_csr_init(csr, csr_storage, 0)
139 nx_clint_init(clint, clint_storage)
140 nx_uart_init(uart, uart_storage, tx_buf, IR_TX_CAP)
141 nx_rv64im_sim_init(sim, rf, csr, clint, uart, IR_MEM_BASE, mem, IR_MEM_SIZE, 0)
142 if which == 0 { ge_emit_straight(mem, g, a, b) } else { ge_emit_loop(mem, a, b) }
143 nx_rv64im_sim_run(sim, 600)
144 steps[0] = sim.steps
145 return ge_read_i64(mem, RES_OFF)
146}
147
148// ---- derive the DISCOVERED (straight-line) family member for a*a (proves "we can generate it") ----
149func ge_fit(pop: *i64, base: i64) -> i64 {
150 var err: i64 = 0; var i: i64 = 0
151 while i < NTRAIN {
152 let a: i64 = ge_ha(i); let b: i64 = ge_hb(i)
153 let r: i64 = ge_eval_s(pop, base, a, b)
154 let y: i64 = ge_target(a, b)
155 var d: i64 = ge_abs(r - y)
156 if r > EVO_MAGIC_1000000000000 { d = EVO_MAGIC_10000000000000 }
157 if r < (0 - EVO_MAGIC_1000000000000) { d = EVO_MAGIC_10000000000000 }
158 err = err + d; i = i + 1
159 }
160 return err
161}
162func ge_randslot(idx: i64, state: *i64) -> i64 { if idx == 0 { return ge_rand(state) % 3 } if idx == 3 { return ge_rand(state) % 3 } return ge_rand(state) % 4 }
163func ge_fill(g: *i64, base: i64, state: *i64) -> i64 { var i: i64 = 0; while i < GLEN { g[base+i] = ge_randslot(i, state); i = i + 1 } return 0 }
164func ge_tourney(fit: *i64, state: *i64) -> i64 {
165 var bi: i64 = ge_rand(state) % EVO_P; var bd: i64 = fit[bi]; var k: i64 = 1
166 while k < EVO_T { let i: i64 = ge_rand(state) % EVO_P; if fit[i] < bd { bd = fit[i]; bi = i } k = k + 1 }
167 return bi
168}
169func ge_derive(state: *i64, G: *i64) -> i64 {
170 let pop: *i64 = sys_mmap(EVO_P * GLEN * 8) as *i64
171 let nxt: *i64 = sys_mmap(EVO_P * GLEN * 8) as *i64
172 let fit: *i64 = sys_mmap(EVO_P * 8) as *i64
173 var p: i64 = 0
174 while p < EVO_P { ge_fill(pop, p*GLEN, state); p = p + 1 }
175 var best_err: i64 = EVO_MAGIC_1000000000; var g: i64 = 0
176 while g < EVO_G {
177 var gbest: i64 = EVO_MAGIC_1000000000; var gbp: i64 = 0
178 p = 0
179 while p < EVO_P { let e: i64 = ge_fit(pop, p*GLEN); fit[p] = e; if e < gbest { gbest = e; gbp = p } p = p + 1 }
180 if gbest < best_err { best_err = gbest; var j: i64 = 0; while j < GLEN { G[j] = pop[gbp*GLEN + j]; j = j + 1 } }
181 if best_err == 0 { g = EVO_G } else {
182 var j2: i64 = 0; while j2 < GLEN { nxt[j2] = G[j2]; j2 = j2 + 1 }
183 p = 1
184 while p < EVO_P {
185 let pa: i64 = ge_tourney(fit, state) * GLEN
186 let pb: i64 = ge_tourney(fit, state) * GLEN
187 let cut: i64 = (ge_rand(state) % (GLEN - 1)) + 1
188 var jj: i64 = 0
189 while jj < GLEN { if jj < cut { nxt[p*GLEN + jj] = pop[pa + jj] } else { nxt[p*GLEN + jj] = pop[pb + jj] } jj = jj + 1 }
190 let idx: i64 = ge_rand(state) % GLEN
191 nxt[p*GLEN + idx] = ge_randslot(idx, state)
192 p = p + 1
193 }
194 var c: i64 = 0; while c < EVO_P * GLEN { pop[c] = nxt[c]; c = c + 1 }
195 g = g + 1
196 }
197 }
198 return best_err
199}
200
201// ---- print -----------------------------------------------------------------------------
202func ge_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
203// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
204// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
205// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
206// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
207func ge_pn(v: i64) -> i64 { nxi_out(v); return 0 }
208
209// capability check: does this family member compute a*a on every held-out point? returns match count.
210// also accumulates total energy (sim.steps) into tot[0]. which: 0 straight (uses G), 1 loop.
211func ge_capability(which: i64, G: *i64, tot: *i64) -> i64 {
212 let st: *i64 = sys_mmap(8) as *i64
213 var ok: i64 = 0; var sum: i64 = 0; var i: i64 = 0
214 while i < NHELD {
215 let a: i64 = ge_ha(i); let b: i64 = ge_hb(i)
216 let r: i64 = ge_run(which, G, a, b, st)
217 if r == ge_target(a, b) { ok = ok + 1 }
218 sum = sum + st[0]
219 i = i + 1
220 }
221 tot[0] = sum
222 return ok
223}
224
225// emit a genealogy descendant row: family, capability, generatable, energy total + at a=4 / a=12 + scaling.
226func ge_row(label: *u8, which: i64, G: *i64, cap: i64, etot: i64) -> i64 {
227 let st: *i64 = sys_mmap(8) as *i64
228 ge_run(which, G, 4, 3, st); let e4: i64 = st[0]
229 ge_run(which, G, 12, 3, st); let e12: i64 = st[0]
230 ge_p(" DESCENDANT family="); ge_p(label)
231 ge_p(" capability=a*a("); ge_pn(cap); ge_p("/"); ge_pn(NHELD); ge_p(")")
232 ge_p(" generatable=yes energy_total="); ge_pn(etot)
233 ge_p(" energy@a=4="); ge_pn(e4); ge_p(" energy@a=12="); ge_pn(e12)
234 if e12 > e4 { ge_p(" scaling=GROWS-with-input(O(a))") } else { ge_p(" scaling=FLAT(O(1))") }
235 ge_p("\n")
236 return 0
237}
238
239// ---- registry authoring: persist energy as a genealogy FEATURE (tmp + atomic renameat, house pattern) ----
240const EE_TMP: *u8 = "knowledge/registry/energy_genealogy.tsv.tmp"
241const EE_LIVE: *u8 = "knowledge/registry/energy_genealogy.tsv"
242func ee_w(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
243// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
244// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
245// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
246// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
247func ee_wn(fd: i64, v: i64) -> i64 { nxi_fd(fd, v); return 0 }
248// one descendant row, all values MEASURED (passed in) -- never hand-typed (Rule 4).
249func ee_row(fd: i64, name: *u8, family: *u8, cap: i64, etot: i64, esmall: i64, elarge: i64) -> i64 {
250 ee_w(fd, name); ee_w(fd, "\t"); ee_w(fd, family); ee_w(fd, "\ta*a\t"); ee_wn(fd, cap); ee_w(fd, "/"); ee_wn(fd, NHELD)
251 ee_w(fd, "\tyes\t"); ee_wn(fd, etot); ee_w(fd, "\t"); ee_wn(fd, esmall); ee_w(fd, "\t"); ee_wn(fd, elarge); ee_w(fd, "\t")
252 if elarge > esmall { ee_w(fd, "O(a)") } else { ee_w(fd, "O(1)") }
253 ee_w(fd, "\tsim.steps@rv64im_min_sim\n")
254 return 0
255}
256func ee_author(capS: i64, eS: i64, s4: i64, s12: i64, capL: i64, eL: i64, l4: i64, l12: i64) -> i64 {
257 let fd: i64 = sys_openat_wr(EE_TMP, 420)
258 if fd < 0 { return 0 - 1 }
259 ee_w(fd, "# energy_genealogy.tsv -- ENERGY/cost as a MEASURED genealogy feature of runnable descendants.\n")
260 ee_w(fd, "# AUTHORED BY nx_geneal_energy (sovereign): cost = instructions retired on rv64im_min_sim (sim.steps),\n")
261 ee_w(fd, "# the architectural energy proxy, measured by the system itself (no host stopwatch). regen=full-rewrite+renameat.\n")
262 ee_w(fd, "# columns: descendant\tfamily\tcapability\tcap_match\tgeneratable\tenergy_total\tenergy_small\tenergy_large\tscaling\tmeasured_by\n")
263 ee_row(fd, "a_sq.discovered", "straight", capS, eS, s4, s12)
264 ee_row(fd, "a_sq.naive", "loop", capL, eL, l4, l12)
265 sys_close(fd)
266 return sys_renameat(EE_TMP, EE_LIVE)
267}
268
269func main() -> i64 {
270 ge_p("GENEALENERGY: record ENERGY (instructions retired on god = sovereign energy proxy) as a descendant feature; compare families for capability a*a\n")
271
272 // (1) DISCOVERED family: derive a straight-line program computing a*a (proves we can GENERATE it).
273 let state: *i64 = sys_mmap(8) as *i64; state[0] = EVO_MAGIC_20260615
274 let G: *i64 = sys_mmap(GLEN * 8) as *i64
275 let de: i64 = ge_derive(state, G)
276 ge_p(" derive straight-line a*a: derive_err="); ge_pn(de); ge_p(" (0 = generated)\n")
277
278 // (2) measure capability + total energy for each family.
279 let tS: *i64 = sys_mmap(8) as *i64
280 let tL: *i64 = sys_mmap(8) as *i64
281 let capS: i64 = ge_capability(0, G, tS)
282 let capL: i64 = ge_capability(1, G, tL) // G ignored for loop
283 let eS: i64 = tS[0]; let eL: i64 = tL[0]
284
285 // (3) genealogy rows -- energy now a recorded FEATURE of each descendant.
286 ge_row("straight(discovered)", 0, G, capS, eS)
287 ge_row("loop(naive) ", 1, G, capL, eL)
288
289 // (4) measured cross-family comparison (same capability, different cost).
290 ge_p(" CROSS-FAMILY: same capability a*a -- discovered energy_total="); ge_pn(eS)
291 ge_p(" vs naive energy_total="); ge_pn(eL)
292 if eS < eL { ge_p(" -> our (discovered) family is CHEAPER, measured\n") } else { ge_p(" -> discovered NOT cheaper\n") }
293
294 // (5) honesty controls: numbers must be REAL. naive grows with input; discovered stays flat.
295 let st: *i64 = sys_mmap(8) as *i64
296 ge_run(1, G, 4, 3, st); let l4: i64 = st[0]
297 ge_run(1, G, 12, 3, st); let l12: i64 = st[0]
298 ge_run(0, G, 4, 3, st); let s4: i64 = st[0]
299 ge_run(0, G, 12, 3, st); let s12: i64 = st[0]
300 ge_p(" control(real-measurement): naive a=4->"); ge_pn(l4); ge_p(" a=12->"); ge_pn(l12)
301 ge_p(" ; discovered a=4->"); ge_pn(s4); ge_p(" a=12->"); ge_pn(s12); ge_p("\n")
302
303 // (6) PERSIST: author the measured energy rows into the real genealogist registry (additive, idempotent).
304 let wrote: i64 = ee_author(capS, eS, s4, s12, capL, eL, l4, l12)
305 ge_p(" registry: authored knowledge/registry/energy_genealogy.tsv (renameat rc="); ge_pn(wrote); ge_p(")\n")
306
307 if de == 0 { if capS == NHELD { if capL == NHELD { if eS < eL { if l12 > l4 { if s12 == s4 { if wrote == 0 {
308 ge_p("GENEALENERGY GREEN: energy AUTHORED into knowledge/registry/energy_genealogy.tsv per descendant (sovereign sim.steps); both families compute a*a; discovered O(1) measured CHEAPER than naive O(a) -- naive grows ("); ge_pn(l4); ge_p("->"); ge_pn(l12); ge_p("), discovered flat ("); ge_pn(s4); ge_p("=="); ge_pn(s12); ge_p(")\n")
309 sys_exit(0); return 0
310 }}}}}}}
311 ge_p("GENEALENERGY RED\n")
312 sys_exit(1)
313 return 1
314}