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}