A serias of mails sent by Koen to Igor2: -- The BOARD section comes after the header. The board section provides enough information to draw the board outline. The BOARD section corresponds to the pcb-rnd "outline" layer. The syntax looks like this: {BOARD (PERIMETER_SEGMENT X1=x1 Y1=y1 X2=x2 Y2=y2) (PERIMETER_ARC X1=x1 Y1=y1 X2=x2 Y2=y2 XC=xc YC=yc R=r) } PERIMETER_SEGMENT is a straight line from (x1, y1) to (x2, y2). PERIMETER_ARC is a counterclockwise circle arc (x1, y1) to (x2, y2) with center (xc, yc) and radius r. x1, y1. x2, y2, xc, yc, and r are in the unit you chose in the UNITS statement (cm or inch). The example above shows only two, but a BOARD section typically has many PERIMETER_SEGMENT and PERIMETER_ARC statements. Test the correct orientation for the arc: counterclockwise. You can mix the PERIMETER_SEGMENT and PERIMETER_ARC any way you want. The order does not matter. Just print one PERIMETER_SEGMENT or PERIMETER_ARC per line. -- The STACKUP section defines all layers, both copper and dielectric. This is an example of a two-sided board: {STACKUP (SIGNAL T=0.003500 L="component") (DIELECTRIC T=0.160000 L="dielectric layer 1") (SIGNAL T=0.003500 L="solder") } The above corresponds to 35um copper on 1.6mm FR4. Apart from SIGNAL and DIELECTRIC, there's a third type of copper layer, PLANE, not shown here. The difference between SIGNAL and PLANE is that a SIGNAL layer is empty by default, unless you draw something on it, while a PLANE layer is full of copper by default. This can be used for power and ground planes. The thickness T is in cm, as that is the UNIT you chose. The STACKUP is where you can define the properties of the material. Most common are the bulk resistivity of the copper (BR=), or the dielectric constant of the dielectric (ER=). (SIGNAL T=0.000700 BR=resistivity L="component") (DIELECTRIC T=0.002000 ER=epsilon L="dielectric layer 1") If you don't say anything, the values default to copper on FR4, which is what most people want. Look at the layer name. This is the first time we have to print a string. Hyperlynx will accept many strings without double quotes, but if the string contains characters like } or ) you may have a problem. To avoid these problems, always print a string between double quotes (""). eg. LAYER="Component" If the string contains a double quote, print two double quotes. e.g "This is a ""string"" with double quotes." Give all layers a name. If you don't choose a name, Hyperlynx will choose a name for you, and it probably won't be what you want. -- A hyperlynx file looks something like this: - header - board outline - stackup: definition of all layers of the board, both copper and dielectric - devices: parts list. - padstack: definition of the shape of vias, pins and pads - net: definition of all copper. A 'net' is connected copper. - straight lines - arcs - polygons - vias: references a padstack. - pins and pads: each pin or pad references a padstack and a device. - unrouted segments - footer I'd split this in different functions, so that the order can be changed easily if you want to re-use the code for another export module. The difference between vias, pins and pads is: - a via has a hole but is not associated with a device - a pin has a hole and a device - a pad does not have a hole, but has a device. The first piece of code is writing the header and the footer. The header looks like this: * test.hyp exported by pcb-rnd 1.2.3 on 01.01.1999 12:45 {VERSION=2.0} {DATA_MODE=DETAILED} {UNITS=METRIC LENGTH} A line that begins with "*" is a comment. This says you are using centimeters for coordinates and for layer thickness. If you would prefer to export coordinates in inches, and layer thickness in ounces per square foot, you could use: {UNITS=ENGLISH WEIGHT} Your choice. and the footer is: {END} If you want to, tomorrow I'll send the info for the board outline. If there are any questions, just ask. -- After the STACKUP section, there's the DEVICES section. The DEVICES section is the parts list of the board. {DEVICES (? REF="U1" NAME="BC548" L="Top") (? REF="R2" NAME="1K2" L="Top") ... } This is where we say which side of the board the component is soldered on. The exact coordinates of the component are specified later, when we handle the PINs and PADs. The L=layer is the layer the component is soldered on. Use the same layer name as in the STACKUP section. A board needs at least one component, else there are no pins or pads to connect the simulation to. -- A PADSTACK section describes the pads of a pin, via or pad. You describe the pads of a via, pin or pad once, and refer to it multiple times when creating vias, pins or pads. A padstack looks like this: {PADSTACK=name, (layer, shape, x-size, y-size, angle, type) ... more layers } where shape is 0 for circle/ellipse, 1 for square/rectangle, 2 for oblong. angle is the rotation in degrees, counterclockwise. The "type" parameter is M, A, T. M Metal: ordinary copper pad, A Antipad: hole around the pad on PLANE layers, T Thermal: thermal relief. Thermal relief is when a pin connects to a ground plane with short, stubby tracks, like spokes on a wheel. This makes the pin easier to solder. If you simply connect the pin to a solid copper polygon it is difficult to solder, because the direct connection to a big copper surface copper cools the pin too much. You don't have to specify the type parameter, but it doesn't hurt. An example: {PADSTACK="pad1" ("Top", 1, 0.5, 0.5, 0, M) } The padstack called "pad1" consists of a single pad on the "Top" layer, 0.5 cm square. If the padstack describes a pin or via, you have to specify the diameter of the drill hole: {PADSTACK=name, diameter (layer, shape, x-size, y-size, angle, type) ... more layers } {PADSTACK="stack2", 0.2 ("Top", 0, 0.5, 0.5, 0, M) ("Bottom", 0, 0.5, 0.5, 0, M) } There are two special layer names: MDEF and ADEF. If the layer is MDEF (without quotes) this means: size of metal pad on all SIGNAL layers. ADEF (without quotes) means size of the hole in the copper on all PLANE layers. Using MDEF and ADEF you can define a padstack for a via or pin which will always work, even if layers are added, removed or changed in name. Example: {PADSTACK="pin1", 0.2 (MDEF, 0, 0.5, 0.5, 0, M) (ADEF, 0, 0.5, 0.5, 0, A) } For completeness: You could define thermal relief around a pad. (layer, shape copper, x-size copper, y-size copper, angle copper, shape thermal relief, x-size thermal relief, y-size thermal relief, angle thermal relief, T) So a single layer may appear up to three times in the same PADSTACK: once for each type (M - metal, A - antipad, T - thermal) The two padstacks to remember when exporting are the "pad1" and "pin1" examples. A hyperlynx file contains multiple PADSTACK sections, one per padstack. When exporting, you have to loop over all vias, pins and pads of the board twice: once when creating the padstacks, and once when creating the vias, pins and pads. -- The NET section specifies a network of connected copper. A NET is not limited to a single layer, but may be on multiple layers. The NET section contains subsections: - SEG and ARC to draw line segments and circle arcs - PIN to draw component pads and pins - VIA for vias - POLYGON and POLYVOID to draw polygons with holes - POLYLINE to draw a sequence of line segments and circle arcs - USEG to draw unrouted segments Each net has a name, e.g. "VCC","CLK", "GND". {NET="I2C_SCL" (SEG X1=6.500000 Y1=3.000000 X2=6.625000 Y2=3.000000 W=0.008333 L="Top") ... other SEG, ARC, PIN, VIA, POLYGON, POLYVOID, POLYLINE, USEG records ... } A hyperlynx file contains multiple NET sections, one per network. Next: the subsections of the NET section. -- Often a copper trace is a sequence of straight lines and arcs, all of the same width. If you have a sequence of line segments and arcs, all of the same net, all on the same layer, all of the same width, you can draw the whole trace as a POLYLINE: {NET=name {POLYLINE L=layer W=width ID=integer_id X=x0 Y=y0 (LINE X=x1 Y=y1) (CURVE X1=x2 Y1=y2 X2=x3 Y2=y3 XC=xc YC=yc R=r) (LINE X=x4 Y=y4) ... } ... } integer_id is a number, which is different for each polyline (and polygon). For integer_id, just initialize a number to 0, and increase it id++ every time you draw a polyline or polygon. How is the POLYLINE above drawn? First a line from (x0, y0) to (x1, y1) on layer "layer" and width w is drawn. Then an arc counterclockwise from (x2, y2) to (x3, y3) with center (xc, yc) and radius r is drawn. Where the next LINE begins depends on where the CURVE ends. The CURVE begins where the previous segment ends. If (x1, y1) is the same as (x2, y2) the CURVE ends at (x3, y3) and a line from (x3, y3) to (x4, y4) is drawn. If (x1, y1) is the same as (x3, y3) the CURVE ends at (x2, y2) and a line from (x2, y2) to (x4, y4) is drawn. An example: {NET="VCC" {POLYLINE L="component" W=0.1 ID=1 X=6.000000 Y=5.000000 (LINE X=8.000000 Y=5.000000) (CURVE X1=8.000000 Y1=5.000000 X2=8.000000 Y2=5.500000 XC=8.000000 YC=5.250000 R=0.250000) (LINE X=6.000000 Y=5.500000) ... } ... } You can have as many LINE and CURVE substatements as you like, and in any order. -- A trace can be defined, not by its shape, but by its delay, characteristic impedance and resistance. This is the unrouted segment USEG. {NET=net_name (USEG X1=x1 Y1=y1 L1=layer1 X2=x2 Y2=y2 L2=layer2 Z=characteristic_impedance D=delay R=resistance ) =85 } This unrouted segment begins on one layer L1= and end on another L2= . Another way of defining a trace is by giving width, length and layer. The delay and characteristic impedance can be calculated from trace width, trace length and the thickness and epsilon of the dielectric above and below the trace. (USEG X1=x1 Y1=y1 L1=layer1 X2=x2 Y2=y2 L2=layer2 ZL=trace_layer ZW=trace_width ZLEN=trace_length) This unrouted segment is a transmission line which begins on one layer L1= and end on another L2= . The microstrip itself is drawn on layer ZL=. This way you can simulate a trace as a lossy transmission line. [ Note: When simulating power supply and ground planes, which are mostly copper, the simulation model is not a transmission line but its two-dimensional equivalent, the transmission plane. ] -- The difference between a PIN and a VIA is that a PIN belongs to a device. (VIA X=x0 Y=y0 P=padstack0) puts a via at coordinates (x0, y0) according to padstack "padstack0". The shape of the pads, whether the via is a through-hole via, a blind or a buried via, is all defined in the padstack. Example: (VIA X=11.750000 Y=5.250000 P="0802pad") A pin (PIN X=x0 Y=y0 R=ref P=padstack0) puts a pin or pad at coordinates (x0, y0) according to padstack "padstack0". The reference is of the format "device_name.pin_name". This requires that "device_name" has been defined in the "DEVICES" section. Example: (PIN X=15 Y=1 R="U1.2" P="smd04") Here U1.1 is pin "2" of device "U1". To avoid problems, it is better if device and pin names do not contain the "." character. The shape of the pads, whether the pin is smd or through hole is defined in the padstack. The simulation connects signal sources to the board at PINs, and measures voltages at PINs. -- When all else fails, you can always represent copper as a POLYGON. The POLYGON syntax is very similar to the POLYLINE syntax. Just change POLYLINE into POLYGON. {NET=name {POLYGON L=layer T=POUR W=width ID=integer_id X=x0 Y=y0 (LINE X=x1 Y=y1) (CURVE X1=x2 Y1=y2 X2=x3 Y2=y3 XC=xc YC=yc R=r) (LINE X=x4 Y=y4) ... (LINE X=xn Y=yn) } ... } The difference is that a POLYGON is closed. A POLYLINE ends at the last point (xn, yn). A POLYGON draws a line from the last point (xn, yn) back to (x0, y0). The T=POUR parameter says the inside of the polygon is filled with copper. A Hyperlynx polygon has an outline of straight line segments and circle arcs. The W=width parameter gives the line width of the outline. You can make a polygon bigger this way. In the often occurring case of a polygon of only line segments, and zero border width, we get: {NET=name ... {POLYGON L=layer T=POUR W=0.0 ID=integer_id X=x0 Y=y0 (LINE X=x1 Y=y1) ... (LINE X=xn Y=yn) } ... } Example: {NET="VCC" {POLYGON L="TOP" W=0.0 ID=1 X=9.000000 Y=6.500000 (LINE X=10.000000 Y=6.500000) (LINE X=10.000000 Y=7.000000) (LINE X=9.500000 Y=7.000000) (LINE X=9.500000 Y=7.500000) (LINE X=9.000000 Y=7.500000) (LINE X=9.000000 Y=6.500000) } } Do not forget that all polygons and polylines should have a different ID= value. -- A POLYVOID is a hole in a POLYGON. The hole itself is shaped like a polygon, too. The shape of the hole is a sequence of straight lines and circle arcs: {NET=name ... {POLYVOID ID=integer_id X=x0 Y=y0 (LINE X=x1 Y=y1) (CURVE X1=x2 Y1=y2 X2=x3 Y2=y3 XC=xc YC=yc R=r) (LINE X=x4 Y=y4) ... (LINE X=xn Y=yn) } ... } The ID= value of the POLYVOID hole is the same as the ID= value of the POLYGON you want to make a hole in. You do not have to specify the layer of the hole, because the hole is on the same layer as the polygon you make a hole in. Example: {NET="Ground" {POLYGON L="component" T=POUR W=0.0 ID=3 X=9.000000 Y=6.500000 (LINE X=10.000000 Y=6.500000) (LINE X=10.000000 Y=7.000000) (LINE X=9.500000 Y=7.000000) (LINE X=9.500000 Y=7.500000) (LINE X=9.000000 Y=7.500000) (LINE X=9.000000 Y=6.500000) } {POLYVOID ID=3 X=9.125000 Y=6.625000 (LINE X=9.625000 Y=6.625000) (LINE X=9.625000 Y=6.875000) (LINE X=9.375000 Y=6.875000) (LINE X=9.375000 Y=7.125000) (LINE X=9.125000 Y=7.125000) (LINE X=9.125000 Y=6.625000) } } A polygon can have several holes. Just write several POLYVOID sections. In practice, if you only export polygons consisting of straight lines of zero width, you get the following: {NET=name ... {POLYGON L=layer T=POUR W=0.0 ID=integer_id X=x0 Y=y0 (LINE X=x1 Y=y1) ... } {POLYVOID ID=integer_id X=x0 Y=y0 (LINE X=x1 Y=y1) ... } {POLYVOID ID=integer_id X=x0 Y=y0 (LINE X=x1 Y=y1) ... } ... } Where integer_id is the same for the POLYGON and its POLYVOIDs. Don't forget to end your exported file with {END} This ends the Hyperlynx exporting HOWTO. -- Result (sent by Igor2 to Koen): > The STACKUP section defines all layers, both copper and dielectric. This is an example of a two-sided board: > > {STACKUP > (SIGNAL T=0.003500 L="component") > (DIELECTRIC T=0.160000 L="dielectric layer 1") > (SIGNAL T=0.003500 L="solder") > } > > The above corresponds to 35um copper on 1.6mm FR4. Deviation: we don't yet store metadata like layer thickness. We are very close to have it, but still don't have it, so I just hardwired these default values for now. > Look at the layer name. This is the first time we have to print a string. > Hyperlynx will accept many strings without double quotes, but if the string contains characters like } or ) you may have a problem. > To avoid these problems, always print a string between double quotes (""). > eg. LAYER="Component" Because of io_kicad, pcb_printf() supports %mq, which gets a list of characters that need quoting and a string and can decide whether quoting is needed or not. So instead of quoting everything, I just configured this to what seemed reasonable and we quote only what needs to be quoted. The list of characters that need quoting is specified only once; if we figure there's a character left out, it's trivial to add. -- > A PADSTACK section describes the pads of a pin, via or pad. > You describe the pads of a via, pin or pad once, and refer to it multiple times when creating vias, pins or pads. > > A padstack looks like this: > > {PADSTACK=name, > (layer, shape, x-size, y-size, angle, type) > ... more layers > } For this I had to write a pad stack hash - in pcb-rnd we don't have central lib/list of geometry, each via and pin specifies its own. This pad stack hash is a hyp-independent lib, I'll move it into a separate plugin this week. > > where shape is 0 for circle/ellipse, 1 for square/rectangle, 2 for oblong. angle is the rotation in degrees, counterclockwise. This is on my TODO; we have more shapes, some are asymmetrical, will have to figure this. > There are two special layer names: MDEF and ADEF. > If the layer is MDEF (without quotes) this means: size of metal pad on all SIGNAL layers. > ADEF (without quotes) means size of the hole in the copper on all PLANE layers. > Using MDEF and ADEF you can define a padstack for a via or pin which will always work, even if layers are added, removed or changed in name. Example: > > {PADSTACK="pin1", 0.2 > (MDEF, 0, 0.5, 0.5, 0, M) > (ADEF, 0, 0.5, 0.5, 0, A) > } Diversion: at the moment pcb-rnd doesn't support anything else for pins/vias just "same copper ring on all layers", so I used MDEF here. -- > Apart from SIGNAL and DIELECTRIC, there's a third type of copper layer, PLANE, not shown here. The difference between SIGNAL and PLANE is that a SIGNAL layer is empty by default, unless you draw something on it, while a PLANE layer is full of copper by default. This can be used for power and ground planes. Diversion: pcb-rnd doesn't support negative drawn copper, so I used SIGNAL and DIELECTRIC only. -- > Often a copper trace is a sequence of straight lines and arcs, all of the same width. > > If you have a sequence of line segments and arcs, all of the same net, all on the same layer, all of the same width, you can draw the whole trace as a POLYLINE: > > > {NET=name > {POLYLINE L=layer W=width ID=integer_id X=x0 Y=y0 > (LINE X=x1 Y=y1) > (CURVE X1=x2 Y1=y2 X2=x3 Y2=y3 XC=xc YC=yc R=r) > (LINE X=x4 Y=y4) > ... > } It's good to know; however pcb-rnd doesn't have polylines of any sort, so we are not using this feature. -- > > A trace can be defined, not by its shape, but by its delay, characteristic impedance and resistance. This is the unrouted segment USEG. > > {NET=net_name > (USEG X1=x1 Y1=y1 L1=layer1 X2=x2 Y2=y2 L2=layer2 Z=characteristic_impedance D=delay R=resistance ) > ? > } > > This unrouted segment begins on one layer L1= and end on another L2= . Question: is USEG the same as rat lines in pcb-rnd? Indication of a logical connection that is derived from the netlist but is not (yet) realized in copper? -- The netlist feature now works. We're getting there. I've run some tests, and there are some conclusions: - all internal layers are called "Intern" instead of the real layer names. This is a problem, because no two layer names may be the same. - the board is upside down The easiest way to check is by importing the io_hyp/tests/test00/test00.hyp file, exporting it as hyperlynx, and importing again. --