ChipNDalePrograms.tioga
Ch. Jacobi, November 30, 1984 6:07:50 pm PST
Ch. Jacobi, March 24, 1986 11:34:33 am PST
ChipNDale
ChipNDale 2.3 — FOR INTERNAL XEROX USE ONLY
ChipNDale
An interactive editor for VLSI designs
Programmers Manual
Release 2.3
Ch. Jacobi March 20, 1986
A relatively incomplete documentation.
Filed on: [Indigo]<ChipNDale>6.0>CDDoc22>ChipNDalePrograms.tioga
© Copyright 1985, 1986 Xerox Corporation. All rights reserved.
Abstract: ChipNDale, is an interactive graphic layout tool made to run in Cedar. This document document tells you how to write additional programs for the ChipNDale environment. It assumes you know how to program in Cedar generally. For documentation on the bare interactive usage of ChipNDale, there is more appropriate documentation.
XEROX Xerox Corporation
Palo Alto Research Center
3333 Coyote Hill Road
Palo Alto, California 94304
For Internal Xerox Use Only
00. Contents
0. Introduction
1. Uncomplete List of Definition Modules
2. Rules
3. Integration level
4. Using Designs in different environments
5. Registering commands
6. An example object generator
7. All the fuss about Coordinate systems
0. Introduction
This documentation has some rules and hints; it is NOT intended to replace reading the definition modules. The definition modules are the primary place to find documentation.
There is some further quite specific documentation on particular features. This may not be included here, because it is not so of general interest. As pointer to these documentation: either look in the DF file or in the documentation subdirectory. There does not exist a list of these additional documentations. This documentation serves both tool maker and designers creating designs by program.
Toolmakers: be carefull: Whatever you do, try not to wedge a designer; designer keep work worth years in .dale files. They tend allways to use your newest feature, before it is even finished. You then get the problem of supporting their files for the next 200 years.
1. Uncomplete List of Definition Modules
Browsing is a good idea! Look also in the .df files.
Basic Structures
CD, CDDirectory, CDOrient, CDBasics, CDInstances
Basic Objects
CDCells, CDRects, CDSymbolicObjects
Less Basic Structures
CDExtras, CDMarks
Less Basic Objects
CDImports, CDRepetitions, CDAtomicObjects, CDTexts, CDPolygons
Generator stuff
CDGenerate, CDGenerateBackdoor
Some Generators
CDGenerateImports, CDRemote
Utilities for generators (not all automatically loaded)
CDUtil, CDCreateLabels, CDCleanUp
Implementors IO
TokenIO, CDRopeViewer, CDMark
Extension Mechanism
CDProperties, CDValue, CDEvents, CDCallSpecific
Introducing commands
CDSequencer, CDMenus, (CDGenerate)
Registering a technology
CDTipEtc, CDDefaults, CDLRUCache, CDPanel, CDColors, CDAtomicObjects, CDDefaultProcs, CDLayers
Handy stuff on command level
CDOps, CDCommands, CDCommandOps, CDViewer, CDDirectoryOps, CDSimpleOps, CDPropertyTools, CDCleanUp
Getting hand on
CDSimpleRules, CDViewer
Crazy stuff
CDStretchyExtras, CDImportsExtras, CDPrivate, CDSimpleOps, CDMenuSpecials
Displaying special things
CDViewHighlight, CDViewer, CDErrors
Private viewer stuff
CDVScale, CDVFurtherPainters, CDVArrow, CDVTicks, CDVPrivate, CDViewerBase
Internal stuff
CDDrawQueue, CDLayers
Technology stuff
CMos stuff
CMos, CMosObjects
NMos stuff
NMos, NMosTransistors, NMosContacts
2. Rules
Style rules
The style rules make it possible for new people to maintain code, without learning for years about tioga formatting and such crap. (I personally refuse to maintain any program where editing shows to be too painful)
No formats except "code".
Only Cedar style.
No looks which do not appear with the <CTRL>-M command; optional exception: to make interim warnings. You may use XXX or ??? to mark warnings. I hate greek characters in program code and I never have the Idea that a variable "greek lambda" and a variale "l" is the same for the compiler...(nor do I know [or want to know] how to edit that) Greek characters in comments are ok, as long as the size of the font does not change.
Names of procedures are bold, independant if their type is an identifier or a PROC constructor. Names of procedures types are NOT bold.
Use Mesa convention for smaller-uppercase... (optional exception: multiword-constants may be made with lower case letters only, are also acceptable).
Use -- for comments in the middle of code, it's easier to read than looking at the font.
Don't use Cedar's object notation for your own types. Exception where usage of object notation is ok are Cedar types which are very well known, like IO.STREAM, Rope.ROPE and Imager.Context.
Interfaces
Avoid non-readonly public variables in public interfaces.
Is the interface complete?
Are the procedures commented?
There is always a client who wants to use it for something you hav'nt thought at.
Release Rules
Df files must be verifyed, with 0 errors and 0 warnings.
Do the release version number crap, it's necessary: if the amount of existing code increases we cannot do nice releases of everything at the same time; different releases must be able to coexist.
A Df file has an owner, do not change it nor its contents without notifying him.
Registration rules
Where ever properties are provided for clients, there MUST be comment whether clients have to follow the CDProperties registration rules or not (This 1 bit decision is mandatory, and there exists no maybe). If the CDProperties registration rules do not hold for some property lists, these lists MUST NOT be written out on ChipNDale files. (It would be really a show stopper, not just a style violation)
There is a file ChipNDale-Registrations.tioga which lists some registered features.
Working hints
Do write new modules, change existing ChipNDale modules only later when the new stuff is tested and accepted. This rule has two exceptions: 1) small bug corrections [Feature adding is NOT bug correction, please]. 2) The owner or maintainer of a module owns it and may change it without following this rule.
Your free to write your own extensions, but your extension should not restrict other people to write other extensions; violaters will end up with their code not beeing used.
If you're for limitted time here only
Please think at the maintenance problem. Even if your code is good and bug free, ChipNDale is still evolving, therfore your code has to be updated.
It's better to write a small peace of code which does a complete job, than to have a big module which needs some finish; remember whoever makes the finish will not know your style and intentions by hart.
When your job ends in changing an existing module, try not just to add the new feature. Try to add it such that improving the existing code is not more difficult than without extension. Some modules (of mine) are really not (yet) perfect, and improving the functionality must not prevent later improving the structure.
3. Integration level
There are different classes of programmers needing this documentation.
-Creating a design by program.
-Implementing generators to generate objects.
-Implementing new simple commands. (eg. Split wire)
-Implementing new object types. (eg. Repetitions)
-Implementing new technologyes. (eg. ChipNSil)
-Implementing new complex commands or features, which might need new properties.... (eg. Spinifex)
-Working on ChipNDale itself.
ChipNDale is keep very flexible to ease all these kind of extensions. Mainly the registration rules bother for friendly coexistence of unrelated features.
Properties and objects are saved on files for permanent storage; this is a great area of problems.
The registration mechanism might look like the ultimate solution for extensability, but it is not. The current version of ChipNDale is able to allow arbitrary extensions; however, designs which use some extensions might not be able to be edited with a ChipNDale without implementation of the extension anymore!. Use uttermost care and precautions please.
4. Using Designs in different environments
There are several methods to get your hand on a design for input.
For debugging:
Use the ^-middle command; a popup menu allows you to make an event handler which has access to the design.
For most simple modules which implement a command to operate on one singular design:
Register a command with CDSequencer; Your command procedure will be called and the design is given as a parameter to the command procedure. The command procedure is either called because of an tip-table entry; or, your module registers an entry in a popup menu using the module CDMenus.
Some more complex applications may require commands registered with the (Cedar)commander. It is possible to get a filename and read in that design, using CDIO. On the other hand it is possible to search for an existing design, using CDViewer.FindDesign. Note: this procedure is in the viewer module, because it allows you only to acces designs which have a viewer. (Yes, there are others, but you do NOT want to access them anyway)
An other way is to use a CDGenerate.GeneratorProc. This is handy if your procedure is supposed to return an object. If your procedure is a generator, it can be called interactively in a design, through a commandtool (if it can run in an emty design) and by programmed calls of the generator.
Which method to chose is dependent on the application, but here some criteria:
If interactive access is important: use a CDSequencer command.
If it returns an object: use a CDGenerate.GeneratorProc.
If running from commandfile is important: use the Cedar commander.
There different methods to get your hand on a design for output either:
Create the design; specially good for commandfile usage.
Modify an input design
and keep it visible on screen
and write it on a file
I think that non interactive programs shoud be simple, they read some designs and create and write a NEW output design. Interactive programs may well work on a design, which was found through a viewer, and stays there at the end. More complex mixtures might confuse designers.
5. Registering commands
Use CDSequencer to register a command. You have either to make a tiptable entry or use the pop up menus to call your command. (Module CDMenus) Typically $RectProgramMenu or $ProgramMenu are good pop up menus to register further entries. Commands which create objects can also be registered as generators (CDGenerate).
Aborting
The command should check for abort! well short commands which are immediately finished don't have to. There are several ways to check for abort.
Calling CDSequencer.CheckAborted will signal if the user aborted the command; this signal is catched by ChipNDale's command execution.
For applications which can not spend the time of busyly calling a check procedure, an Event mechanism exist. The event (CDEvents) $Abort is called when an abort is issued.
Applications which involve drawing some objects may use the stop flag of the drawrecord to cause finishing the drawing.
A handy feature is CDCommandOps.CallWithResource; this procedure catches an abort event and sets you an abort flag.
Resources
Certain modules use global variables which must be protected; CDCommandOps.CallWithResource is the tool to manage such resources.
Generally CDCommandOps is a module which gives you some "creaturecomfort-level" help in implementing commands. (CDCommandOps is not considered a part of the kernel of ChipNDale, but is loaded with any ChipNDale config which contains commands)
6. An example object generator
Example 1
Example.mesa
Example of ChipNDale usage
Copyright © 1985 by Xerox Corporation. All rights reserved.
by Christian Jacobi, June 5, 1985 8:02:35 pm PDT
Last Edited by Christian Jacobi, July 10, 1985 10:28:49 am PDT
DIRECTORY
CD,
CDGenerate, --0
CDDirectory,
CDUtil;
Example:
CEDAR
PROGRAM
IMPORTS CDDirectory, CDGenerate, CDUtil =
BEGIN
Test: CDGenerate.GeneratorProc =
--
3
--this generator fetches the objects "x", "y" and, "z" and creates a cell "test"-- --4
--which is an abut of "x", "y" and, "z" in x direction to the right.
BEGIN
ob1: CD.Object ← CDDirectory.Fetch[design, "x"].object; --5
ob2: CD.Object ← CDDirectory.Fetch[design, "y"].object;
ob3: CD.Object ← CDDirectory.Fetch[design, "z"].object;
ob ← CDUtil.CreateSimpleCell[design, LIST[[ob1], [ob2], [ob3]], "test", right]; --6
END;
table: CDGenerate.Table ← CDGenerate.AssertTable["USER"]; --1
[] ← table.Register["Test", Test]; --2
END.
0) Look at the actual definitions modules, they have lots of comments.
1) Get or create a generator environment called "USER".
2) Register the procedure Test with name "Test". The pop up menu of the generator USER will now show an entry Test.
3) This procedure will create an object.
4) Every procedure has some comment what it does.
5) This line will fetch an object "x" of the designs directory. The design is actually passed as parameter to the procedure Test. This simple example does not test if "x" was really found. Bad!.
6) The object ob is created. (ob is a return parameter of the procedure Test). Here we used CDUtil.CreateSimpleCell to create an simple abut. CDUtil.CreateSimpleCell does complete the creation of the object and includes it into the designs directory. More complex generators might create objects an other way...
CDUtil.CreateSimpleCell is only one example of many object creation procedures available for many purposes...
Example2
Example2.mesa
Example of ChipNDale usage
Copyright © 1985 by Xerox Corporation. All rights reserved.
by Christian Jacobi, June 5, 1985 8:02:35 pm PDT
Last Edited by Christian Jacobi, July 10, 1985 10:28:49 am PDT
DIRECTORY
CD,
CDGenerate,
CDGenerateRemote,
CDUtil;
Example2:
CEDAR
PROGRAM
IMPORTS CDGenerate, CDRemote, CDUtil =
BEGIN
Test2: CDGenerate.GeneratorProc =
--this generator fetches the objects "x" and "y" and creates a cell "abut"--
BEGIN
ob1: CD.Object ← CDGenerate.FetchNCall[library, design, "x"]; --8
ob2: CD.Object ← CDGenerate.FetchNCall[library, design, "y"];
IF ob1=NIL OR ob2=NIL THEN ERROR;
ob ← CDUtil.CreateSimpleCell[design, LIST[[ob1], [ob2]], "abut", right];
END;
library: CDGenerate.Table ← CDRemote.GetTable["Library"]; --7
table: CDGenerate.Table ← CDGenerate.AssertTable["USER"];
[] ← table.Register["Test2", Test2];
END.
7) Get or create a generator environment which gets objects from another design with name "Library".
8) This line will make a copy of the object "x" found in "Library"; the copy is included into the design "design". (Parameter of Test2).
This example could be called reasonably from a command tool:
% CDUtil
% run Example2
% CDGenerate Test2 * ← -cmos
however, probably it will crash because it will not find a design "Library". Make one with an object "x" and and object "y" and try again. Make sure the design name of this design is "Library"; to make it simpler, store it also on the file library.dale.
Example3
The next example is an inverter cell. This inverter had been drawn interactively, the program was then created automatically using the makeproc utility. This example is probably to long to be read; it is a source for you to experiment; it runs without preparing a library first.
To run it, run cmos, the example program and then type
% CDGenerate Temp * ← -cmos
--Example3.mesa
--created by ChipNDale
DIRECTORY
CDAtomicObjects, CDProperties, CDRects, CDCells, CDGenerate, CD, CDDirectory, CDSymbolicObjects;
Temp: CEDAR PROGRAM
IMPORTS CDAtomicObjects, CDProperties, CDRects, CDCells, CDGenerate, CD, CDDirectory, CDSymbolicObjects =
BEGIN
tech: CD.Technology ← CD.FetchTechnology[$cmos];
wpdif: CD.Layer ← CD.FetchLayer[t: tech, uniqueKey: $wpdif];
nwel: CD.Layer ← CD.FetchLayer[t: tech, uniqueKey: $nwel];
met: CD.Layer ← CD.FetchLayer[t: tech, uniqueKey: $met];
pol: CD.Layer ← CD.FetchLayer[t: tech, uniqueKey: $pol];
nwelCont: CD.Layer ← CD.FetchLayer[t: tech, uniqueKey: $nwelCont];
ndif: CD.Layer ← CD.FetchLayer[t: tech, uniqueKey: $ndif];
CreateCell: CDGenerate.GeneratorProc =
BEGIN
inst: CD.Instance;
pinOb0: CD.Object;
alignmentMarkOb: CD.Object;
cWellSimpleCon: CD.Object;
rect: CD.Object;
child: CD.Object;
IF design.technology#tech THEN ERROR;
ob ← CDCells.CreateEmptyCell[];
child ← CDAtomicObjects.CreateAtomicOb[classKey: $CWellTrans, size: [x: 48, y: 12], tech: tech, lev: wpdif];
[] ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 28, y: 42], orientation: 2];
cWellSimpleCon ← CDAtomicObjects.CreateAtomicOb[classKey: $CWellSimpleCon, size: [x: 8, y: 8], tech: tech, lev: wpdif];
[] ← CDCells.IncludeOb[cell: ob, ob: cWellSimpleCon, position: [x: 10, y: 78], orientation: 5];
child ← CDRects.CreateRect[size: [x: 44, y: 60], l: nwel];
[] ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 0, y: 36]];
pinOb0 ← CDSymbolicObjects.CreatePin[[x: 4, y: 4]];
inst ← CDCells.IncludeOb[cell: ob, ob: pinOb0, position: [x: 20, y: 0]].newInst;
CDSymbolicObjects.SetName[inst, "in"];
inst ← CDCells.IncludeOb[cell: ob, ob: pinOb0, position: [x: 20, y: 86]].newInst;
CDSymbolicObjects.SetName[inst, "in"];
inst ← CDCells.IncludeOb[cell: ob, ob: pinOb0, position: [x: 34, y: 86]].newInst;
CDSymbolicObjects.SetName[inst, "out"];
inst ← CDCells.IncludeOb[cell: ob, ob: pinOb0, position: [x: 34, y: 0]].newInst;
CDSymbolicObjects.SetName[inst, "out"];
alignmentMarkOb ← CDSymbolicObjects.CreateMark[dummySize: 4];
inst ← CDCells.IncludeOb[cell: ob, ob: alignmentMarkOb, position: [x: 42, y: 90]].newInst;
CDSymbolicObjects.SetName[inst, "UpperRight"];
inst ← CDCells.IncludeOb[cell: ob, ob: alignmentMarkOb, position: [x: 4, y: 0]].newInst;
CDSymbolicObjects.SetName[inst, "BottomLeft"];
rect ← CDRects.CreateRect[size: [x: 12, y: 38], l: met];
inst ← CDCells.IncludeOb[cell: ob, ob: rect, position: [x: 4, y: 0], orientation: 3].newInst;
CDProperties.PutPropOnInstance[inst, $SignalName, "GND"];
child ← CDRects.CreateRect[size: [x: 4, y: 22], l: pol];
[] ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 34, y: 68]];
child ← CDAtomicObjects.CreateAtomicOb[classKey: $CSimpleCon, size: [x: 8, y: 8], tech: tech, lev: nwelCont];
[] ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 8, y: 86], orientation: 5];
child ← CDAtomicObjects.CreateAtomicOb[classKey: $CButtingCont, size: [x: 8, y: 12], tech: tech, lev: ndif];
[] ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 38, y: 18], orientation: 2];
child ← CDRects.CreateRect[size: [x: 6, y: 28], l: met];
inst ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 28, y: 54], orientation: 5].newInst;
CDProperties.PutPropOnInstance[inst, $SignalName, "output"];
child ← CDAtomicObjects.CreateAtomicOb[classKey: $CWellButtingCont, size: [x: 8, y: 12], tech: tech, lev: wpdif];
[] ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 38, y: 64], orientation: 2];
[] ← CDCells.IncludeOb[cell: ob, ob: cWellSimpleCon, position: [x: 34, y: 46], orientation: 1];
child ← CDAtomicObjects.CreateAtomicOb[classKey: $CSimpleCon, size: [x: 8, y: 8], tech: tech, lev: ndif];
[] ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 18, y: 4], orientation: 1];
child ← CDRects.CreateRect[size: [x: 6, y: 1], l: met];
[] ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 12, y: 80]];
child ← CDRects.CreateRect[size: [x: 4, y: 18], l: pol];
inst ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 34, y: 0]].newInst;
CDProperties.PutPropOnInstance[inst, $SignalName, "OUT"];
inst ← CDCells.IncludeOb[cell: ob, ob: rect, position: [x: 4, y: 78], orientation: 3].newInst;
CDProperties.PutPropOnInstance[inst, $SignalName, "VDD"];
child ← CDRects.CreateRect[size: [x: 4, y: 36], l: pol];
inst ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 20, y: 6]].newInst;
CDProperties.PutPropOnInstance[inst, $SignalName, "IN"];
child ← CDAtomicObjects.CreateAtomicOb[classKey: $CTrans, size: [x: 28, y: 12], tech: tech, lev: ndif];
[] ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 16, y: 0], orientation: 3];
child ← CDRects.CreateRect[size: [x: 6, y: 10], l: met];
[] ← CDCells.IncludeOb[cell: ob, ob: child, position: [x: 28, y: 54]];
CDCells.SetInterestRect[ob, [x1: 4, y1: 0, x2: 42, y2: 90]];
[] ← CDDirectory.Include[design: design, object: ob, alternateName: "Inverter"];
END;
table: CDGenerate.Table ← CDGenerate.AssertTable["USER"];
[] ← table.Register["Temp", CreateCell];
END.
7. All the fuss about Coordinate systems
Coordinates are the standard way: increasing from left to right or from down to up. There are eight orientations. (See CDOrient).
CDCells exports 3 coordinate systems:
CoordSystem:
TYPE = {cdCoords, interrestCoords, originCoords};
-- cdCoords: chipndales internal and native coordinate system used in Instances
-- interrestCoords: base of interest-rects.
-- originCoords: invariant fake origin which for cells never changes, but might be far off...
I strongly think if you are using one of them it is quite advantageous to know all of them. I have not yet seen an application where only one of the coordinate systems is needed...
cdCoords: This is the only coordinate system you'll ever need...
If you want to do all the computations yourself.
ChipNDale internally uses ALLWAYS cdCoords. That where its name come from.
interrestCoords: This is the only coordinate system you'll ever need...
If you ask fans of abuts.
originCoords: This is the only coordinate system you'll ever need...
If you want a coordinate system where you have your own control and where the coordinates of object origins never change underneath you.
cdCoords
If you find numbers in data types of ChipNDale, like in Instances, these numbers are cdCoords.
cdCoords are actually the real truth, but they have some severe problems for certain applications. To gain (significantly!) speed in the process of displaying ChipNDale designs in viewers and other devices, cdCoords are defined such that the [0, 0] origin in cdCoords matches the lower left point of objects. Lower left point is defined as lower left point of the object which needs to be drawn. (There might be elecrical, magical or other influences more to the left or lower, but this lower left is used to determine the clipping boundary for displaying). Unhappily when cells are edited the position of the lower left point might change relative to some stable points in the cell. To maintain the lower-left-[0, 0] invariant ChipNDale (at some time) performs a coordinate system translation (called reposition); the position of all instances in the cell will change. If you maintain a copy of some coordinate in the cell, your copy probably will no more be correct.
When ChipNDale repositions a cell this is really made complete: the instances inside the cell get new coordinates. All instances of this cell in the whole design are then checked and translated, such that it exactly compensate for the coordinate system translation inside the cell: The design as a whole does not change. To get this process right it is necessary that the directory invariants are hold.
The complicate reposition process may be speed up if a cell is first created and repositioned and only thereafter included into a design. IncludeMode is a type which allows to postbone repositioning on IncludeOb, it can then be done using RepositionCell.
The position of an oriented object in cdCoords is the position of its lower left point after the orientation is applied.
interrestCoords
The interest rect is an (artifical) rectangle denoting the users interest. It might therefore be conveniant to use it's lower left point as origin of some coordinate system. This is specially the case for abuts.
The coordinates returned by a procedure CD.InterestRect[mumble] are of course cdCoords.
The coordinates of the interest rect might change on any repositioning process, the coordinates of the interest rect might also change on user requests. Finally, when the interest rect is defaulted, its coordinates might even change by including or removing sub-objects into a cell.
The position of an oriented object in interrestCoords is the position of the lower left point of the already oriented interest rect.
originCoords
This is the hassle free coordinate system for lazy applications. The position of the origin is returned by CD.ClientOrigin and is of course told in cdCoords. Whenever some repositioning happens the position of the origin is updated, such that relative positions of points relative to the origin will NOT change. There is no guarantee that with multiple edits the origin might not lie outside a cell...
The position of an oriented object in originCoords is the position of the objects origin.
The origin of rectangles is the lower left point of its interest rect before its orientation.
The wonderfull stableness of these originCoords is paid by needing more overhaed at run time.