code wiki / (root) / nx_pcb_gerber.nx

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}