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}