hanley@cmcl2.UUCP (05/13/88)
I am considering implementing the following 'proposed standard' as a summer project. Please send comments directly to me at either mancol!jh (..!CMCL2.nyu.edu!manhat!jh is forwarded to mancol!jh) or hanley@nyu.edu (which I log on to less often). If you feel you really must post (please avoid posting), be sure to include the keyword "schem88" in your subject line so people can ignore this thread. By the time I'm through I'm sure I will have implemented object rotation, and an editor for at least one machine, probably Sun. I am particularly interested in comments on a) the usefulness of my IC model and suggestions of alternatives b) the importance of making it run under VMS (looks like it's going to lean heavily on Unix pipelines!) c) how to implement the schematics editor in a machine-independent way (will porting be painless if I just call a few generic clear-the-screen, draw-a-line, and get-mouse/pointing_device-xy routines and assume I'll be able to implement that handful of routines on each machine, or are there subtle issues that would be better considered now than later?) T H E S C H E M 8 8 S T A N D A R D Copyright 1988 by John Hanley. Permission is granted to store and redistribute unedited copies of this document, and to make excerpts for purposes of preliminary discussion of the standard. We don't multiple versions of a "standard." A long time ago when this whole "posting schematics" discussion began, I started working on something that would combine SPICE netlists with (x,y) information, using the following article as a starting point: In well-reasoned article <2349@vice.TEK.COM>, keithl@vice.TEK.COM (Keith Lofstrom) writes: > We are not going to all be able to directly use the same format. Most of > us will need translators. Lots of people are volunteering formats, but NOBODY > is volunteering TRANSLATORS. So, whatever format is used must be easy to > translate with hack programs written by dummies like myself. I would propose > we select a format that fits the following criteria: > > 1) ALPHANUMERIC, no special characters, no binary [Agreed. --jh] > 2) FIXED drawing window ( how about 1024*768? ;-) ) [I disagree] > 3) AS SIMPLE AS POSSIBLE - just MOVEs and DRAWs and unscaled text > (you can build scaled text with moves and draws if necessary). [yes!] > 4) No dashes, filled polygons, rotated text, or hierarchy (the last > is hard ... how many times do you want to send the same resistor > shape over USENET? Nonetheless, simplicity counts for much!) See #3. [I agree with all but the hierarchy business... more on macros below.] > [...] > I *DO KNOW* that I can build translators TO all of the above from moves and > draws and unscaled text with simple AWK scripts or BASIC programs or > whatever. I can build translators FROM my favorite drawing tools to > moves and draws. I am doing so for UN*X plot(1), on the assumptions that a) UN*X is pretty much the native OS for Usenet, and b) since UN*X runs on so many machines, right down to the lowly '286, even if for some reason you got hold of the posted schematic on a machine running a different OS, you should still be able to track down a target machine running UN*X. I chose to support plot(1) because it's simple, readily available, and it already supports lots of diverse devices. If it doesn't support your favorite hardware, write the short filter to cvt plot-codes to your-codes, and post the source. The basic scheme is to post SPICE source that includes (x,y) information, pipe this through a filter that extracts this information and outputs only "draw a line from here to there" information, and pipe that to a display program. > Perhaps a primitive subset of some existing format would do, so at least > SOMEONE could imbed it. If nothing else, how about: > NNNxNNNy for absolute coordinate > m for move to prefixed coordinate > d for draw to prefixed coordinate > (string) for text to prefixed coordinate > \* comment *\ > all other characters ignored > [...] Does anyone have any other suggestions that fit the above criteria? > -- > Keith Lofstrom ...!tektronix!vice!keithl keithl@vice.TEK.COM > MS 59-316, Tektronix, PO 500, Beaverton OR 97077 (503)-627-4052 I like this as a starting point, but (after resisting the strong urge to support primitives like triangles and IC's) I decided that a few more commands are needed to support macros (resistors, op amps, etc): relative moves and scaling. My design goals were to provide precisely enough power to allow any machine to do a good job of rendering a schematic while making implementation fairly easy. Text is a sticky point. The exact set of drawing commands I use is: NNN,NNN for scaled relative coordinate m for move to prefixed coordinate d for draw to prefixed coordinate NNNs to change scale factor, pushing the old one onto a stack S to pop the old scale factor o to move (absolute) to the origin, so a following relative move will actually be absolute (assuming unity scale factor) "text" for text at prefixed coordinate sized to current scale Text is not handled directly, but is inserted with the label macro, e.g., label(size, `some text'). It is illegal to directly insert "some text" into a schematics file; you must use the label macro. A distinct and replaceable stage of the pipeline handles expansion of label macros to provide some flexibility for displaying text on devices that can only do it if you give them lots of vectors, devices that can plot text by themselves, and devices like VT100's and printers that don't "plot" text at all. For the moment, only upper case letters, digits, and a few punctuation marks will be fully supported. Also, coordinates are expressed as floats rather than integers. Fixed resolution is unacceptable in a standard that is to be broadly applicable to many machines, so I leave each poster free to draw schematics using his favorite resolution. Screen coordinates are mapped to numbers in the range 0 to 1, inclusive, with (0,0) being the lower left corner and (1,1) the upper right. Individual implementations are responsible for getting the aspect ratio right; connecting the points (0,0)-(1,0)-(1,1)-(0,1)-(0,0) should result in a perfect square being rendered on the display device. Similarly, individual implementations are responsible for zooming in on portions of the display and performing clipping. This is an important capability, even for hosts supporting high resolution, since the decimal coordinates can theoretically express arbitrarily fine detail. Since plot(1) supports line printer output and VT100's, anyone with a VT100 should be able to (laboriously) view any schematic by examining portions of it piecemeal. Incidentally, VT100's are capable of medium resolution that people seldom use: there are 16 graphic characters that let you display any 2*2 combination of pixels in any of the 132*24 character cells, giving a resolution of 264*48, a resolution at which it would be somewhat practical to pan over a medium-size schematic. So who's going to write the filter and post it? Following a mandatory header line (to identify revision level of the standard) is a file describing the schematic, essentially a SPICE description of the ckt with annotations describing where components are located (x,y) and how wires are routed. I don't know how SPICE deals with IC's; there is some minimal support for IC's in schem88a to make it a little easier to create the netlist. I am open to discussion on this -- send mail to ..!CMCL2.nyu.edu!manhat!jh. No attempt has been made to support rotated components; if you want to rotate a resistor 90 degrees, you must come up with the new vectors yourself. If you want to automate this, fine, but schem88 doesn't support it directly at the the moment (so you need macros like horizontal_resistor, vertical_resistor, etc.). It's not that rotating is hard, just that m4 isn't good at arithmetic and I'm more interested in getting the other things working first. In schem88 files, comments can always be inserted between curly braces; the first stage of the pipeline is always a filter to nuke {comments}. Position information always appears after semi-colons; anything between ";" and new-line (after {comment} removal) should be something describing (x,y)/labeling information. Anything else is valid SPICE input; this way you can always do something like cat schematic | strip_braces | strip_semicolons | spice while developing. The SPICE information is always left untouched, but is used to find connectivity information. The stuff hiding behind semi-colons is transformed from a "high-level" form to one containing strictly "draw line from (x,y) to (x,y)" type information This is then then read by a device-specific program which does the actual drawing. Output is to a "device" that understands plot(1)-type commands, so a wide variety of devices are already supported. Format A schematics are the "high-level" description, and are converted to format B (x,y only), using m4 and awk. M4 was selected because it provides nested macros so that complex library symbols may be easily built out of simpler ones, and because it has an "include(lib_file)" facility. There are potential problems with m4 doing macro expansion on things that shouldn't be expanded (including "*" comments), and I am open to comments on this. The router (an awk script) tries to connect components based on the SPICE netlist, but doesn't make any special effort to be an amazingly intelligent router, so it provides for easy over-riding of its default connections if you want to route things yourself. A pair of examples should help to clarify matters: ; schem88a * Parallel Caps ; ports cap 500,0 500,1000 ; define(cap, ``$0'' $1s` ;500,0m 500,400d 0,400d 1000,400d { library definition for cap symbol } ;500,1000m 500,600d 0,600d 100,600d ;S' ) C1 0 1 50pF ; 250,500 cap(100) {Amazing example shows how to make a 100pF} C2 0 1 50pF ; 450,500 cap(100) { capacitor by putting 2 50's in parallel.} .end The first 2 lines and the .end are mandatory. The first line _must_ start with the characters "; schem88a" and may optionally be followed by a blank and any comments you like. This is to facilitate automatic extraction of circuit descriptions from posted articles, and to permit version compatibility when the standard is (inevitably) revised -- translators for schem88b and following will at least be able to identify circuit descriptions written for the original standard. The second line _must_ be a comment describing the overall circuit -- this is a requirement imposed by SPICE (actually, I think the 1st character doesn't even have to be "*" -- SPICE just ignores it's 1st line of input, using it to title all pages of SPICE output). The last line of the schematic _must_ be ".end" on a line by itself, not only because SPICE requires it, but because the schem88 standard requires it to facilitate extraction of schematics from news articles. For m4 fans, the double quotes in ``$0'' are needed to prevent a recursive macro expansion, the open quote in "$1s`" is to keep m4 from interpretting commas in coordinates as being commas separating arguments, and the "S'" is a close quote. Note that the coordinate system was previously described as being a unit square, yet the example gives coordinates like 500,400. This should be interpreted as the coordinate (0.5,0.4) on the unit square. Since this standard is intended to be read and written by humans as well as machines, all coordinates are scaled by 1000 for convenience. (I started writing the example in decimal notation and found that repeatedly typing the extraneous decimal point became quite exasperating.) Note that coordinates are still DECIMALS of theoretically unlimited precision; the coordinate 271.828,314.59 is perfectly valid. I don't care if you think of coordinates as being on a unit square or a 1000-unit square. Just remember that precision is NOT limited to 1 part in 1000. Also, I am open to suggestions if anyone thinks a 100-unit square would be more convenient. I even have doubts about the value of scaling for human convenience at all, since editors are likely to output hairy decimals anyway. I'm not overly concerned about large decimals making schematic files unduly large, but perhaps I should be. Send in your votes, together with sample schematics to prove that you used the standard enough to have some basis for deciding which was more convenient, to CMCL2!manhat!jh. Like Kermit or FTP, schem88 is both a standard and a program (OK, a collection of programs). The standard specifies that coordinates are _decimals_. This is especially important for handling scaled macros. While it is perfectly possible to develop a schematic description by iteratively going through an edit-then-display cycle, it is hoped that someone will write an X-windows front-end to allow generating symbols and whole schematics by simply pointing with a mouse to where you want your lines to be drawn. There is no real reason why humans should ever have to worry about exactly what 2 numbers specify a particular point. The definition of a graphic symbol macro is pretty straightforward. The definition of "cap" and the symbol it draws are given below: ; define(cap, ``$0'' $1s` | ;500,0m 500,400d 0,400d 1000,400d ----- ;500,1000m 500,600d 0,600d 100,600d ----- ;S' ) | The $0 is the name of the macro (`cap') and is for reference by the router. The $1 expands to argument #1, and followed by "s" it sets the scale factor for relative line-drawing commands. The capital "S" at the end of the macro is a "pop-your-stack" command and restores the scale and absolute (x,y) position to whatever they were just before the "$1s" command. The 500,0m command Moves to (0.500,0.000) on the unit square without drawing, and the 500,400d command Draws from that point to (0.5,0.4). Similarly for the other commands, so that the first line of commands draws the lower capacitor plate the second line draws the upper plate. Note that macros by convention are drawn to fill the unit square. This is to make it easier to piece them together with the overall drawing. It is not mandatory that they fit the unit square, but it will make your life much easier if you draw them that way. Long and skinny shapes need only span the unit square in one dimension. The line ; ports cap 500,0 500,1000 defines where connections to our graphic symbol may be made. In this case, there are leads at top and bottom, so we define port 1 to be at the bottom of our symbol in the middle, and port 2 to be at the top in the middle. If you tell SPICE that you have a bypass cap connecting nodes 15 and 16 using the line "CBYPASS 15 16 10uF" and then draw it using the "cap" macro, it is assumed that you want node 15 to be connected to port #1 (bottom) and node 16 to be connected to port #2 (top). If this is not what you wanted, you may reverse the nodes ("CBYPASS 16 15 10uF") without changing the SPICE meaning. For things like transistors, it is important that you label your "ports" in the right order. If you find you will run into the problem of wires crossing right over your device, you can specify an explicit routing, or create a version of your device in a different orientation (NPN1 and NPN2 might be necessary in a diff-amp because the base lead of the BJT has a different orientation in the 2 transistors). I encourage others to write the software that will extract a macro definition and create a new macro that is the mirror image or rotation of the original. (The mathematics is extremely trivial, but the user interface requires some thought.) Ports should almost always appear at the edges of the unit square, as in the above example, to aid routing. It is essential that the "ports" line _precede_ the corresponding definition, so m4 doesn't do a macro expansion on the "ports" line. As an aid to writing consistency checkers, if any of the 6 characters [iobnpg] is found preceding a port coordinate, it is stripped and the coordinate is processed normally. For example, ; port IC1 i0,100 o0,200 b0,300 n0,400 p0,800 g0,900 would represent an IC with an input pin, and output pin, a bi-directional pin, one N/C, a power (+5V) pin, and ground. At the moment, no effort is made to check for consistency (input pin connected to an input pin, &c.). Freely intermixed with macro definitions are SPICE lines like these: C1 0 1 50pF ; 250,500 cap(100) {Amazing example shows how to make a 100pF} C2 0 1 50pF ; 450,500 cap(100) { capacitor by putting 2 50's in parallel.} {scale cap to 10% of size of drawing} M4 requires that macros be defined (usually with include(`file')) before they are used. The router requires that position information come immediately after you define a component to SPICE. The component's position does not need to be on the same line as the SPICE definition (you might have a lot of comments to insert), but it must come before any drawing commands. Note that by the time the router sees the schematic, m4 has already expanded macros and comments have been removed, so that the above 2 lines look something like: C1 0 1 50pF ; 250,500 cap 100s 500,0m 500,400d 0,400d 1000,400d [etc.] S C2 0 1 50pF ; 450,500 cap 100s 500,0m 500,400d 0,400d 1000,400d [etc.] S For capacitor C1 above, the router finds that the component is a cap with its lower left corner at (0.250,0.500) on the unit square, and that it is scaled to fit a 100x100 square on the 1000-unit system or a 0.100x0.100 square on the unit square system. Since the router has already seen a line saying: ; ports cap 500,0 500,1000 it knows that port 1 (which is connected to node 0) is at the coordinate (0.250 + 0.1*0.5, 0.5 + 0.1*0.0). (Lower-left corner of the screen plus a relative move scaled by 10%.) Similarly for port 1 of C2. Also, the router knows that the only two connections to node 0 are the ones specified by C1 and C2. So it just connects them. A few heuristics guide the router in drawing wires: - If a wire is coming out of the top or bottom of a symbol, it is initially extended vertically. Wires coming out of the left or right sides are initially extended horizontally. Ports on corners are considered to be on the left or right side. - A node's location is considered to be the average (x,y) of the ports which connect to it, all other things being equal. However, top/bottom ports are considered to provide "better" information on x-coordinates, and left/right ports provide "better" y-information. If "better" x-information is available, the inferior information (provided by left/right ports) is disregarded and has no effect on the average. Similarly for y-information. Ex: suppose the left-hand lead of a capacitor is being connected to the top lead of a resistor. The x-coord of the connecting node is determined by the cap, the y-coord by the resistor. - If all y-information was provided by "inferior" sources, i.e., only top/bottom ports connect to a node, we have to "average" their y-values to come up with a location for this node. However, this can result in dismal failures, like wires going right through the device. Consider 3 chips with distinct x-coordinates: chip1 near the bottom of the drawing (top-connection), chip2 slightly above it (bottom-connection), and chip3 near the top of the drawing (bottom-connection). In this case, the y-coordinate of their common node must nestle between chips 1 & 2 near the bottom of the drawing, but chip3 would pull the average up too high. So the bounds "node must be above y1" and "node must be below y2" are imposed, and since y2<y3, y3 is discarded (doesn't contribute to the average). If only one kind of bound is found to apply, e.g., "node must be right of x1" and "node must be right of x2", rather than put it on the edge of the device, it is put slightly to the right of the right-most device, spaced away from it by 50% of that device's width. Note that this procedure covers, for example, the case of connecting pins 1 & 3 on a 14-pin IC, but does nothing to resolve the ambiguous drawing that results when pins 2 & 4 on the same IC are also connected; this must be routed by hand. If anyone has an easy solution to the "allocate space for wires" problem (without using storage proportional to screen resolution), I'm all ears. Or, implement it as a front-end, as "node" directives may appear anywhere. - A dot is always drawn to mark nodes with 3 or more connections. - A node's location may always be explicitly specified with the directive ; node NN xx,yy (except for node 0) - Explicit routing information on how to get from a port to a node may always be given with the directive ; route particular_device port_number x,y x,y x,y... For example, ; route C1 1 300,500 300,600 This would draw a line from port 1 of C1 to (0.3,0.5), then to (0.3,0.6), then to the calculated position of the node that port 1 connects to. This last connection will be suppressed if the last x,y specified is 0,0. This would be useful, for example, for showing power connections. - Node zero is always treated as a special case: the wire is extended horizontally or vertically away from the device by 50% of the width or height of the device, and then a GND symbol is drawn. This can be overriden with the "route" directive -- a GND is affixed to the last x,y. - [none of this stuff is implemented yet] [In fact, I don't even think I'll bother to figure out the width of skinny devices or the height of short squat ones; I'll just use the overall size.] All of these pieces are organized using the following pipeline: cat schematic | strip_braces | do_labels | m4 | router | cvt2plot | plot -T4014 You can, of course, give plot any arguments you like, depending on what device you're using. The strip_braces command will need a -t argument if you want text to be output todevices capable of handling text; ordinarily the input to cvt2plot consists strictly of vectors. The strip_braces, m4, and router steps can each be thought of as removing something: comments, macros, and SPICE commands. The router stage winds up creating a temp file so the router can make a first pass to build the connectivity graph and a second pass to output scaled graphic vectors. --John Hanley System Programmer, Manhattan College ..!cmcl2.nyu.edu!manhat!jh or hanley@nyu.edu (CMCL2<=>NYU.EDU)
doug-merritt@cup.portal.com (05/17/88)
I suggest that you start off each schematic with "schem v88a" as a keyword to allow such documents to be automatically recognized as such by software. Note that EDIF does this; each file starts with "edif version 88989" or some such. Doug --- Doug Merritt ucbvax!sun.com!cup.portal.com!doug-merritt or ucbvax!eris!doug (doug@eris.berkeley.edu) or ucbvax!unisoft!certes!doug