code wiki / (root) / nx_isa_manager.nx

nx_isa_manager.nx source

↩ module page · 1148 lines · 43395 B

1// nx_isa_manager.nx -- THE MASTER ISA MANAGER. 2// 3// WHAT IT IS: not another conformance gate. The gates measure ONE 4// architecture each and answer "does this emulator obey its manual". 5// This organ measures THE POPULATION and answers a different question: 6// of every ISA the estate has declared in scope, which ones does 7// anything at all measure, which have an emulator nobody rules on, 8// which are declared and untouched, and what is the next actionable 9// name in each of those classes. 10// 11// THE DENOMINATOR IS PUBLISHED. knowledge/isa_targets.conf is the 12// population and it is READ, never inferred. A coverage ratio whose 13// denominator is "the ISAs I happened to think of" flatters itself by 14// omission; 14 of 122 is an honest number and 14 of 14 is not. 15// 16// impl AND ext ROWS ARE NOT TARGETS AND ARE EXCLUDED FROM EVERY 17// EMITTER/EMULATOR RATIO. An impl row is a HOST that implements another 18// row's ISA (Phytium implements aarch64) and an ext row is an EXTENSION 19// of a base ISA (SVE extends aarch64). Counting either in a codegen 20// ratio double-counts the base ISA and inflates the number in the one 21// direction nobody audits. They get their own named state, 22// NOT-A-TARGET, so they are visible and excluded at the same time. 23// 24// HOW A NEW ISA JOINS -- NO EDIT TO THIS ORGAN, EVER: 25// 1. add a row to knowledge/isa_targets.conf. It reads DECLARED-ONLY. 26// 2. write buildroot/runtime/nx_emu_<id>.nx. It reads EMULATOR-ONLY. 27// 3. write buildroot/runtime/nx_isa_<id>_gate.nx, or import 28// nx_emu_<id>.nx from nx_isa_conform_gate.nx. It reads 29// GATE-PRESENT-UNRUN. 30// 4. let that gate bank "<id> <passed>" into 31// knowledge/status/isa_<id>.ratchet, or into the core gate's 32// shared knowledge/status/isa_conform.ratchet. It reads 33// MEASURED-GREEN. 34// If the organs are already named something other than the conf id, add 35// ONE row to knowledge/isa_emu_alias.conf. That file is DATA and the 36// manager reports how many rows it used and names any alias whose id is 37// not in the population, because an alias for an undeclared id is a 38// typo that silently hides a target. 39// 40// DISCOVERY IS A PROBE, NOT A LIST. There is no array of architecture 41// names in this file. Every state comes from stat-ing a path derived 42// from a conf row and from scanning the core gate's own source for the 43// emulator it imports. A hardcoded roster is a name list, and a name 44// list always lags the next generator -- this estate has measured that 45// four times in three weeks on the compare trees alone. 46// 47// TWO TREES, FOUR CANDIDATE ROOTS. buildroot/runtime and runtime are 48// different trees and the builder probes _hdl_build FIRST, so a probe 49// that knows only one of them returns a confident, complete-looking 50// false negative. Every existence question here is asked against all 51// four and the answer carries the root it resolved from. 52// 53// WHY THE TEETH DO NOT MEASURE THE ISAs. Every gv_check below asserts 54// something THIS ORGAN controls: that the partitions sum, that discovery 55// did not silently stop finding gates, that no target was left without a 56// state, that the ratchet was not touched. A manager whose verdict went 57// RED because an ISA is incomplete would be RED on the day it shipped 58// and every day after, and a permanently red detector is one everyone 59// learns to ignore. The ISA numbers are PUBLISHED, and the worklist at 60// the end is what a seat acts on. The verdict is the fence; the numbers 61// are the work. 62// 63// THE RATCHET IS READ-ONLY HERE. The gates own it. A tooth re-reads it 64// at the end of the run and byte-compares against the copy taken at the 65// start, so "the manager does not write the ratchet" is measured rather 66// than promised. Size is never an identity, so the comparison is over 67// content. 68// 69// license_tier: ORIGINAL 70 71import "nx_gate_verdict.nx" 72import "nx_syscalls.nx" 73 74// ---- population and evidence paths ----------------------------- 75const IM_CONF_NAME: *u8 = "isa_targets.conf" 76const IM_ALIAS_NAME: *u8 = "isa_emu_alias.conf" 77const IM_CORE_GATE: *u8 = "nx_isa_conform_gate.nx" 78const IM_CORE_RATCH: *u8 = "status/isa_conform.ratchet" 79const IM_RATCH_PRE: *u8 = "status/isa_" 80const IM_RATCH_SUF: *u8 = ".ratchet" 81const IM_EMU_PRE: *u8 = "nx_emu_" 82const IM_GATE_PRE: *u8 = "nx_isa_" 83const IM_GATE_SUF: *u8 = "_gate.nx" 84const IM_NX_SUF: *u8 = ".nx" 85 86// Runtime roots, probed in this order. _hdl_build first inside each 87// tree because that is the order the builder resolves imports in, so 88// reporting on the other one would report on a file that does not 89// compile. 90const IM_ROOTS: i64 = 4 91func im_root(i: i64) -> *u8 { 92 if i == 0 { return "buildroot/runtime/_hdl_build/" as *u8 } 93 if i == 1 { return "buildroot/runtime/" as *u8 } 94 if i == 2 { return "runtime/_hdl_build/" as *u8 } 95 return "runtime/" as *u8 96} 97const IM_KROOTS: i64 = 2 98func im_kroot(i: i64) -> *u8 { 99 if i == 0 { return "knowledge/" as *u8 } 100 return "buildroot/knowledge/" as *u8 101} 102 103// ---- sizes. No silent caps: every one of these is asserted by a 104// tooth and announced when reached, because a cap reached in silence 105// becomes a measurement nobody knows is partial. 106const IM_MAX_TARGETS: i64 = 512 107const IM_MAX_ALIAS: i64 = 256 108const IM_PATH_BYTES: i64 = 1024 109const IM_SLICE_BYTES: i64 = 256 110const IM_BOX_BYTES: i64 = 16 111const IM_ALIAS_COLS: i64 = 4 112const IM_WORD: i64 = 8 113const IM_ALIAS_TAG: i64 = 6 114const IM_ISA_TAG: i64 = 4 115// The schema is SEVEN '|'-separated fields and the FIRST IS THE LITERAL 116// TAG "isa", which the tag test has already consumed -- so the walk that 117// starts after it sees SIX. The first cut of this constant said 7 and 118// every one of the 122 rows read as malformed: a fixture with the real 119// population found it in one run, and a fixture built from a row I had 120// typed myself would have agreed with my own miscount. 121const IM_FIELDS_AFTER_TAG: i64 = 6 122 123// ---- discovery floors. NOT health bars: regression fences on the 124// DISCOVERY mechanism itself. Measured 2026-09-03 the estate carried 125// six conformance gate sources and eleven emulator sources. If a root 126// moves or a naming rule changes and discovery silently stops finding 127// them, these fire. They ratchet upward by hand, never downward. 128const IM_GATE_FLOOR: i64 = 6 129const IM_EMU_FLOOR: i64 = 6 130 131// ---- byte constants -------------------------------------------- 132const IM_NL: i64 = 10 133const IM_CR: i64 = 13 134const IM_SPACE: i64 = 32 135const IM_PIPE: i64 = 124 136const IM_DIG_LO: i64 = 48 137const IM_DIG_HI: i64 = 57 138const IM_BYTE_M: i64 = 255 139const IM_PERMIL: i64 = 1000 140const IM_B10: i64 = 10 141const IM_SEEK_END: i64 = 2 142const IM_NUL: i64 = 0 143 144// ---- classes. UNKNOWN is its own bucket and never folds into a known 145// one: the bucket an unrecognised class lands in becomes the number 146// somebody plans against. 147const IM_C_CPU: i64 = 0 148const IM_C_MCU: i64 = 1 149const IM_C_GPU: i64 = 2 150const IM_C_ACCEL: i64 = 3 151const IM_C_DSP: i64 = 4 152const IM_C_VM: i64 = 5 153const IM_C_FPGA: i64 = 6 154const IM_C_LEGACY: i64 = 7 155const IM_C_IMPL: i64 = 8 156const IM_C_EXT: i64 = 9 157const IM_C_NISHI: i64 = 10 158const IM_C_UNKNOWN: i64 = 11 159const IM_C_COUNT: i64 = 12 160 161func im_class_name(c: i64) -> *u8 { 162 if c == IM_C_CPU { return "cpu" as *u8 } 163 if c == IM_C_MCU { return "mcu" as *u8 } 164 if c == IM_C_GPU { return "gpu" as *u8 } 165 if c == IM_C_ACCEL { return "accel" as *u8 } 166 if c == IM_C_DSP { return "dsp" as *u8 } 167 if c == IM_C_VM { return "vm" as *u8 } 168 if c == IM_C_FPGA { return "fpga" as *u8 } 169 if c == IM_C_LEGACY { return "legacy" as *u8 } 170 if c == IM_C_IMPL { return "impl" as *u8 } 171 if c == IM_C_EXT { return "ext" as *u8 } 172 if c == IM_C_NISHI { return "nishi" as *u8 } 173 return "UNKNOWN-CLASS" as *u8 174} 175 176// ---- states. UNSET is a real value the array is initialised to, so 177// "every target got exactly one named state" is a MEASUREMENT and not 178// an assumption: any row the classifier failed to reach is still UNSET 179// at the end and the tooth names it. 180const IM_S_UNSET: i64 = -1 181const IM_S_GREEN: i64 = 0 182const IM_S_RED: i64 = 1 183const IM_S_UNRUN: i64 = 2 184const IM_S_EMUONLY: i64 = 3 185const IM_S_DECLARED: i64 = 4 186const IM_S_NOTARGET: i64 = 5 187const IM_S_COUNT: i64 = 6 188 189func im_state_name(s: i64) -> *u8 { 190 if s == IM_S_GREEN { return "MEASURED-GREEN" as *u8 } 191 if s == IM_S_RED { return "MEASURED-RED" as *u8 } 192 if s == IM_S_UNRUN { return "GATE-PRESENT-UNRUN" as *u8 } 193 if s == IM_S_EMUONLY { return "EMULATOR-ONLY" as *u8 } 194 if s == IM_S_DECLARED { return "DECLARED-ONLY" as *u8 } 195 if s == IM_S_NOTARGET { return "NOT-A-TARGET" as *u8 } 196 return "UNSET-CLASSIFIER-DID-NOT-REACH-THIS-ROW" as *u8 197} 198 199func im_state_meaning(s: i64) -> *u8 { 200 if s == IM_S_GREEN { return "a ratchet banks a passing score for it" as *u8 } 201 if s == IM_S_RED { return "a ratchet banks a score of zero: measured, and nothing passes" as *u8 } 202 if s == IM_S_UNRUN { return "a gate covers it, no ratchet banks a score, so no run was ever recorded" as *u8 } 203 if s == IM_S_EMUONLY { return "an emulator exists and nothing rules on it" as *u8 } 204 if s == IM_S_DECLARED { return "in the population, no emulator, no gate: the frontier" as *u8 } 205 if s == IM_S_NOTARGET { return "impl or ext row: a host or an extension, never a standalone codegen target" as *u8 } 206 return "the classifier did not reach this row -- a defect in this organ" as *u8 207} 208 209// ---- tiny string helpers --------------------------------------- 210 211func im_nl() -> i64 { 212 let b: *u8 = sys_mmap(IM_WORD) 213 b[0] = IM_NL as u8 214 sys_write(1, b, 1) 215 return 0 216} 217 218// Compare a (buf, off, len) slice against a NUL-terminated string. 219func im_slice_eq(buf: *u8, off: i64, len: i64, s: *u8) -> i64 { 220 var i: i64 = 0 221 var ok: i64 = 1 222 while s[i] != (IM_NUL as u8) { 223 if i >= len { ok = 0 } 224 if ok == 1 { 225 if buf[off + i] != s[i] { ok = 0 } 226 } 227 i = i + 1 228 } 229 if i != len { ok = 0 } 230 return ok 231} 232 233func im_slice_eq_slice(a: *u8, ao: i64, al: i64, b: *u8, bo: i64, bl: i64) -> i64 { 234 if al != bl { return 0 } 235 var i: i64 = 0 236 var ok: i64 = 1 237 while i < al { 238 if a[ao + i] != b[bo + i] { ok = 0 } 239 i = i + 1 240 } 241 return ok 242} 243 244func im_cat_slice(d: *u8, o: i64, buf: *u8, off: i64, len: i64) -> i64 { 245 var i: i64 = 0 246 var p: i64 = o 247 while i < len { 248 d[p] = buf[off + i] 249 p = p + 1 250 i = i + 1 251 } 252 return p 253} 254 255// Print a slice. Slices are not NUL-terminated so they are copied into 256// scratch first, which keeps every emitter going through gv_puts. 257func im_puts_slice(scratch: *u8, buf: *u8, off: i64, len: i64) -> i64 { 258 var n: i64 = len 259 if n > (IM_SLICE_BYTES - 1) { n = IM_SLICE_BYTES - 1 } 260 let p: i64 = im_cat_slice(scratch, 0, buf, off, n) 261 scratch[p] = IM_NUL as u8 262 gv_puts(scratch) 263 return n 264} 265 266// ---- existence probing ----------------------------------------- 267 268func im_exists(path: *u8) -> i64 { 269 let fd: i64 = sys_openat_rd(path) 270 if fd < 0 { return 0 } 271 sys_close(fd) 272 return 1 273} 274 275// Build <root><pre><slug><suf> and return the root index it resolved 276// from, or -1. Asking all four roots is the whole point: a probe that 277// knows one tree answers a confident false negative for anything that 278// lives in the other. 279func im_probe_roots(scratch: *u8, pre: *u8, buf: *u8, off: i64, len: i64, suf: *u8) -> i64 { 280 var r: i64 = 0 281 var hit: i64 = -1 282 while r < IM_ROOTS { 283 if hit < 0 { 284 var p: i64 = gv_cat(scratch, 0, im_root(r)) 285 p = gv_cat(scratch, p, pre) 286 p = im_cat_slice(scratch, p, buf, off, len) 287 p = gv_cat(scratch, p, suf) 288 scratch[p] = IM_NUL as u8 289 if im_exists(scratch) == 1 { hit = r } 290 } 291 r = r + 1 292 } 293 return hit 294} 295 296// Read a knowledge-rooted file from whichever tree carries it. 297func im_kread(scratch: *u8, name: *u8, lenbox: *i64) -> *u8 { 298 var r: i64 = 0 299 var got: *u8 = 0 as *u8 300 while r < IM_KROOTS { 301 if (got as i64) == 0 { 302 var p: i64 = gv_cat(scratch, 0, im_kroot(r)) 303 p = gv_cat(scratch, p, name) 304 scratch[p] = IM_NUL as u8 305 got = sys_read_file(scratch, lenbox) 306 } 307 r = r + 1 308 } 309 return got 310} 311 312// ---- substring search (core-gate import detection) -------------- 313func im_contains(buf: *u8, n: i64, s: *u8) -> i64 { 314 var sl: i64 = 0 315 while s[sl] != (IM_NUL as u8) { sl = sl + 1 } 316 if sl == 0 { return 0 } 317 if sl > n { return 0 } 318 var i: i64 = 0 319 var hit: i64 = 0 320 let last: i64 = n - sl 321 while i <= last { 322 if hit == 0 { 323 var j: i64 = 0 324 var ok: i64 = 1 325 while j < sl { 326 if ok == 1 { 327 if buf[i + j] != s[j] { ok = 0 } 328 } 329 j = j + 1 330 } 331 if ok == 1 { hit = 1 } 332 } 333 i = i + 1 334 } 335 return hit 336} 337 338// Same question, asked with a slug slice rather than a literal. 339func im_contains_slug(scratch: *u8, buf: *u8, n: i64, pre: *u8, sb: *u8, so: i64, sl: i64, suf: *u8) -> i64 { 340 var p: i64 = gv_cat(scratch, 0, pre) 341 p = im_cat_slice(scratch, p, sb, so, sl) 342 p = gv_cat(scratch, p, suf) 343 scratch[p] = IM_NUL as u8 344 return im_contains(buf, n, scratch) 345} 346 347// ---- ratchet reading (READ ONLY -- the gates own these files) ---- 348// Format, identical in the shared core file and in every per-arch file: 349// one line per arch, "<slug> <passed>". Reading both through ONE 350// function is deliberate: two readers of one format is the duplicate 351// ruler defect, and they drift. 352func im_digits_at(buf: *u8, n: i64, p0: i64) -> i64 { 353 var v: i64 = 0 354 var any: i64 = 0 355 var p: i64 = p0 356 var go: i64 = 1 357 while go == 1 { 358 if p >= n { go = 0 } 359 if go == 1 { 360 let c: i64 = buf[p] & IM_BYTE_M 361 if c < IM_DIG_LO { go = 0 } 362 if go == 1 { 363 if c > IM_DIG_HI { go = 0 } 364 } 365 if go == 1 { 366 v = v * IM_B10 + (c - IM_DIG_LO) 367 any = 1 368 p = p + 1 369 } 370 } 371 } 372 if any == 0 { return -1 } 373 return v 374} 375 376func im_ratchet_score(buf: *u8, n: i64, sb: *u8, so: i64, sl: i64) -> i64 { 377 var i: i64 = 0 378 var found: i64 = -1 379 while i < n { 380 if found < 0 { 381 if (i + sl) < n { 382 if im_slice_eq_slice(buf, i, sl, sb, so, sl) == 1 { 383 if buf[i + sl] == (IM_SPACE as u8) { 384 found = im_digits_at(buf, n, i + sl + 1) 385 } 386 } 387 } 388 } 389 var adv: i64 = 1 390 while adv == 1 { 391 if i >= n { adv = 0 } 392 if adv == 1 { 393 if buf[i] == (IM_NL as u8) { adv = 0 } 394 i = i + 1 395 } 396 } 397 } 398 return found 399} 400 401// ---- box layout for the population table ----------------------- 402// Parallel arrays rather than a struct: this dialect resolves a field 403// name across every struct, so parallel arrays with named index 404// constants are the safer shape here. 405const IM_A_IDOFF: i64 = 0 406const IM_A_IDLEN: i64 = 1 407const IM_A_CLS: i64 = 2 408const IM_A_SRC: i64 = 3 409const IM_A_SOFF: i64 = 4 410const IM_A_SLEN: i64 = 5 411const IM_A_STATE: i64 = 6 412const IM_A_SCORE: i64 = 7 413const IM_A_GATE: i64 = 8 414const IM_A_EMU: i64 = 9 415const IM_A_RATSRC: i64 = 10 416const IM_A_COUNT: i64 = 11 417 418const IM_SRC_CONF: i64 = 0 419const IM_SRC_ALIAS: i64 = 1 420 421// Which ratchet a score came from, so a reader can tell the shared core 422// file from a per-arch one without opening either. 423const IM_RS_NONE: i64 = 0 424const IM_RS_PER: i64 = 1 425const IM_RS_CORE: i64 = 2 426func im_ratsrc_name(r: i64) -> *u8 { 427 if r == IM_RS_PER { return "per-arch" as *u8 } 428 if r == IM_RS_CORE { return "core-shared" as *u8 } 429 return "none" as *u8 430} 431 432func im_cell(tab: *i64, i: i64, f: i64) -> i64 { return tab[i * IM_A_COUNT + f] } 433func im_setcell(tab: *i64, i: i64, f: i64, v: i64) -> i64 { 434 tab[i * IM_A_COUNT + f] = v 435 return v 436} 437 438func im_permil(a: i64, b: i64) -> i64 { 439 if b <= 0 { return -1 } 440 return (a * IM_PERMIL) / b 441} 442 443func im_class_of(buf: *u8, off: i64, len: i64) -> i64 { 444 if im_slice_eq(buf, off, len, "cpu" as *u8) == 1 { return IM_C_CPU } 445 if im_slice_eq(buf, off, len, "mcu" as *u8) == 1 { return IM_C_MCU } 446 if im_slice_eq(buf, off, len, "gpu" as *u8) == 1 { return IM_C_GPU } 447 if im_slice_eq(buf, off, len, "accel" as *u8) == 1 { return IM_C_ACCEL } 448 if im_slice_eq(buf, off, len, "dsp" as *u8) == 1 { return IM_C_DSP } 449 if im_slice_eq(buf, off, len, "vm" as *u8) == 1 { return IM_C_VM } 450 if im_slice_eq(buf, off, len, "fpga" as *u8) == 1 { return IM_C_FPGA } 451 if im_slice_eq(buf, off, len, "legacy" as *u8) == 1 { return IM_C_LEGACY } 452 if im_slice_eq(buf, off, len, "impl" as *u8) == 1 { return IM_C_IMPL } 453 if im_slice_eq(buf, off, len, "ext" as *u8) == 1 { return IM_C_EXT } 454 if im_slice_eq(buf, off, len, "nishi" as *u8) == 1 { return IM_C_NISHI } 455 return IM_C_UNKNOWN 456} 457 458// Is this class a codegen target at all? impl and ext are not, and the 459// answer is asked ONCE here so the exclusion cannot be spelled two ways 460// in two places. 461func im_is_target(c: i64) -> i64 { 462 if c == IM_C_IMPL { return 0 } 463 if c == IM_C_EXT { return 0 } 464 return 1 465} 466 467// ---- the state decision, in ONE place -------------------------- 468// Two organs that must agree should be made unable to disagree; this 469// classifier is the single place a state is decided, so the worklist, 470// the counts and the per-row print can never drift apart. 471func im_classify(is_target: i64, score: i64, gate: i64, emu: i64) -> i64 { 472 if is_target == 0 { return IM_S_NOTARGET } 473 if score > 0 { return IM_S_GREEN } 474 if score == 0 { return IM_S_RED } 475 if gate == 1 { return IM_S_UNRUN } 476 if emu == 1 { return IM_S_EMUONLY } 477 return IM_S_DECLARED 478} 479 480// ===== main ===================================================== 481 482func main(argc: i64, argv: *i64) -> i64 { 483 gv_head("nx_isa_manager -- the master ISA manager: declared population, discovered evidence, one named state per ISA, coverage with its denominator, worklist last" as *u8) 484 let ctr: *i64 = gv_ctr() 485 486 let scratch: *u8 = sys_mmap(IM_PATH_BYTES) 487 let scr2: *u8 = sys_mmap(IM_PATH_BYTES) 488 let slice: *u8 = sys_mmap(IM_SLICE_BYTES) 489 let tab: *i64 = sys_mmap(IM_MAX_TARGETS * IM_A_COUNT * IM_WORD) as *i64 490 let alid: *i64 = sys_mmap(IM_MAX_ALIAS * IM_ALIAS_COLS * IM_WORD) as *i64 491 492 // ---- read the population ---- 493 let clen: *i64 = sys_mmap(IM_BOX_BYTES) as *i64 494 let conf: *u8 = im_kread(scratch, IM_CONF_NAME, clen) 495 var cn: i64 = 0 496 if (conf as i64) != 0 { cn = clen[0] } 497 498 gv_puts("population conf: " as *u8) 499 gv_puts(IM_CONF_NAME) 500 gv_puts(" bytes=" as *u8) 501 gv_num(cn) 502 im_nl() 503 504 // ---- read the alias table (optional DATA) ---- 505 let alen: *i64 = sys_mmap(IM_BOX_BYTES) as *i64 506 let abuf: *u8 = im_kread(scratch, IM_ALIAS_NAME, alen) 507 var an: i64 = 0 508 if (abuf as i64) != 0 { an = alen[0] } 509 var alias_rows: i64 = 0 510 var alias_over: i64 = 0 511 512 var i: i64 = 0 513 while i < an { 514 let als: i64 = i 515 var ale: i64 = i 516 var asc: i64 = 1 517 while asc == 1 { 518 if ale >= an { asc = 0 } 519 if asc == 1 { 520 if abuf[ale] == (IM_NL as u8) { asc = 0 } 521 if asc == 1 { ale = ale + 1 } 522 } 523 } 524 var alend: i64 = ale 525 if alend > als { 526 if abuf[alend - 1] == (IM_CR as u8) { alend = alend - 1 } 527 } 528 if im_slice_eq(abuf, als, IM_ALIAS_TAG, "alias|" as *u8) == 1 { 529 let aido: i64 = als + IM_ALIAS_TAG 530 var q: i64 = aido 531 var aidl: i64 = -1 532 while q < alend { 533 if aidl < 0 { 534 if abuf[q] == (IM_PIPE as u8) { aidl = q - aido } 535 } 536 q = q + 1 537 } 538 if aidl > 0 { 539 let aslo: i64 = aido + aidl + 1 540 var q2: i64 = aslo 541 var asll: i64 = -1 542 while q2 < alend { 543 if asll < 0 { 544 if abuf[q2] == (IM_PIPE as u8) { asll = q2 - aslo } 545 } 546 q2 = q2 + 1 547 } 548 if asll < 0 { asll = alend - aslo } 549 if asll > 0 { 550 if alias_rows < IM_MAX_ALIAS { 551 alid[alias_rows * IM_ALIAS_COLS] = aido 552 alid[alias_rows * IM_ALIAS_COLS + 1] = aidl 553 alid[alias_rows * IM_ALIAS_COLS + 2] = aslo 554 alid[alias_rows * IM_ALIAS_COLS + 3] = asll 555 alias_rows = alias_rows + 1 556 } 557 if alias_rows >= IM_MAX_ALIAS { alias_over = 1 } 558 } 559 } 560 } 561 i = ale + 1 562 } 563 564 gv_puts("alias conf: " as *u8) 565 gv_puts(IM_ALIAS_NAME) 566 gv_puts(" bytes=" as *u8) 567 gv_num(an) 568 gv_puts(" rows=" as *u8) 569 gv_num(alias_rows) 570 if an == 0 { 571 gv_puts(" ABSENT -- every id resolves to itself, which is the default and not an error" as *u8) 572 } 573 im_nl() 574 575 // ---- read the core gate source and the shared ratchet ---- 576 var core_n: i64 = 0 577 var core_root: i64 = -1 578 var core: *u8 = 0 as *u8 579 let corelen: *i64 = sys_mmap(IM_BOX_BYTES) as *i64 580 var rr: i64 = 0 581 while rr < IM_ROOTS { 582 if (core as i64) == 0 { 583 var cp: i64 = gv_cat(scratch, 0, im_root(rr)) 584 cp = gv_cat(scratch, cp, IM_CORE_GATE) 585 scratch[cp] = IM_NUL as u8 586 core = sys_read_file(scratch, corelen) 587 if (core as i64) != 0 { core_root = rr } 588 } 589 rr = rr + 1 590 } 591 if (core as i64) != 0 { core_n = corelen[0] } 592 593 gv_puts("core gate: " as *u8) 594 gv_puts(IM_CORE_GATE) 595 gv_puts(" bytes=" as *u8) 596 gv_num(core_n) 597 gv_puts(" root=" as *u8) 598 if core_root >= 0 { gv_puts(im_root(core_root)) } 599 if core_root < 0 { gv_puts("UNRESOLVED-in-all-4-roots" as *u8) } 600 im_nl() 601 602 let crlen: *i64 = sys_mmap(IM_BOX_BYTES) as *i64 603 let cratch: *u8 = im_kread(scratch, IM_CORE_RATCH, crlen) 604 var crn: i64 = 0 605 if (cratch as i64) != 0 { crn = crlen[0] } 606 gv_puts("shared ratchet: " as *u8) 607 gv_puts(IM_CORE_RATCH) 608 gv_puts(" bytes=" as *u8) 609 gv_num(crn) 610 gv_puts(" READ-ONLY here: the gates own it" as *u8) 611 im_nl() 612 im_nl() 613 614 // ---- parse the population ---- 615 var n: i64 = 0 616 var malformed: i64 = 0 617 var isa_lines: i64 = 0 618 var over_cap: i64 = 0 619 620 i = 0 621 while i < cn { 622 let ls: i64 = i 623 var le: i64 = i 624 var sc: i64 = 1 625 while sc == 1 { 626 if le >= cn { sc = 0 } 627 if sc == 1 { 628 if conf[le] == (IM_NL as u8) { sc = 0 } 629 if sc == 1 { le = le + 1 } 630 } 631 } 632 var lend: i64 = le 633 if lend > ls { 634 if conf[lend - 1] == (IM_CR as u8) { lend = lend - 1 } 635 } 636 if im_slice_eq(conf, ls, IM_ISA_TAG, "isa|" as *u8) == 1 { 637 isa_lines = isa_lines + 1 638 var fo: i64 = ls + IM_ISA_TAG 639 var fields: i64 = 1 640 let ido: i64 = fo 641 var idl: i64 = -1 642 var clo: i64 = -1 643 var cll: i64 = -1 644 var p: i64 = fo 645 while p <= lend { 646 var atend: i64 = 0 647 if p == lend { atend = 1 } 648 if atend == 0 { 649 if conf[p] == (IM_PIPE as u8) { atend = 1 } 650 } 651 if atend == 1 { 652 if fields == 1 { idl = p - fo } 653 if fields == 3 { 654 clo = fo 655 cll = p - fo 656 } 657 fields = fields + 1 658 fo = p + 1 659 } 660 p = p + 1 661 } 662 let nfields: i64 = fields - 1 663 var good: i64 = 1 664 if nfields != IM_FIELDS_AFTER_TAG { good = 0 } 665 if idl <= 0 { good = 0 } 666 if cll <= 0 { good = 0 } 667 if good == 0 { malformed = malformed + 1 } 668 if good == 1 { 669 if n < IM_MAX_TARGETS { 670 im_setcell(tab, n, IM_A_IDOFF, ido) 671 im_setcell(tab, n, IM_A_IDLEN, idl) 672 im_setcell(tab, n, IM_A_CLS, im_class_of(conf, clo, cll)) 673 im_setcell(tab, n, IM_A_SRC, IM_SRC_CONF) 674 im_setcell(tab, n, IM_A_SOFF, ido) 675 im_setcell(tab, n, IM_A_SLEN, idl) 676 im_setcell(tab, n, IM_A_STATE, IM_S_UNSET) 677 im_setcell(tab, n, IM_A_SCORE, -1) 678 im_setcell(tab, n, IM_A_GATE, 0) 679 im_setcell(tab, n, IM_A_EMU, 0) 680 im_setcell(tab, n, IM_A_RATSRC, IM_RS_NONE) 681 n = n + 1 682 } 683 if n >= IM_MAX_TARGETS { over_cap = 1 } 684 } 685 } 686 i = le + 1 687 } 688 689 // ---- resolve slugs from the alias table ---- 690 var aliased: i64 = 0 691 var alias_unknown: i64 = 0 692 var ai: i64 = 0 693 while ai < alias_rows { 694 let aio: i64 = alid[ai * IM_ALIAS_COLS] 695 let ail: i64 = alid[ai * IM_ALIAS_COLS + 1] 696 let aso: i64 = alid[ai * IM_ALIAS_COLS + 2] 697 let asl: i64 = alid[ai * IM_ALIAS_COLS + 3] 698 var matched: i64 = 0 699 var t: i64 = 0 700 while t < n { 701 if im_slice_eq_slice(conf, im_cell(tab, t, IM_A_IDOFF), im_cell(tab, t, IM_A_IDLEN), abuf, aio, ail) == 1 { 702 im_setcell(tab, t, IM_A_SRC, IM_SRC_ALIAS) 703 im_setcell(tab, t, IM_A_SOFF, aso) 704 im_setcell(tab, t, IM_A_SLEN, asl) 705 matched = 1 706 } 707 t = t + 1 708 } 709 if matched == 1 { aliased = aliased + 1 } 710 if matched == 0 { 711 alias_unknown = alias_unknown + 1 712 gv_puts("ALIAS-ID-NOT-IN-POPULATION " as *u8) 713 im_puts_slice(slice, abuf, aio, ail) 714 gv_puts(" an alias for an undeclared id silently hides a target" as *u8) 715 im_nl() 716 } 717 ai = ai + 1 718 } 719 720 // ---- probe evidence and classify ---- 721 var t2: i64 = 0 722 while t2 < n { 723 let cls: i64 = im_cell(tab, t2, IM_A_CLS) 724 let istgt: i64 = im_is_target(cls) 725 if istgt == 1 { 726 var sb: *u8 = conf 727 if im_cell(tab, t2, IM_A_SRC) == IM_SRC_ALIAS { sb = abuf } 728 let so: i64 = im_cell(tab, t2, IM_A_SOFF) 729 let sl: i64 = im_cell(tab, t2, IM_A_SLEN) 730 731 let emur: i64 = im_probe_roots(scratch, IM_EMU_PRE, sb, so, sl, IM_NX_SUF) 732 var emu: i64 = 0 733 if emur >= 0 { emu = 1 } 734 735 let gr: i64 = im_probe_roots(scratch, IM_GATE_PRE, sb, so, sl, IM_GATE_SUF) 736 var gate: i64 = 0 737 if gr >= 0 { gate = 1 } 738 // A gate need not be a separate file: the core gate imports 739 // the emulators it measures, so its own source is evidence. 740 if gate == 0 { 741 if core_n > 0 { 742 if im_contains_slug(scr2, core, core_n, IM_EMU_PRE, sb, so, sl, IM_NX_SUF) == 1 { gate = 1 } 743 } 744 } 745 746 // score: per-arch ratchet first, shared core ratchet second. 747 var score: i64 = -1 748 var rsrc: i64 = IM_RS_NONE 749 let prl: *i64 = sys_mmap(IM_BOX_BYTES) as *i64 750 var rp: i64 = gv_cat(scratch, 0, IM_RATCH_PRE) 751 rp = im_cat_slice(scratch, rp, sb, so, sl) 752 rp = gv_cat(scratch, rp, IM_RATCH_SUF) 753 scratch[rp] = IM_NUL as u8 754 let pr: *u8 = im_kread(scr2, scratch, prl) 755 if (pr as i64) != 0 { 756 let prn: i64 = prl[0] 757 let s2: i64 = im_ratchet_score(pr, prn, sb, so, sl) 758 if s2 >= 0 { 759 score = s2 760 rsrc = IM_RS_PER 761 } 762 } 763 if score < 0 { 764 if crn > 0 { 765 let s3: i64 = im_ratchet_score(cratch, crn, sb, so, sl) 766 if s3 >= 0 { 767 score = s3 768 rsrc = IM_RS_CORE 769 } 770 } 771 } 772 773 im_setcell(tab, t2, IM_A_EMU, emu) 774 im_setcell(tab, t2, IM_A_GATE, gate) 775 im_setcell(tab, t2, IM_A_SCORE, score) 776 im_setcell(tab, t2, IM_A_RATSRC, rsrc) 777 im_setcell(tab, t2, IM_A_STATE, im_classify(1, score, gate, emu)) 778 } 779 if istgt == 0 { 780 im_setcell(tab, t2, IM_A_STATE, im_classify(0, -1, 0, 0)) 781 } 782 t2 = t2 + 1 783 } 784 785 // ---- CLASS PARTITION ---- 786 let ccnt: *i64 = sys_mmap(IM_C_COUNT * IM_WORD) as *i64 787 var ci: i64 = 0 788 while ci < IM_C_COUNT { 789 ccnt[ci] = 0 790 ci = ci + 1 791 } 792 var t3: i64 = 0 793 while t3 < n { 794 let c: i64 = im_cell(tab, t3, IM_A_CLS) 795 ccnt[c] = ccnt[c] + 1 796 t3 = t3 + 1 797 } 798 var csum: i64 = 0 799 gv_puts("=== CLASS PARTITION (a partition is a claim: the parts must sum) ===" as *u8) 800 im_nl() 801 ci = 0 802 while ci < IM_C_COUNT { 803 if ccnt[ci] > 0 { 804 gv_puts(" class " as *u8) 805 gv_puts(im_class_name(ci)) 806 gv_puts(" = " as *u8) 807 gv_num(ccnt[ci]) 808 if im_is_target(ci) == 0 { gv_puts(" NOT A CODEGEN TARGET: excluded from every emulator and gate ratio" as *u8) } 809 im_nl() 810 } 811 csum = csum + ccnt[ci] 812 ci = ci + 1 813 } 814 gv_puts(" class parts sum = " as *u8) 815 gv_num(csum) 816 gv_puts(" rows parsed = " as *u8) 817 gv_num(n) 818 gv_puts(" isa-tagged lines seen = " as *u8) 819 gv_num(isa_lines) 820 gv_puts(" malformed = " as *u8) 821 gv_num(malformed) 822 im_nl() 823 im_nl() 824 825 // ---- STATE PARTITION ---- 826 let scnt: *i64 = sys_mmap((IM_S_COUNT + 1) * IM_WORD) as *i64 827 var si: i64 = 0 828 while si < IM_S_COUNT { 829 scnt[si] = 0 830 si = si + 1 831 } 832 var unset: i64 = 0 833 var t4: i64 = 0 834 while t4 < n { 835 let s: i64 = im_cell(tab, t4, IM_A_STATE) 836 if s == IM_S_UNSET { unset = unset + 1 } 837 if s != IM_S_UNSET { scnt[s] = scnt[s] + 1 } 838 t4 = t4 + 1 839 } 840 var ssum: i64 = unset 841 gv_puts("=== PER-ISA STATE PARTITION (every row gets exactly one NAMED state) ===" as *u8) 842 im_nl() 843 si = 0 844 while si < IM_S_COUNT { 845 gv_puts(" " as *u8) 846 gv_puts(im_state_name(si)) 847 gv_puts(" = " as *u8) 848 gv_num(scnt[si]) 849 gv_puts(" " as *u8) 850 gv_puts(im_state_meaning(si)) 851 im_nl() 852 ssum = ssum + scnt[si] 853 si = si + 1 854 } 855 gv_puts(" UNSET (classifier did not reach) = " as *u8) 856 gv_num(unset) 857 im_nl() 858 gv_puts(" state parts sum = " as *u8) 859 gv_num(ssum) 860 gv_puts(" rows parsed = " as *u8) 861 gv_num(n) 862 im_nl() 863 im_nl() 864 865 // ---- COVERAGE WITH ITS DENOMINATOR ---- 866 let targetable: i64 = n - scnt[IM_S_NOTARGET] 867 var with_emu: i64 = 0 868 var with_gate: i64 = 0 869 var measured: i64 = 0 870 var banked_total: i64 = 0 871 var t5: i64 = 0 872 while t5 < n { 873 if im_is_target(im_cell(tab, t5, IM_A_CLS)) == 1 { 874 if im_cell(tab, t5, IM_A_EMU) == 1 { with_emu = with_emu + 1 } 875 if im_cell(tab, t5, IM_A_GATE) == 1 { with_gate = with_gate + 1 } 876 if im_cell(tab, t5, IM_A_SCORE) >= 0 { 877 measured = measured + 1 878 banked_total = banked_total + im_cell(tab, t5, IM_A_SCORE) 879 } 880 } 881 t5 = t5 + 1 882 } 883 884 // Distinct emulator SLUGS, not rows. A reference count is not a work 885 // count: two ids aliased onto one emulator would read as two covered 886 // targets from one organ, and only the distinct count exposes that. 887 var distinct_emu: i64 = 0 888 var t6: i64 = 0 889 while t6 < n { 890 if im_is_target(im_cell(tab, t6, IM_A_CLS)) == 1 { 891 if im_cell(tab, t6, IM_A_EMU) == 1 { 892 var seen: i64 = 0 893 var u: i64 = 0 894 while u < t6 { 895 if im_is_target(im_cell(tab, u, IM_A_CLS)) == 1 { 896 if im_cell(tab, u, IM_A_EMU) == 1 { 897 var ab: *u8 = conf 898 if im_cell(tab, u, IM_A_SRC) == IM_SRC_ALIAS { ab = abuf } 899 var bb: *u8 = conf 900 if im_cell(tab, t6, IM_A_SRC) == IM_SRC_ALIAS { bb = abuf } 901 if im_slice_eq_slice(ab, im_cell(tab, u, IM_A_SOFF), im_cell(tab, u, IM_A_SLEN), bb, im_cell(tab, t6, IM_A_SOFF), im_cell(tab, t6, IM_A_SLEN)) == 1 { seen = 1 } 902 } 903 } 904 u = u + 1 905 } 906 if seen == 0 { distinct_emu = distinct_emu + 1 } 907 } 908 } 909 t6 = t6 + 1 910 } 911 912 gv_puts("=== COVERAGE (the denominator travels with every ratio) ===" as *u8) 913 im_nl() 914 gv_puts(" population rows = " as *u8) 915 gv_num(n) 916 im_nl() 917 gv_puts(" NOT-A-TARGET (impl + ext) = " as *u8) 918 gv_num(scnt[IM_S_NOTARGET]) 919 gv_puts(" excluded from every ratio below" as *u8) 920 im_nl() 921 gv_puts(" TARGETABLE denominator = " as *u8) 922 gv_num(targetable) 923 im_nl() 924 gv_puts(" with an emulator = " as *u8) 925 gv_num(with_emu) 926 gv_puts(" of " as *u8) 927 gv_num(targetable) 928 gv_puts(" permil=" as *u8) 929 gv_num(im_permil(with_emu, targetable)) 930 im_nl() 931 gv_puts(" distinct emulator slugs = " as *u8) 932 gv_num(distinct_emu) 933 gv_puts(" a reference count is not a work count" as *u8) 934 im_nl() 935 gv_puts(" covered by a gate = " as *u8) 936 gv_num(with_gate) 937 gv_puts(" of " as *u8) 938 gv_num(targetable) 939 gv_puts(" permil=" as *u8) 940 gv_num(im_permil(with_gate, targetable)) 941 im_nl() 942 gv_puts(" MEASURED (a banked score) = " as *u8) 943 gv_num(measured) 944 gv_puts(" of " as *u8) 945 gv_num(targetable) 946 gv_puts(" permil=" as *u8) 947 gv_num(im_permil(measured, targetable)) 948 im_nl() 949 im_nl() 950 951 // ---- PER-CLASS COVERAGE ---- 952 gv_puts("=== COVERAGE BY CLASS (measured / with-emulator / rows) ===" as *u8) 953 im_nl() 954 ci = 0 955 while ci < IM_C_COUNT { 956 if ccnt[ci] > 0 { 957 var cm: i64 = 0 958 var ce: i64 = 0 959 var t7: i64 = 0 960 while t7 < n { 961 if im_cell(tab, t7, IM_A_CLS) == ci { 962 if im_cell(tab, t7, IM_A_SCORE) >= 0 { cm = cm + 1 } 963 if im_cell(tab, t7, IM_A_EMU) == 1 { ce = ce + 1 } 964 } 965 t7 = t7 + 1 966 } 967 gv_puts(" " as *u8) 968 gv_puts(im_class_name(ci)) 969 gv_puts(" measured=" as *u8) 970 gv_num(cm) 971 gv_puts(" emulated=" as *u8) 972 gv_num(ce) 973 gv_puts(" rows=" as *u8) 974 gv_num(ccnt[ci]) 975 if im_is_target(ci) == 0 { gv_puts(" NOT-A-TARGET class: zeros here are correct, not a gap" as *u8) } 976 im_nl() 977 } 978 ci = ci + 1 979 } 980 im_nl() 981 982 // ---- RATCHET LEVELS (read, never written) ---- 983 gv_puts("=== BANKED RATCHET SCORES (good-when-higher; the gates own these files) ===" as *u8) 984 im_nl() 985 gv_puts(" A ratchet file holds a LEVEL. A level cannot express a trajectory:" as *u8) 986 im_nl() 987 gv_puts(" one reading gives a number, two readings say whether the estate is climbing." as *u8) 988 im_nl() 989 gv_puts(" banked_total is the single scalar to watch across runs." as *u8) 990 im_nl() 991 var t8: i64 = 0 992 while t8 < n { 993 if im_cell(tab, t8, IM_A_SCORE) >= 0 { 994 gv_puts(" " as *u8) 995 im_puts_slice(slice, conf, im_cell(tab, t8, IM_A_IDOFF), im_cell(tab, t8, IM_A_IDLEN)) 996 gv_puts(" banked=" as *u8) 997 gv_num(im_cell(tab, t8, IM_A_SCORE)) 998 gv_puts(" from=" as *u8) 999 gv_puts(im_ratsrc_name(im_cell(tab, t8, IM_A_RATSRC))) 1000 im_nl() 1001 } 1002 t8 = t8 + 1 1003 } 1004 gv_puts(" banked_total = " as *u8) 1005 gv_num(banked_total) 1006 gv_puts(" over " as *u8) 1007 gv_num(measured) 1008 gv_puts(" measured architectures" as *u8) 1009 im_nl() 1010 im_nl() 1011 1012 // ---- PER-ISA TABLE ---- 1013 gv_puts("=== PER-ISA STATE (id class slug emu gate score STATE) ===" as *u8) 1014 im_nl() 1015 var t9: i64 = 0 1016 while t9 < n { 1017 gv_puts(" " as *u8) 1018 im_puts_slice(slice, conf, im_cell(tab, t9, IM_A_IDOFF), im_cell(tab, t9, IM_A_IDLEN)) 1019 gv_puts(" " as *u8) 1020 gv_puts(im_class_name(im_cell(tab, t9, IM_A_CLS))) 1021 gv_puts(" slug=" as *u8) 1022 var sb2: *u8 = conf 1023 if im_cell(tab, t9, IM_A_SRC) == IM_SRC_ALIAS { sb2 = abuf } 1024 im_puts_slice(slice, sb2, im_cell(tab, t9, IM_A_SOFF), im_cell(tab, t9, IM_A_SLEN)) 1025 if im_cell(tab, t9, IM_A_SRC) == IM_SRC_ALIAS { gv_puts("(alias)" as *u8) } 1026 gv_puts(" emu=" as *u8) 1027 gv_num(im_cell(tab, t9, IM_A_EMU)) 1028 gv_puts(" gate=" as *u8) 1029 gv_num(im_cell(tab, t9, IM_A_GATE)) 1030 gv_puts(" score=" as *u8) 1031 gv_num(im_cell(tab, t9, IM_A_SCORE)) 1032 gv_puts(" " as *u8) 1033 gv_puts(im_state_name(im_cell(tab, t9, IM_A_STATE))) 1034 im_nl() 1035 t9 = t9 + 1 1036 } 1037 im_nl() 1038 1039 // ---- TEETH: structural only ---- 1040 gv_puts("=== TEETH (structural: what THIS organ controls, never the health of an ISA) ===" as *u8) 1041 im_nl() 1042 1043 gv_check("fixture-reached-population-conf-is-nonempty" as *u8, cn > 0, ctr) 1044 gv_check("fixture-reached-rows-were-parsed" as *u8, n > 0, ctr) 1045 gv_check("class-partition-sums-to-rows-parsed" as *u8, csum == n, ctr) 1046 gv_check("isa-lines-reconcile-parsed-plus-malformed" as *u8, isa_lines == (n + malformed), ctr) 1047 gv_check("state-partition-sums-to-rows-parsed" as *u8, ssum == n, ctr) 1048 gv_check("every-row-got-exactly-one-named-state" as *u8, unset == 0, ctr) 1049 gv_check("no-silent-cap-on-the-population-table" as *u8, over_cap == 0, ctr) 1050 gv_check("no-silent-cap-on-the-alias-table" as *u8, alias_over == 0, ctr) 1051 gv_check("every-alias-id-exists-in-the-population" as *u8, alias_unknown == 0, ctr) 1052 gv_check("core-gate-source-resolved-in-some-root" as *u8, core_n > 0, ctr) 1053 gv_check("discovery-found-at-least-the-known-gate-floor" as *u8, with_gate >= IM_GATE_FLOOR, ctr) 1054 gv_check("discovery-found-at-least-the-known-emulator-floor" as *u8, distinct_emu >= IM_EMU_FLOOR, ctr) 1055 1056 // Negative control: a slug that cannot exist must NOT probe present. 1057 // Without it a probe that returned 1 for everything would score a 1058 // perfect discovery and every ISA would read covered. 1059 let bogus: *u8 = "zzz_no_such_isa_qq" as *u8 1060 var bl: i64 = 0 1061 while bogus[bl] != (IM_NUL as u8) { bl = bl + 1 } 1062 let bogus_emu: i64 = im_probe_roots(scratch, IM_EMU_PRE, bogus, 0, bl, IM_NX_SUF) 1063 let bogus_gate: i64 = im_probe_roots(scratch, IM_GATE_PRE, bogus, 0, bl, IM_GATE_SUF) 1064 gv_check("neg-control-absent-slug-must-not-resolve-an-emulator" as *u8, bogus_emu < 0, ctr) 1065 gv_check("neg-control-absent-slug-must-not-resolve-a-gate" as *u8, bogus_gate < 0, ctr) 1066 1067 // Negative control on the classifier: impl/ext short-circuits ahead 1068 // of every evidence test, so evidence can never promote a non-target. 1069 gv_check("neg-control-not-a-target-outranks-every-evidence-axis" as *u8, im_classify(0, 99, 1, 1) == IM_S_NOTARGET, ctr) 1070 gv_check("neg-control-a-zero-score-is-RED-not-UNRUN" as *u8, im_classify(1, 0, 1, 1) == IM_S_RED, ctr) 1071 gv_check("neg-control-no-evidence-is-DECLARED-ONLY" as *u8, im_classify(1, -1, 0, 0) == IM_S_DECLARED, ctr) 1072 1073 // The manager must not write the ratchet the gates own. Measured by 1074 // re-reading it and comparing CONTENT -- size is never an identity, 1075 // and a same-size rewrite is exactly what a size guard misses. 1076 let cr2len: *i64 = sys_mmap(IM_BOX_BYTES) as *i64 1077 let cratch2: *u8 = im_kread(scratch, IM_CORE_RATCH, cr2len) 1078 var same: i64 = 0 1079 // BOTH ABSENT IS UNCHANGED. The first cut of this tooth failed 1080 // whenever the ratchet did not exist, which reads as "the manager 1081 // wrote it" -- an instrument that cannot observe must not convict. 1082 // Caught by running the organ against a tree with no knowledge dir. 1083 if (cratch as i64) == 0 { 1084 if (cratch2 as i64) == 0 { same = 1 } 1085 } 1086 if (cratch2 as i64) != 0 { 1087 if cr2len[0] == crn { 1088 var eq: i64 = 1 1089 var z: i64 = 0 1090 while z < crn { 1091 if cratch[z] != cratch2[z] { eq = 0 } 1092 z = z + 1 1093 } 1094 same = eq 1095 } 1096 } 1097 gv_puts(" ratchet before=" as *u8) 1098 gv_num(crn) 1099 gv_puts("B after=" as *u8) 1100 if (cratch2 as i64) != 0 { gv_num(cr2len[0]) } 1101 if (cratch2 as i64) == 0 { gv_puts("ABSENT" as *u8) } 1102 gv_puts("B identical=" as *u8) 1103 gv_num(same) 1104 im_nl() 1105 gv_check("ratchet-content-unchanged-by-this-run" as *u8, same == 1, ctr) 1106 1107 im_nl() 1108 1109 // ---- WORKLIST LAST. A count without a worklist is not actionable, 1110 // and a worklist printed in the body is lost the moment a caller 1111 // tails the output. 1112 gv_puts("=== WORKLIST (the named ISAs in each actionable state) ===" as *u8) 1113 im_nl() 1114 var ws: i64 = 0 1115 while ws < IM_S_COUNT { 1116 var actionable: i64 = 1 1117 if ws == IM_S_GREEN { actionable = 0 } 1118 if ws == IM_S_NOTARGET { actionable = 0 } 1119 if actionable == 1 { 1120 gv_puts("[" as *u8) 1121 gv_puts(im_state_name(ws)) 1122 gv_puts("] n=" as *u8) 1123 gv_num(scnt[ws]) 1124 gv_puts(" remedy: " as *u8) 1125 if ws == IM_S_RED { gv_puts("the emulator runs and computes the wrong answer -- fix the emulator, its gate already names which KAT" as *u8) } 1126 if ws == IM_S_UNRUN { gv_puts("a gate covers it but banks no score -- run the gate and let it write knowledge/status/isa_<slug>.ratchet" as *u8) } 1127 if ws == IM_S_EMUONLY { gv_puts("an emulator exists and nothing rules on it -- write nx_isa_<slug>_gate.nx with KATs taken from the ISA manual" as *u8) } 1128 if ws == IM_S_DECLARED { gv_puts("the frontier -- write nx_emu_<slug>.nx, then its gate. This is the largest class and it is supposed to be" as *u8) } 1129 im_nl() 1130 var wt: i64 = 0 1131 while wt < n { 1132 if im_cell(tab, wt, IM_A_STATE) == ws { 1133 gv_puts(" " as *u8) 1134 im_puts_slice(slice, conf, im_cell(tab, wt, IM_A_IDOFF), im_cell(tab, wt, IM_A_IDLEN)) 1135 gv_puts(" (" as *u8) 1136 gv_puts(im_class_name(im_cell(tab, wt, IM_A_CLS))) 1137 gv_puts(")" as *u8) 1138 im_nl() 1139 } 1140 wt = wt + 1 1141 } 1142 } 1143 ws = ws + 1 1144 } 1145 im_nl() 1146 1147 return gv_verdict("nx_isa_manager" as *u8, ctr, "structural teeth only: a manager that went RED because an ISA is incomplete would be RED the day it shipped and every day after, so the numbers above are the work and this verdict is only the fence" as *u8) 1148}