code wiki / _hdl_build / nx_fab_slice_test.nx

nx_fab_slice_test.nx source

↩ module page · 124 lines · 6033 B

1// nx_fab_slice_test.nx -- ACCEPTANCE GATE for nx_fab_slice (the Engineer's test of the tutored module). 2// KATs are EXACT-INTEGER by construction: the test triangle (0,0,0)-(10mm,0,10mm)-(0,10mm,10mm) cut at 3// z=5mm intersects at exactly (5.000, 0.000) and (0.000, 5.000) -- no float, no tolerance, no ambiguity. 4// f32 KATs are IEEE-754 ground-truth bit patterns (1.0f, 10.0f, -pi) decoded by hand-checked math. 5// A synthetic binary STL (1 triangle, 134 bytes) is built in memory byte-for-byte per the STL spec. 6// license_tier: ORIGINAL 7import "nx_fab_slice.nx" 8import "nx_syscalls.nx" 9 10func ft_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 11func ft_putn(v: i64) -> i64 { let bb: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) } let t: *u8 = sys_mmap(28); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 } while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } var i: i64 = 0; while i < k { bb[i] = t[k-1-i]; i = i + 1 } sys_write(1, bb, k); return 0 } 12 13// write u32 little-endian (test-local STL builder helper) 14func ft_w32(b: *u8, off: i64, v: i64) -> i64 { 15 b[off] = (v % 256) as u8 16 b[off+1] = ((v / 256) % 256) as u8 17 b[off+2] = ((v / 65536) % 256) as u8 18 b[off+3] = ((v / 16777216) % 256) as u8 19 return 4 20} 21 22func main() -> i64 { 23 var pass: i64 = 0 24 var total: i64 = 0 25 26 // T1: f32 1.0 (0x3F800000) -> 1000 um 27 total = total + 1 28 if ff32_to_um(1065353216) == 1000 { pass = pass + 1 } 29 if ff32_to_um(1065353216) != 1000 { ft_puts("T1 FAIL ff32(1.0)=" as *u8); ft_putn(ff32_to_um(1065353216)); ft_puts("\n" as *u8) } 30 31 // T2: f32 -pi (0xC0490FDB = 3226013659) -> -3142 um (13176795*2^-22 mm = 3141.5927 um, round-nearest) 32 total = total + 1 33 if ff32_to_um(3226013659) == 0 - 3142 { pass = pass + 1 } 34 if ff32_to_um(3226013659) != 0 - 3142 { ft_puts("T2 FAIL ff32(-pi)=" as *u8); ft_putn(ff32_to_um(3226013659)); ft_puts("\n" as *u8) } 35 36 // T3: f32 0.0 -> 0 ; f32 10.0 (0x41200000) -> 10000 ; f32 0.5 (0x3F000000) -> 500 37 total = total + 1 38 var t3: i64 = 1 39 if ff32_to_um(0) != 0 { t3 = 0 } 40 if ff32_to_um(1092616192) != 10000 { t3 = 0 } 41 if ff32_to_um(1056964608) != 500 { t3 = 0 } 42 if t3 == 1 { pass = pass + 1 } 43 if t3 == 0 { ft_puts("T3 FAIL\n" as *u8) } 44 45 // build the synthetic binary STL: 80B zero header, count=1, normal=0, 3 vertices, attr=0 46 // v0=(0,0,0) v1=(10.0, 0, 10.0) v2=(0, 10.0, 10.0) (mm as f32 bit patterns; mmap is zero-filled) 47 let stl: *u8 = sys_mmap(256) 48 // tri record at 84: normal 84-95, v0 96-107, v1 108-119, v2 120-131, attr 132-133 49 ft_w32(stl, 80, 1) // triangle count 50 ft_w32(stl, 108, 1092616192) // v1.x = 10.0f 51 ft_w32(stl, 116, 1092616192) // v1.z = 10.0f 52 ft_w32(stl, 124, 1092616192) // v2.y = 10.0f 53 ft_w32(stl, 128, 1092616192) // v2.z = 10.0f 54 55 // T4: tri count parses 56 total = total + 1 57 if fstl_tri_count(stl) == 1 { pass = pass + 1 } 58 if fstl_tri_count(stl) != 1 { ft_puts("T4 FAIL count=" as *u8); ft_putn(fstl_tri_count(stl)); ft_puts("\n" as *u8) } 59 60 // T5: vertex micrometers parse from raw STL bytes 61 total = total + 1 62 var t5: i64 = 1 63 if fstl_vert_um(stl, 0, 0, 0) != 0 { t5 = 0 } 64 if fstl_vert_um(stl, 0, 1, 0) != 10000 { t5 = 0 } 65 if fstl_vert_um(stl, 0, 1, 2) != 10000 { t5 = 0 } 66 if fstl_vert_um(stl, 0, 2, 1) != 10000 { t5 = 0 } 67 if fstl_vert_um(stl, 0, 2, 2) != 10000 { t5 = 0 } 68 if t5 == 1 { pass = pass + 1 } 69 if t5 == 0 { ft_puts("T5 FAIL\n" as *u8) } 70 71 // T6: slice at z=5mm -> exactly 2 points: (5000,0) and (0,5000) 72 total = total + 1 73 let tri: *i64 = sys_mmap(128) as *i64 74 fstl_tri_um(stl, 0, tri) 75 let seg: *i64 = sys_mmap(64) as *i64 76 let np: i64 = fslice_tri(tri, 5000, seg) 77 var t6: i64 = 1 78 if np != 2 { t6 = 0 } 79 if seg[0] != 5000 { t6 = 0 } 80 if seg[1] != 0 { t6 = 0 } 81 if seg[2] != 0 { t6 = 0 } 82 if seg[3] != 5000 { t6 = 0 } 83 if t6 == 1 { pass = pass + 1 } 84 if t6 == 0 { ft_puts("T6 FAIL np=" as *u8); ft_putn(np); ft_puts(" p0=" as *u8); ft_putn(seg[0]); ft_puts("," as *u8); ft_putn(seg[1]); ft_puts(" p1=" as *u8); ft_putn(seg[2]); ft_puts("," as *u8); ft_putn(seg[3]); ft_puts("\n" as *u8) } 85 86 // T7: plane above the triangle (z=20mm) -> 0 points; plane below (z=-1mm) -> 0 points 87 total = total + 1 88 var t7: i64 = 1 89 if fslice_tri(tri, 20000, seg) != 0 { t7 = 0 } 90 if fslice_tri(tri, 0 - 1000, seg) != 0 { t7 = 0 } 91 if t7 == 1 { pass = pass + 1 } 92 if t7 == 0 { ft_puts("T7 FAIL\n" as *u8) } 93 94 // T8: G-code emit, byte-exact: "G0 X5.000 Y0.000\nG1 X0.000 Y5.000\n" (34 bytes) 95 total = total + 1 96 let gc: *u8 = sys_mmap(256) 97 let glen: i64 = fgcode_emit(seg, 2, gc) 98 let exp: *u8 = "G0 X5.000 Y0.000\nG1 X0.000 Y5.000\n" as *u8 99 var t8: i64 = 1 100 if glen != 34 { t8 = 0 } 101 var gi: i64 = 0 102 while gi < 34 { if gc[gi] != exp[gi] { t8 = 0 } gi = gi + 1 } 103 if t8 == 1 { pass = pass + 1 } 104 if t8 == 0 { ft_puts("T8 FAIL len=" as *u8); ft_putn(glen); ft_puts(" got=" as *u8); sys_write(1, gc, glen); ft_puts("\n" as *u8) } 105 106 // T9: negative coordinate G-code ("-2.500") -- sign + zero-pad path 107 total = total + 1 108 let npts: *i64 = sys_mmap(32) as *i64 109 npts[0] = 0 - 2500; npts[1] = 750 110 let gc2: *u8 = sys_mmap(64) 111 let gl2: i64 = fgcode_emit(npts, 1, gc2) 112 let exp2: *u8 = "G0 X-2.500 Y0.750\n" as *u8 113 var t9: i64 = 1 114 if gl2 != 18 { t9 = 0 } 115 var g2: i64 = 0 116 while g2 < 18 { if gc2[g2] != exp2[g2] { t9 = 0 } g2 = g2 + 1 } 117 if t9 == 1 { pass = pass + 1 } 118 if t9 == 0 { ft_puts("T9 FAIL len=" as *u8); ft_putn(gl2); ft_puts(" got=" as *u8); sys_write(1, gc2, gl2); ft_puts("\n" as *u8) } 119 120 ft_puts("FAB-SLICE " as *u8); ft_putn(pass); ft_puts("/" as *u8); ft_putn(total); ft_puts("\n" as *u8) 121 if pass == total { ft_puts("FAB-SLICE ALL-PASS\n" as *u8); sys_exit(0) } 122 sys_exit(1) 123 return 1 124}