nx_pcb_gerber.nx source
↩ module page · 104 lines · 4501 B
1// nx_pcb_gerber.nx -- SOVEREIGN PCB/EDA copper-layer emitter: a board copper-geometry model
2// (apertures + flashes/pads + draws/traces, struct-free parallel arrays) -> a valid Gerber
3// RS-274X file. This is the MANUFACTURABLE FAB SEAM of the Omniforge "chips" leg: the universal
4// handoff every PCB fab accepts AND the input our own isolation-milling CAM will consume next.
5// INTEGER-ONLY / NO-FLOAT by construction -- all coordinates are micrometers (um); Gerber format
6// 4.6 in MM has 6 implied decimals, so a coordinate's format-units = um*1000 (pure integer, zero
7// FP drift -- the determinism float EDA tools cannot match). Aperture sizes formatted as I.FFFFFF
8// mm from integer um. Verified against the real RS-274X spec example in
9// knowledge/fetched/of_ed_gerber.raw (%FSLAX..*% / %MOMM*% / %ADDnnC,d*% / D01 D02 D03 / M02).
10// Mirrors the nx_cad / nx_stl_write organ idiom (reused by the gate, exactly like nx_cad_test).
11// license_tier: ORIGINAL expect_exit: 0
12import "nx_syscalls.nx"
13
14// append the decimal of non-negative v to buf at *len
15func g_puti(buf: *u8, len: *i64, v: i64) -> i64 {
16 if v == 0 { buf[len[0]] = 48 as u8; len[0] = len[0] + 1; return 0 }
17 var m: i64 = v
18 let d: *u8 = sys_mmap(24)
19 var k: i64 = 0
20 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
21 var i: i64 = k - 1
22 while i >= 0 { buf[len[0]] = d[i]; len[0] = len[0] + 1; i = i - 1 }
23 return 0
24}
25
26// append C-string s to buf at *len
27func g_puts(buf: *u8, len: *i64, s: *u8) -> i64 {
28 var i: i64 = 0
29 while s[i] != (0 as u8) { buf[len[0]] = s[i]; len[0] = len[0] + 1; i = i + 1 }
30 return 0
31}
32
33// append micrometers as "I.FFFFFF" millimetres (6 decimal digits)
34func g_mm6(buf: *u8, len: *i64, um: i64) -> i64 {
35 let ip: i64 = um / 1000
36 let fr: i64 = (um % 1000) * 1000 // remaining nm = 6 decimal digits of a mm
37 g_puti(buf, len, ip)
38 g_puts(buf, len, "." as *u8)
39 var div: i64 = 100000
40 while div >= 1 {
41 let dig: i64 = (fr / div) % 10
42 buf[len[0]] = (48 + dig) as u8
43 len[0] = len[0] + 1
44 div = div / 10
45 }
46 return 0
47}
48
49// append one coordinate op "X<xv>Y<yv>D0<d>*\n" where xv = um*1000 (format 4.6 units)
50func g_xyd(buf: *u8, len: *i64, x_um: i64, y_um: i64, d: i64) -> i64 {
51 g_puts(buf, len, "X" as *u8); g_puti(buf, len, x_um * 1000)
52 g_puts(buf, len, "Y" as *u8); g_puti(buf, len, y_um * 1000)
53 g_puts(buf, len, "D0" as *u8); g_puti(buf, len, d)
54 g_puts(buf, len, "*\n" as *u8)
55 return 0
56}
57
58// append a D-code aperture-select line "D<code>*\n"
59func g_sel(buf: *u8, len: *i64, code: i64) -> i64 {
60 g_puts(buf, len, "D" as *u8); g_puti(buf, len, code); g_puts(buf, len, "*\n" as *u8)
61 return 0
62}
63
64// append an aperture definition. kind 0 = circle "C,d", 1 = rect "R,d1Xd2". code = D-number.
65func g_apdef(buf: *u8, len: *i64, code: i64, kind: i64, d1_um: i64, d2_um: i64) -> i64 {
66 g_puts(buf, len, "%ADD" as *u8); g_puti(buf, len, code)
67 if kind == 0 { g_puts(buf, len, "C," as *u8); g_mm6(buf, len, d1_um) }
68 else { g_puts(buf, len, "R," as *u8); g_mm6(buf, len, d1_um); g_puts(buf, len, "X" as *u8); g_mm6(buf, len, d2_um) }
69 g_puts(buf, len, "*%\n" as *u8)
70 return 0
71}
72
73// Emit a full single copper layer into out[]; return total byte length.
74// aperture index i (0-based) -> D-code (10 + i). tr_ap[]/pad_ap[] hold aperture INDICES.
75func gerber_emit(
76 ap_kind: *i64, ap_d1: *i64, ap_d2: *i64, n_ap: i64,
77 tr_ap: *i64, tr_x1: *i64, tr_y1: *i64, tr_x2: *i64, tr_y2: *i64, n_tr: i64,
78 pad_ap: *i64, pad_x: *i64, pad_y: *i64, n_pad: i64,
79 out: *u8) -> i64 {
80 let len: *i64 = sys_mmap(8) as *i64
81 len[0] = 0
82 g_puts(out, len, "G04 Nishi Omniforge sovereign Gerber RS-274X*\n" as *u8)
83 g_puts(out, len, "%FSLAX46Y46*%\n" as *u8)
84 g_puts(out, len, "%MOMM*%\n" as *u8)
85 g_puts(out, len, "%LPD*%\n" as *u8)
86 var i: i64 = 0
87 while i < n_ap { g_apdef(out, len, 10 + i, ap_kind[i], ap_d1[i], ap_d2[i]); i = i + 1 }
88 g_puts(out, len, "G01*\n" as *u8)
89 i = 0
90 while i < n_tr {
91 g_sel(out, len, 10 + tr_ap[i])
92 g_xyd(out, len, tr_x1[i], tr_y1[i], 2) // move (pen up) to start
93 g_xyd(out, len, tr_x2[i], tr_y2[i], 1) // draw (pen down) to end
94 i = i + 1
95 }
96 i = 0
97 while i < n_pad {
98 g_sel(out, len, 10 + pad_ap[i])
99 g_xyd(out, len, pad_x[i], pad_y[i], 3) // flash a pad
100 i = i + 1
101 }
102 g_puts(out, len, "M02*\n" as *u8)
103 return len[0]
104}