ChipNDaleProgramsDoc.tioga
Christian Jacobi, November 30, 1984 6:07:50 pm PST
Christian Jacobi, April 7, 1987 10:58:37 am PDT
ChipNDale
ChipNDale 2.5 — FOR INTERNAL XEROX USE ONLY
ChipNDale
An interactive editor for VLSI designs
Programmers Manual
Release 2.5
Christian Jacobi, April 7, 1987
A relatively incomplete documentation.
Filed on: [Indigo]<ChipNDale>7.0>CDDoc25>ChipNDaleProgramsDoc.tioga

© Copyright 1985, 1986, 1987 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.
XEROXXerox 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
8. Garbage Collection Of Designs
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, CDBasics, CDInstances
Basic Objects
CDCells, CDRects, CDSymbolicObjects
Less Basic Structures
CDExtras
Less Basic Objects
CDImports, CDRepetitions, CDAtomicObjects, CDTexts, CDCurves
Generator stuff
CDGenerate, CDGenerateBackdoor
Some Generators
CDGenerateImports, CDRemote
Utilities for generators (not all automatically loaded)
CDUtil, CDCreateLabels
IO
TerminalIO, CDIO, CDEnvironment
Implementors IO
TokenIO, CDRopeViewer
Extension Mechanism
CDProperties, CDValue, CDEvents
Introducing commands
CDSequencer, (CDGenerate)
Registering a technology
CDEnvironment, CDPanel, CDColors, CDAtomicObjects, CDDefaultProcs, CDLayers
Handy stuff on command level
CDOps, CDCommandOps, CDViewer, CDDirectoryOps, CDPropertyTools, CDCleanUp
Getting hand on
CDSimpleRules, CDViewer
Crazy stuff
CDStretchyBackdoor, CDImportsExtras, CDPrivate
Displaying special things
CDViewHighlight, CDViewer, CDErrors
Private viewer stuff
CDVScale, CDVArrow, CDVTicks, CDVPrivate, CDViewerBackdoor
Internal stuff
CDDrawQueue, CDLayers
Technology stuff
CMos stuff
CMosB, CMos, CMosObjects
NMos stuff
NMos, NMosTransistors, NMosContacts
Related stuff
CStitching
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 havn't 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, therefore 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; patchWork, PWCore
-Implementing new simple commands. (eg. Split wire)
-Implementing new object classe. (eg. Repetitions, RoutingObjects)
-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 any generator environment: CDGenerate.GeneratorProc or PWCore. 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 or PWCore.
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. 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 D2Orient).
8. Garbage Collection Of Designs
Garbage collecting a designs object when a design is garbage collected is very handy:
It breaks circular refs using object or instance properties.
These circular refs happen for three reasons:
Spinifex uses them.
They simplify design of certain tools quite a lot.
Some tools introduce circularity unwanted and unknown; some people might call that bugs.
Garbage collecting objects is invisible:
Modifying objects when designs are garbage collected will never be noticed by any client:
Read-only objects are never touched [Checked in garbage collection].
Read-write objects are never included into more than 1 design. [Never ever: I have Brians, Ricks and Bertrands promise. If it happens, ChipNDale is allowed to call the world swap debugger.] Since a garbage collected object was in a design it can not be reached using any other design or anything else as root; you can't notice what the garbage collection does to this object.
Shure it is difficult to find bugs where an object is included into more than 1 design, but it is still much easier than to detect circular refs!!
Garbage collecting objects depends on designs mutability:
findOut:
Mutability is not yet defined; garbage collection does not touch any objects; it does not know what the objects are used for. A message is made on terminal, so you have a chance to detect that this problem occurs.
editable, readonly:
Breaks up circular refs, get rid of [mutable] objects.
Small point: Why change object instead of removing properties: In error case, a changed object is recognized easy; removed properties might not be noticed and could cause their harm secretely.
inaccessible:
Objects are not touched if this design is garbage collected [this design is not allowed to change any objects]. But objects are garbage collected if their real home design is garbage collected. [This is no special case: the real home design is allowed to do any changes to the objects, it might be editable]
A last resort if you cant stand it:
If you don't want a design to be garbage collected: Don't do tricks with ChipNDale; simply keep a ref... [That method is used by ChipNDale to keep imported objects]