/* WIRELIST.ULP ---- A WIRE WRAPPING NETLIST User Language Program (Ver. 1.0 - 13/09/05) - by Joseph Zeglinski * A modification of "TESTPNTS.ULP" - by Richard Hammerl (CADSOFT), * PURPOSE: * This ULP is for those who need a shortest, point-to-point, "wire wrapping (or soldering)" run list for nets * in a board produced from an EAGLE schematic. Applications include "prototype breadboard" or "project board" * layouts for testing or hobby projects. * * This EAGLE User Language Program (ULP) produces the netlist with X & Y locations of pads/wire wrap pins * on a board, or a netlist of a schematic. It is saved as a "_WW.SCR" script file which the user can * simply view/print, or execute on a new, fully laid out BRD file - but ONLY after he executes DELETE SIGNALS to * remove all of the original NETS, produced by the original matching SCH schematic file. This allows display * of the resulting "wire runs" (no more than 2 wraps per pin). Each "constellation" of a signal's wire run can * be high lighted using the Eagle SHOW command, to verify the expected run. New columns were * added to augment the X & Y coordinates, with pin-to-pin wire lengths in (mils), as well as the * X & Y wire wrap pin's, equivalent board Row & Column numbers. The latter are "rounded up" in cases where the user * placed parts with pins in grid "spaces", instead of on "grid lines", to gain an extra row from the licensed * Eagle board size limit. This results in "thin border edges and an offset pad spacing. A library part symbol * might also be poorly designed, with pads not falling on even grid lines. Such pin positions are "Rounded Up", to align * board row & column numbers in this netlist SCR file, so wired pins fall on STANDARD 0.1 inch (2.54 mm) GRID LINES. * REPORT LAYOUT: * The information header identifies the ULP revision, and the BOARD file name, along with a warning, and column names. * The body of the netlist is a command file, beginning with SIGNAL , followed by multiple lines of PART & PAD * identifiers. The SIGNAL command terminates with a single line starting with a semicolon (;) * The pound signs (#) after the PAD numbers, are used as a "comment" seperators of the SIGNAL command string, from * the "information columns" to the right, in this netlist report. * This method allows the netlist to be used, both as a TEXT report for printing, or as a "Command String File" * for execution as a script (SCR), on a copied BOARD, with deleted air wires, to create a Wire Wrapped version. * If this naming convention is undesirable, change the file name extension, in the OUTPUT statement, from SCR to TXT. * USE: * (1) Produce an Eagle Schematic and parts laid out Board file - as usual. * (2) Save SCH & BRD files immediately, before running this ULP - as a precaution. * (3) Run WIRELIST.ULP -in the (opened) BOARD file, to produce the wire-wrap netlist file - then print/view. * Note: It would be convenient to set your board display GRID unit to (mil), when comparing to the NETLIST coordinates * OPTION: To produce an auxillary, DIFFERENT board version, which is air wire ROUTED as a WIRE-WRAP project board * (4) CLOSE the schematic SCH file, and execute (DELETE SIGNALS;) to remove all previously autorouted board signals * (5) EXECUTE the "_WW.SCR" script that was created above, in this (now) "wireless", but laid out board. * * This now shows a board TOP VIEW of all the parts air-wired point-to-point as it would be, wire wrapped. * To verify runs, run (DISPLAY ... NONE) all layers except UNROUTED, DIMENSION, and PADS. Then use * SHOW to see a high lighted constellation of that wire wrapped signal run. * * CAUTION: Do NOT run RATSNEST or AUTOROUTER, on this new board - that would ruin the wire wrap routing, thus * recreating the original BOARD file. In fact, any manual file editing may change "optimized" wire lengths. * However, displaying a signal may show where a wire run can be shortened by breaking into a run and * joining obvious islands that the this routing algorithm could not optimize, locally, and which * in quite rare situations, was forced to produce one overly long "joining" wire. * ROUTING ALGORITHM: * Very simple - starting with the original version, the netlist from the laid out board is first sorted by * radial distance from board origin, to every X/Y PAD coordinate for a signal. This is to identify * the "closest starting point" of each signal, to the lower left corner of the board. * Next, with the starting point of a signal so defined, the remaining PADS of the signal are "BUBBLE SORTED" * by "shortest wire jump", nearest-neighbour pad distance, for each signal run. The DISPLAY may show some "exceptions" * with a few very long runs. These are caused by "groups of points" which are nearest to each other, but are not * near to another group. So, there must be one longer wire run, to join the two "groups". * Finally, the resulting WIRE WRAPPING NETLIST is printed to the SCR file, complete with EAGLE SIGNAL COMMANDS and * proper command punctuation. This SCR can now be either printed/viewed, or run against the "air-wireless" board * to produce a fully wire wrapped BOARD file. This NETLIST can also be used for production of a wired board. * (To verify exact ROW and COLUMN position of wire wrap pin, divide the "X & Y mils" positions by 100). ********************************************************************************************************************** */ // WIRE WRAP NETLIST OF BOARD if (board) board(B) { output(filesetext(B.name, "_WW.scr")) { printf("%s %s\n\n", "#", EAGLE_SIGNATURE); printf("# WW_TESTPNTS.ULP Version 1.0 - Wire Wrapping Board Netlist / SCR Script File, generator\n\n"); printf("# %s \n# on %s \n\n# WIRE WRAP Netlist [sorted by shortest wire run] with Wire Wrap Board pin locations. \n", B.name, t2string(time())); printf("# A FLAG (*) after Pin-X or before Pin-Y, means the PART's pad is not placed exactly on \n"); printf("# a standard 0.1 inch (2.54 mm) EAGLE BOARD grid line (Check: X & Y mils coordinates)\n"); printf("# This may be O.K. (e.g. thin board edge) - Pin Position is ROUNDED UP to CORRECT spacing.\n\n"); printf("\n\n%s %-*s %-*s %s %s %s %s %s \n","#", SIGNAL_NAME_LENGTH, "Net", ELEMENT_NAME_LENGTH, "Part", " Pad"," Pin-X , Pin-Y "," X mils "," Y mils "," Wire Length mils"); B.signals(S) { numeric string Part[], Pad[]; real x[], y[], Len[], L, M; int cnt = 0, i, j, index[], Temp; S.contactrefs(C) { Part[cnt] = C.element.name; Pad[cnt] = C.contact.name; x[cnt] = u2mil(C.contact.x); y[cnt] = u2mil(C.contact.y); /* Preset all wire lengths to distance from board origin so that after sort, each signal's FIRST starting pad will be closest to board origin. */ Len[cnt] = sqrt((x[cnt]*x[cnt]) + (y[cnt]*y[cnt])); // Radial distance of PAD cnt++; } if (cnt) { sort(cnt, index, Len); //sort the list by shortest wire to board origin // BUBBLE SORT signal list & create shortest point-to-point wiring sequences for each network set. Len[index[0]] = 0; for ( i = 0; i < cnt-1; i++) { L = sqrt((x[index[i+1]]-x[index[i]])*(x[index[i+1]]-x[index[i]]) + (y[index[i+1]]-y[index[i]])*(y[index[i+1]]-y[index[i]])); Len[index[i+1]] = L; // Calculate: PAD-to-PAD nearest neighbour distance - for this signal run, to find shortest wiring length for ( j = i+1; j < cnt-1; j++) { M = sqrt((x[index[j+1]]-x[index[i]])*(x[index[j+1]]-x[index[i]]) + (y[index[j+1]]-y[index[i]])*(y[index[j+1]]-y[index[i]])); if( M < L ) { Temp = index[i+1]; index[i+1] = index[j+1]; index[j+1] = Temp; Len[index[i+1]] = M; Len[index[j+1]] = L; L = M; } } } Len[index[cnt-1]] = sqrt((x[index[cnt-1]]-x[index[cnt-2]])*(x[index[cnt-1]]-x[index[cnt-2]]) + (y[index[cnt-1]]-y[index[cnt-2]])*(y[index[cnt-1]]-y[index[cnt-2]])); printf("SIGNAL %-*s \n", SIGNAL_NAME_LENGTH, S.name); for ( i = 0; i < cnt; i++) printf(" %-*s %3s %s %4d %s %s %-4d %12f %12f %14f \n", ELEMENT_NAME_LENGTH, Part[index[i]], Pad[index[i]], "# ", (int(x[index[i]])+50)/100, frac(x[index[i]]/100) ? "*,":" ,", frac(y[index[i]]/100) ? "*":" ", (int(y[index[i]])+50)/100, x[index[i]], y[index[i]], Len[index[i]]); printf(";\n"); } } } } /* ******** END OF ZEGLINSKI MODIFICATIONS ******** /* NETLIST OF SCHEMATIC */ if (schematic) schematic(SCH) { output(filesetext(SCH.name, ".NET")) { printf("%s\n\n", EAGLE_SIGNATURE); printf("Netlist exported from %s at %s\n\n", SCH.name, t2string(time())); printf("%-*s %-*s %s\n", NET_NAME_LENGTH, "Net", PART_NAME_LENGTH, "Part", "Pin"); SCH.nets(N) { numeric string Part[], Pin[]; int cnt = 0, index[]; N.pinrefs(P) { Part[cnt] = P.part.name; Pin[cnt] = P.pin.name; cnt++; } if (cnt) { sort(cnt, index, Part, Pin); printf("\n"); for (int i = 0; i < cnt; i++) printf("%-*s %-*s %s\n", NET_NAME_LENGTH, i ? "" : N.name, PART_NAME_LENGTH, Part[index[i]], Pin[index[i]]); } } } }