CDIn.mesa
Copyright © 1983, 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Kimr, November 28, 1983 10:22 am
Last Edited by: Jacobi, February 8, 1984 9:41 am
Last Edited by: Christian Jacobi, January 10, 1987 11:24:34 am PST
DIRECTORY
Atom,
Ascii,
BasicTime,
Commander,
CD,
CDBasics,
CDCells,
CDDirectory,
CDEnvironment,
CDEvents,
CDInstances,
CDIO,
CDSequencer USING [CheckAborted],
CDOps,
CDPrivate,
CDProperties,
CDRects,
CDValue,
Convert,
FileNames,
FS,
IO,
PropertyLists,
RefTab,
Rope,
RuntimeError USING [UNCAUGHT],
TerminalIO,
TokenIO,
CDOldInterestRects;
CDIn: CEDAR PROGRAM
IMPORTS Atom, BasicTime, Commander, Convert, CD, CDBasics, CDCells, CDDirectory, CDEnvironment, CDEvents, CDInstances, CDIO, CDOps, CDPrivate, CDProperties, CDRects, CDSequencer, CDValue, FileNames, FS, IO, PropertyLists, RefTab, Rope, RuntimeError, TerminalIO, TokenIO, CDOldInterestRects
EXPORTS CDIO
SHARES CD, CDDirectory =
BEGIN
xChipndaleFile: INT = 12121983;
xVersion: INT = 16;
Version: PROC [h: TokenIO.Handle] RETURNS [INT] = INLINE {
RETURN [IF h.oldVersion THEN VersionKey[h] ELSE xVersion ]
};
IndexTable: TYPE = RECORD[table: SEQUENCE max: CARDINAL OF CD.Object];
TableTable: TYPE = RECORD[tt: SEQUENCE max: CARDINAL OF REF IndexTable];
maxTableSize: INT = 32000;
signalOnPropertyProblem: BOOLTRUE; --set variable with debugger
setManually: INT ← 0; --used for saving old designs
specialForVersion4: BOOLFALSE;
GetTableEntry: PROC[h: TokenIO.Handle, i: INT] RETURNS [ob: CD.Object←NIL] = INLINE {
IF i<maxTableSize THEN {
indexTable: REF IndexTable ← NARROW[PropertyLists.GetProp[h.properties^, $IndexTable]];
ob ← indexTable.table[i];
}
ELSE {
tableTable: REF TableTable ← NARROW[PropertyLists.GetProp[h.properties^, $TableTable]];
ob ← tableTable.tt[i/maxTableSize-1].table[i MOD maxTableSize];
};
IF ob=NIL THEN TerminalIO.PutRope["*** read object failed\n"];
};
SetTableEntry: PROC[h: TokenIO.Handle, i: INT, ob: CD.Object] = INLINE {
IF i<maxTableSize THEN {
indexTable: REF IndexTable ← NARROW[CDProperties.GetPRefProp[h.properties, $IndexTable]];
indexTable.table[i] ← ob
}
ELSE {
tableTable: REF TableTable ← NARROW[CDProperties.GetPRefProp[h.properties, $TableTable]];
tableTable.tt[i/maxTableSize-1].table[i MOD maxTableSize] ← ob;
}
};
AllocateTables: PROC[h: TokenIO.Handle, i: INT] = {
indexTable: REF IndexTable ← NEW[IndexTable[MIN[i, maxTableSize]]];
CDProperties.PutPRefProp[h.properties, $IndexTable, indexTable];
IF i>=maxTableSize THEN {
tableTable: REF TableTable ← NEW[TableTable[i/maxTableSize]];
CDProperties.PutPRefProp[h.properties, $TableTable, tableTable];
FOR n: INT IN [0..i/maxTableSize) DO -- don't be picky with size if it is anyway as big
tableTable.tt[n] ← NEW[IndexTable[maxTableSize]]
ENDLOOP
};
};
ReadProperties: PUBLIC PROC [h: TokenIO.Handle] RETURNS [props: CD.PropList←NIL] = {
PropertyProblem: PROC [h: TokenIO.Handle, key: ATOMNIL, skip: BOOLFALSE] = {
TerminalIO.PutRope["**** property not readable"];
IF key#NIL THEN {
TerminalIO.PutRopes["; probably ", Atom.GetPName[key]];
};
TerminalIO.PutRope["\n"];
IF signalOnPropertyProblem THEN SIGNAL TokenIO.EncodingError;
IF skip THEN TokenIO.Skip[h];
};
CheckNoRegistration: PROC [a: ATOM] RETURNS [ok: BOOL] = {
--ok means NOT registered
propProcs: CDProperties.PropertyProcs ← CDProperties.FetchProcs[a];
ok ← propProcs=NIL OR propProcs.internalRead=NIL;
IF ~ok THEN {
TerminalIO.PutRope["**** property registered and not readable"];
PropertyProblem[h, a];
};
};
ExplicitProperty: PROC [h: TokenIO.Handle] = {
key: ATOM; propProcs: CDProperties.PropertyProcs;
token: TokenIO.Token ← TokenIO.Read[h];
WITH token SELECT FROM
push2: TokenIO.Token.push2 => key ← push2.value;
push: TokenIO.Token.push => {
--only old version may use that !
IF Version[h]>=16 THEN SIGNAL TokenIO.EncodingError;
key ← push.value;
};
ENDCASE => SIGNAL TokenIO.EncodingError;
propProcs ← CDProperties.FetchProcs[key];
IF propProcs#NIL AND propProcs.internalRead#NIL THEN {
props ← PropertyLists.PutProp[props, key, propProcs.internalRead[h, key]];
}
ELSE IF Version[h]>=12 THEN {
n: Rope.ROPE ← Atom.GetPName[key];
TerminalIO.PutRopes["**** property ", n, " not registered\n"];
CDEnvironment.ExecFileEntry[n, CDIO.DesignInReadOperation[h].technology];
propProcs ← CDProperties.FetchProcs[key];
IF propProcs#NIL AND propProcs.internalRead#NIL THEN {
props ← PropertyLists.PutProp[props, key, propProcs.internalRead[h, key]];
}
ELSE {
TerminalIO.PutRope["failed"];
IF signalOnPropertyProblem THEN SIGNAL TokenIO.EncodingError;
};
}
ELSE OldDefaultProperty[key];
TokenIO.ReadPop[h ! TokenIO.EncodingError => PropertyProblem[h, key, TRUE]];
};
DefaultProperty: PROC [h: TokenIO.Handle] = {
PushCase: PROC [key: ATOM] = {
IF CheckNoRegistration[key] THEN {
SELECT TokenIO.ReadAtom[h] FROM
$properties => {
propertieProps: CD.PropList ← ReadProperties[h];
props ← PropertyLists.PutProp[props, key, propertieProps];
};
$layer => {
layer: CD.Layer ← ReadLayer[h];
props ← PropertyLists.PutProp[props, key, CDPrivate.layers[layer]]
};
$ropeList => {
rList: LIST OF Rope.ROPENIL;
DO
token: TokenIO.Token ← TokenIO.Read[h];
WITH token SELECT FROM
rope: TokenIO.Token.rope => rList ← CONS[rope.value, rList];
ENDCASE => {
TokenIO.ReadAgain[h, token];
props ← PropertyLists.PutProp[props, key, rList];
EXIT;
}
ENDLOOP
};
ENDCASE => PropertyProblem[h, key, FALSE];
TokenIO.ReadPop[h ! TokenIO.EncodingError => PropertyProblem[h, key, TRUE]];
};
};
token: TokenIO.Token ← TokenIO.Read[h];
WITH token SELECT FROM
atom: TokenIO.Token.atom =>
IF CheckNoRegistration[atom.value] THEN {
token: TokenIO.Token ← TokenIO.Read[h];
WITH token SELECT FROM
ropex: TokenIO.Token.rope =>
props ← PropertyLists.PutProp[props, atom.value, ropex.value];
atomx: TokenIO.Token.atom =>
props ← PropertyLists.PutProp[props, atom.value, atomx.value];
intx: TokenIO.Token.int =>
props ← PropertyLists.PutProp[props, atom.value, NEW[INT←intx.value]];
ENDCASE => PropertyProblem[h, atom.value];
};
push2: TokenIO.Token.push2 => PushCase[push2.value];
push: TokenIO.Token.push => {
IF Version[h]>=16 THEN SIGNAL TokenIO.EncodingError;
PushCase[push.value];
};
ENDCASE => PropertyProblem[h, NIL];
};
OldDefaultProperty: PROC [key: ATOM] = {
token: TokenIO.Token ← TokenIO.Read[h];
WITH token SELECT FROM
rope: TokenIO.Token.rope =>
props ← PropertyLists.PutProp[props, key, rope.value];
atom: TokenIO.Token.atom =>
props ← PropertyLists.PutProp[props, key, atom.value];
int: TokenIO.Token.int =>
props ← PropertyLists.PutProp[props, key, NEW[INT←int.value]];
pop: TokenIO.Token.pop => {
TokenIO.ReadAgain[h, token];
props ← PropertyLists.PutProp[props, key, key]
};
push: TokenIO.Token.push => {
IF push.value=NIL OR push.value=$properties THEN {
propertieProps: CD.PropList ← ReadProperties[h];
props ← PropertyLists.PutProp[props, key, propertieProps];
}
ELSE IF push.value=$layer THEN {
layer: CD.Layer ← ReadLayer[h];
props ← PropertyLists.PutProp[props, key, CDPrivate.layers[layer]]
}
ELSE PropertyProblem[h, key];
TokenIO.ReadPop[h ! TokenIO.EncodingError => PropertyProblem[h, key]];
};
ENDCASE => PropertyProblem[h, key];
};
DO
token: TokenIO.Token ← TokenIO.Read[h];
WITH token SELECT FROM
atom: TokenIO.Token.atom =>
SELECT atom.value FROM
$Property => ExplicitProperty[h];
$DefaultProperty => DefaultProperty[h];
ENDCASE => {TokenIO.ReadAgain[h, token]; RETURN};
ENDCASE => {TokenIO.ReadAgain[h, token]; RETURN};
ENDLOOP;
};
DirectoryOp: PROC [me: CD.Object, design: CD.Design, name: Rope.ROPE, function: CDDirectory.DirectoryFunction] RETURNS [proceed: BOOL] ~ INLINE {
IF proceed←me.class.inDirectory THEN {
dp: CDDirectory.DirectoryProc ← CDDirectory.ObToDirectoryProcs[me].directoryOp;
IF dp#NIL THEN proceed ← dp[me, design, name, function]
}
};
ReadObjectDefinition: PROC [h: TokenIO.Handle, pushRec: BOOLFALSE] RETURNS [obj: CD.Object←NIL] = {
index: INT ← -1;
name: Rope.ROPE;
versionKey: INT ~ Version[h];
atom: ATOM ← TokenIO.ReadPush[h];
design: CD.Design ~ InlineDesignInReadOperation[h];
class: CD.ObjectClass ← CD.FetchObjectClass[atom, design.technology];
CDSequencer.CheckAborted[design];
IF class=NIL OR class.internalRead=NIL THEN {
IF atom#NIL THEN {TerminalIO.PutRope["NIL is a bad object class\n"]; RETURN}
ELSE {
n: Rope.ROPE ~ Atom.GetPName[atom];
TerminalIO.PutRopes["object class ", n, " not registered\n"];
CDEnvironment.ExecFileEntry[n, design.technology];
class ← CD.FetchObjectClass[atom, design.technology];
}
};
IF class=NIL OR class.internalRead=NIL THEN {
TerminalIO.PutF1["reading object class %g failed\n", [atom[atom]]];
TokenIO.Skip[h];
obj ← CDRects.CreateBareRect[[10, 10], CD.errorLayer];
RETURN
};
IF versionKey>=15 THEN {
IF class.inDirectory THEN {
index ← TokenIO.ReadInt[h];
}
ELSE {
token: TokenIO.Token ← TokenIO.Read[h];
WITH token SELECT FROM
atom: TokenIO.Token.atom =>
IF atom.value=$CDIOUseTable THEN index ← TokenIO.ReadInt[h]
ELSE TokenIO.ReadAgain[h, token];
ENDCASE => TokenIO.ReadAgain[h, token];
};
};
obj ← class.internalRead[h, atom];
IF obj=NIL OR obj.class=NIL THEN
obj ← NEW[CD.ObjectRep ← CDRects.CreateRect[[10, 10], CD.errorLayer]^];
IF index>0 THEN SetTableEntry[h, index, obj];
IF versionKey>0 THEN {
IF class.inDirectory THEN {
name ← TokenIO.ReadRope[h];
IF versionKey<=4 THEN [] ← TokenIO.ReadRope[h]; --ignore an old versionkey feature
};
};
BEGIN
token: TokenIO.Token ← TokenIO.Read[h];
WITH token SELECT FROM
pop: TokenIO.Token.pop => NULL;
ENDCASE => {
TokenIO.ReadAgain[h, token];
obj.properties ← ReadProperties[h];
TokenIO.ReadPop[h];
IF versionKey<8 THEN CDOldInterestRects.AdjustInterest[h, obj];
};
END;
IF obj.class.inDirectory THEN {
[] ← DirectoryOp[obj, NIL, name, rename];
IF versionKey>=15 THEN {
IF ~CDDirectory.IsOwner[design, obj] AND ~pushRec THEN
[] ← CDDirectory.Include[design, obj, name];
};
};
};
ReadObject: PUBLIC PROC [h: TokenIO.Handle] RETURNS [ob: CD.Object←NIL] = {
t: TokenIO.Token ~ TokenIO.Read[h];
WITH t SELECT FROM
int: TokenIO.Token.int => ob ← GetTableEntry[h, int.value];
push: TokenIO.Token.push => {
TokenIO.ReadAgain[h, t]; ob ← ReadObjectDefinition[h];
};
ENDCASE => SIGNAL TokenIO.EncodingError[];
};
Get23Table: PROC [h: TokenIO.Handle] RETURNS [RefTab.Ref←NIL] = {
rt: RefTab.Ref;
WITH PropertyLists.GetProp[h.properties^, $convert23] SELECT FROM
tab: RefTab.Ref => rt ← tab;
ENDCASE => {
rt ← RefTab.Create[201];
h.properties^ ← PropertyLists.PutProp[h.properties^, $convert23, rt]
};
RETURN [rt];
};
BBox23: PROC [ob: CD.Object, h: TokenIO.Handle] RETURNS [bbox: CD.Rect] = {
bbox←ob.bbox;
IF ob.class.inDirectory THEN
WITH RefTab.Fetch[Get23Table[h], ob].val SELECT FROM
rr: REF CD.Rect => RETURN [rr^]
ENDCASE => NULL;
};
FitObject23: PROC [ob: CD.Object, location: CD.Position ← [0, 0], orientation: CD.Orientation ← CD.Orientation[original], h: TokenIO.Handle] RETURNS [trans: CD.Transformation] = {
--for the conversion from cd2.3 to cd2.4 use bbox with interest rect excluded
oldR: CD.Rect ← ob.bbox;
IF CDCells.IsCell[ob] THEN oldR ← BBox23[ob, h];
WITH ob.specific SELECT FROM
cp: CD.CellSpecific => IF cp.specifiedIr THEN
oldR ← CDCellsBackdoor.Bounds[list: cp.contents, seq: cp.sequence, doIr: FALSE, doBb: TRUE].bbox;
ENDCASE => NULL;
trans.orient ← orientation;
trans.off ← CDBasics.SubPoints[location, CDBasics.BaseOfRect[CDBasics.MapRect[oldR, [[0, 0], orientation]]]];
};
FitObjectO: PROC [ob: CD.Object, location: CD.Position ← [0, 0], orientation: CD.Orientation ← CD.Orientation[original]] RETURNS [trans: CD.Transformation] = {
trans.orient ← orientation;
trans.off ← CDBasics.SubPoints[location, CDBasics.BaseOfRect[CDBasics.MapRect[ob.bbox, [[0, 0], orientation]]]];
};
OldReadInstance: PROC [h: TokenIO.Handle] RETURNS [inst: CD.Instance] = {
location: CD.Position ← ReadPos[h];
orientation: CD.Orientation ← CDIO.ReadOrientation[h];
properties: CD.PropList ← ReadProperties[h];
ob: CD.Object ← ReadObject[h];
versionKey: INT ~ Version[h];
IF versionKey>=8 THEN {
inst ← NEW[CD.InstanceRep ← [trans: FitObject23[ob, location, orientation, h], properties: properties, ob: ob]]
}
ELSE {
IF versionKey>=5 THEN {
??? better instead of I: CDOldInterestRects.InsideRect[ob]
inst ← NEW[CD.InstanceRep ← [trans: CDOps.FitObjectI[ob, location, orientation], properties: properties, ob: ob]]
}
ELSE { --ancient cases
absoluteMode: BOOLTRUE;
IF versionKey<3 THEN absoluteMode←TRUE
ELSE IF versionKey=4 THEN {
IF specialForVersion4 THEN
IF ob.class.inDirectory THEN absoluteMode←TRUE ELSE absoluteMode←FALSE
ELSE absoluteMode←FALSE
}
ELSE IF versionKey=3 THEN {
IF ob.class.inDirectory THEN absoluteMode←TRUE ELSE absoluteMode←FALSE
};
IF setManually=1 THEN absoluteMode←TRUE
ELSE IF setManually=2 THEN absoluteMode←FALSE
ELSE IF setManually=3 THEN absoluteMode←ob.class.inDirectory;
IF absoluteMode THEN
inst ← NEW[CD.InstanceRep ← [trans: FitObjectO[ob, location, orientation], properties: properties, ob: ob]]
ELSE
inst ← NEW[CD.InstanceRep ← [trans: CDOps.FitObjectI[ob, location, orientation], properties: properties, ob: ob]]
};
};
};
ReadInstance: PUBLIC PROC [h: TokenIO.Handle] RETURNS [inst: CD.Instance] = {
IF Version[h]<=15 THEN RETURN [OldReadInstance[h]]
ELSE {
location: CD.Position ← ReadPos[h];
orientation: CD.Orientation ← ReadOrientation[h];
properties: CD.PropList ← ReadProperties[h];
ob: CD.Object ← ReadObject[h];
inst ← NEW[CD.InstanceRep ← [trans: [location, orientation], properties: properties, ob: ob]]
}
};
ReadPos: PUBLIC PROC [h: TokenIO.Handle] RETURNS [p: CD.Position] = {
p.x ← TokenIO.ReadInt[h];
p.y ← TokenIO.ReadInt[h];
};
ReadRect: PUBLIC PROC [h: TokenIO.Handle] RETURNS [r: CD.Rect] = {
r.x1 ← TokenIO.ReadInt[h];
r.y1 ← TokenIO.ReadInt[h];
r.x2 ← TokenIO.ReadInt[h];
r.y2 ← TokenIO.ReadInt[h];
};
ReadPushRec: PROC [h: TokenIO.Handle] RETURNS [pr: CD.PushRec] = {
dummy: CD.Object;
token: TokenIO.Token ← TokenIO.Read[h];
WITH token SELECT FROM
atom: TokenIO.Token.atom => {
IF atom.value=$Nil THEN pr.mightReplace←NIL
ELSE {
TokenIO.ReadAgain[h, token];
pr.mightReplace ← ReadInstance[h];
}
};
ENDCASE =>{
TokenIO.ReadAgain[h, token];
pr.mightReplace ← ReadInstance[h];
};
dummy ← ReadObjectDefinition[h, TRUE];
pr.specific ← NARROW[dummy.specific, CD.CellSpecific];
pr.specific.changed ← TRUE;
ToListMode[pr.specific];
pr.specific.dummyCell ← TRUE;
IF Version[h]<=15 AND Version[h]>=11 THEN {
pr.specific.ir ← ReadRect[h];
};
pr.dummyCell ← CDInstances.NewInst[ob: dummy];
};
ToListMode: PROC [cp: CD.CellSpecific] = {
old: CD.InstanceSequence ← cp.sequence;
cp.sequence ← NIL;
IF old#NIL THEN
FOR n: NAT IN [0..old.length) DO
cp.contents ← CONS[old[n], cp.contents]
ENDLOOP;
};
ReadLayer: PUBLIC PROC [h: TokenIO.Handle] RETURNS [CD.Layer] = {
key: ATOM ← TokenIO.ReadAtom[h];
IF Version[h]<=12 THEN {
--The layer keys have changed from ChipNDale 2.2 to ChipNDale 2.3.
SELECT key FROM
$combined => key ← $undefLayer;
$highLightShade => key ← $shadeLayer;
$highLightError => key ← $errorLayer;
$backGround => key ← $backGround;
ENDCASE => NULL;
};
RETURN [CD.FetchLayer[InlineDesignInReadOperation[h].technology, key]];
};
ReadSubObjects: PROC [h: TokenIO.Handle] = {
obj: CD.Object;
DO
token: TokenIO.Token ← TokenIO.Read[h];
TokenIO.ReadAgain[h, token];
WITH token SELECT FROM
push: TokenIO.Token.push => obj ← ReadObject[h];
int: TokenIO.Token.int => obj ← ReadObject[h];
ENDCASE => EXIT;
ENDLOOP;
};
ReadDesignData: PROC [h: TokenIO.Handle, design: CD.Design] = {
versionKey: INT ← Version[h];
index, directoryCount: INT;
obj: CD.Object;
directoryCount ← TokenIO.ReadInt[h];
AllocateTables[h, directoryCount+1];
IF versionKey>=15 THEN ReadSubObjects[h]
ELSE {
FOR n: INT IN [1..directoryCount] DO
index ← TokenIO.ReadInt[h];
obj ← ReadObject[h];
SetTableEntry[h, index, obj];
IF versionKey=0 THEN {
DO
token: TokenIO.Token ← TokenIO.Read[h];
WITH token SELECT FROM
rope: TokenIO.Token.rope => {
obx: INT = TokenIO.ReadInt[h];
[] ← CDDirectory.Include[design, GetTableEntry[h, obx], rope.value];
}
ENDCASE => {TokenIO.ReadAgain[h, token]; EXIT};
ENDLOOP
}
ELSE IF obj.class.inDirectory THEN {
--hack to simplify some read procedures...
IF ~CDDirectory.IsOwner[design, obj] THEN {
name: Rope.ROPE = CDDirectory.Name[obj];
[] ← CDDirectory.Include[design, obj, name];
}
}
ENDLOOP;
};
design.properties ← NEW[CD.PropList←ReadProperties[h]];
--this overwrites an previous $FileVersion property read in the normal (wrong) way
CDProperties.PutDesignProp[design, $FileVersion, CDProperties.GetProp[h.properties, $FileVersion]];
design.actual ← NIL;
DO
token: TokenIO.Token ← TokenIO.Read[h];
WITH token SELECT FROM
atom: TokenIO.Token.atom =>
IF atom.value=$Push THEN {design.actual ← CONS[ReadPushRec[h], design.actual]}
ELSE {TokenIO.ReadAgain[h, token]; EXIT};
ENDCASE => {TokenIO.ReadAgain[h, token]; EXIT};
ENDLOOP;
IF TokenIO.ReadAtom[h]#$EndOfDesign THEN SIGNAL TokenIO.EncodingError;
};
ReadDesign: PUBLIC PROC [from: REFNIL, check: PROC [h: TokenIO.Handle] RETURNS [BOOL] ← NIL, wDir: Rope.ROPENIL, stop: REF BOOLNIL] RETURNS [design: CD.Design←NIL] = {
wDirUsed: Rope.ROPENIL;
DoInner: PROC [h: TokenIO.Handle] RETURNS [design: CD.Design←NIL] = {
ENABLE {
TokenIO.EncodingError => {
TerminalIO.PutRope["** TokenIO encoding problem\n"];
REJECT;
};
RuntimeError.UNCAUGHT => {
TerminalIO.PutRope["** problem while reading; abort or proceed\n"];
REJECT
};
UNWIND => {
TokenIO.Close[h, iDidTheOpen];
};
};
TechnologyCheck: PROC [h: TokenIO.Handle] = {
--Side-effect: if bad, design is set to NIL
ENABLE UNWIND => design ← NIL;
dont: BOOL ← CDEvents.ProcessEvent[ev: readEvent, design: design, x: h, listenToDont: TRUE].dont;
IF dont THEN {
design ← NIL;
TerminalIO.PutRope["**technology rejects read\n"];
}
};
VersionAndSealCheck: PROC [h: TokenIO.Handle] = {
--ChipNDale check
versionKey: INT;
IF TokenIO.ReadInt[h]#xChipndaleFile THEN {
TerminalIO.PutRope["File is not a ChipNDale design\n"];
ERROR TokenIO.EncodingError;
};
--version check
versionKey ← TokenIO.ReadInt[h];
CDProperties.PutProp[h.properties, $VersionKey, NEW[INT←versionKey]];
IF versionKey#xVersion THEN {
OldMsg: PROC [versionKey: INT, bar: BOOLFALSE, conv: BOOLFALSE, extra: Rope.ROPENIL] = {
IF bar THEN TerminalIO.PutRope["****\n"];
TerminalIO.PutF1["design was written with old ChipNDale version; filekey = %g\n", [integer[versionKey]]];
IF conv THEN
TerminalIO.PutRope["please convert all your designs (by reading and subsequent writing)\n"];
IF extra#NIL THEN TerminalIO.PutRope[extra];
IF bar THEN TerminalIO.PutRope["****\n"];
};
h.oldVersion ← TRUE;
IF versionKey>xVersion THEN { -- too new
TerminalIO.PutRope["design has newer file format version\n; bringover ChipNDale !!\n"];
ERROR TokenIO.EncodingError;
}
ELSE IF versionKey IN [13..xVersion] THEN { -- not new but dont tell it
NULL
}
ELSE IF versionKey IN [6..xVersion] THEN { -- not new but everything ok
OldMsg[versionKey];
}
ELSE IF versionKey=4 THEN { -- known problem versions
OldMsg[versionKey, TRUE, TRUE, "check carefully the alignment of cells which have n-well; if you have troubles, try CD18InputToggle and repeat the input\n"];
}
ELSE IF versionKey=3 THEN { -- known problem versions
OldMsg[versionKey, TRUE, TRUE, "check carefully the alignment of cells which have n-well\n"];
}
ELSE IF versionKey IN [0..xVersion] THEN { -- not new but please convert
OldMsg[versionKey, TRUE, TRUE];
}
ELSE { -- too old
OldMsg[versionKey, TRUE, FALSE, "sorry this version is no more supported\n"];
ERROR TokenIO.EncodingError;
};
};
--seal check
IF versionKey>0 THEN {
IF TokenIO.ReadInt[h]#-1 THEN {
TerminalIO.PutRope["**file had not been properly closed\n"];
ERROR TokenIO.EncodingError;
};
};
};
ReadDesignVersion: PROC [h: TokenIO.Handle, design: CD.Design] = {
designVersionKey: Rope.ROPENIL;
IF Version[h]>=7 THEN
designVersionKey ← TokenIO.ReadRope[h];
IF Rope.IsEmpty[designVersionKey] THEN
designVersionKey ← Convert.RopeFromTime[from: BasicTime.Now[], end: seconds];
CDProperties.PutDesignProp[design, $FileVersion, designVersionKey];
CDProperties.PutProp[h.properties, $FileVersion, designVersionKey];
};
ReadDesignName: PROC [h: TokenIO.Handle] RETURNS [name: Rope.ROPE] = {
name ← TokenIO.ReadRope[h];
IF Rope.IsEmpty[name] THEN {
name ← FileNames.GetShortName[fileName, TRUE];
name ← Rope.Substr[name, 0, Rope.Index[name, 0, ".dale", FALSE]]
}
};
-- DoInner
VersionAndSealCheck[h];
technologyKey ← TokenIO.ReadAtom[h];
technologyName ← TokenIO.ReadRope[h];
technology ← CDEnvironment.LoadTechnology[technologyKey, technologyName];
IF technology=NIL THEN GOTO NotDone;
h.clientData ← design ← CDOps.CreateDesign[technology];
TechnologyCheck[h];
IF design=NIL THEN GOTO NotDone;
design.name ← ReadDesignName[h];
ReadDesignVersion[h, design]; --read before check, fixed again later
IF check#NIL THEN
IF NOT check[h] THEN GOTO NotDone;
ReadDesignData[h, design];
CDEnvironment.SetWorkingDirectory[design, wDirUsed];
CDValue.Store[boundTo: design, key: $CDxFromFile, value: fileName];
CDValue.Store[boundTo: design, key: $CDxLastFile, value: fileName];
TokenIO.Close[h, FALSE];
EXITS NotDone => RETURN [design←NIL];
};
-- begin ReadDesign
h: TokenIO.Handle;
technology: CD.Technology;
technologyKey: ATOM;
technologyName: Rope.ROPE;
binfile: IO.STREAM;
fileName: Rope.ROPE;
iDidTheOpen: BOOLFALSE;
name: Rope.ROPE;
streamOptions: FS.StreamOptions ← ALL[TRUE];
streamOptions[tiogaRead] ← FALSE;
streamOptions[commitAndReopenTransOnFlush] ← FALSE;
streamOptions[truncatePagesOnClose] ← TRUE;
streamOptions[finishTransOnClose] ← TRUE;
streamOptions[closeFSOpenFileOnClose] ← TRUE;
-- open file; assign fileName and binfile
IF wDir=NIL THEN wDir ← FileNames.CurrentWorkingDirectory[];
IF from#NIL AND ISTYPE[from, IO.STREAM] THEN {
fileName ← NIL;
binfile ← NARROW[from, IO.STREAM]
}
ELSE {
ReadName: PROC [wDir: Rope.ROPE] RETURNS [name: Rope.ROPE] = {
TerminalIO.PutRopes[" input file (", wDir, ")"];
name ← TerminalIO.RequestRope[" > "];
};
IF from=NIL THEN name ← ReadName[wDir]
ELSE IF ISTYPE[from, Rope.ROPE] THEN {
name ← NARROW[from, Rope.ROPE];
IF Rope.IsEmpty[name] THEN name ← ReadName[wDir];
}
ELSE {
TerminalIO.PutRope["ReadDesign: bad parameter\n"];
GOTO NotOpened;
};
fileName ← CDEnvironment.MakeName[name, "dale", wDir];
binfile ← FS.StreamOpen[fileName, $read, streamOptions ! FS.Error =>
IF error.group # bug THEN {
TerminalIO.PutRope[Rope.Cat[fileName, " not opened: ", error.explanation, "\n"]];
GOTO NotOpened;
}];
fileName ← RealFileName[binfile, fileName];
wDirUsed ← FileNames.Directory[fileName];
iDidTheOpen ← TRUE;
TerminalIO.PutRopes[fileName, " opened \n"];
};
-- do the actual work
IF stop=NIL THEN stop ← NEW[BOOLFALSE];
h ← TokenIO.CreateReader[stream: binfile, stop: stop !
TokenIO.EncodingError => {
TerminalIO.PutRope["**TokenIO says file not ok; maybe not a ChipNDale file\n"];
GOTO NotOpened
};
];
design ← DoInner[h];
IF design#NIL THEN
[] ← CDEvents.ProcessEvent[ev: afterInputEvent, design: design, x: h, listenToDont: FALSE];
TokenIO.Close[h, iDidTheOpen];
EXITS NotOpened => RETURN [NIL];
};
RealFileName: PROC [s: IO.STREAM, default: Rope.ROPENIL] RETURNS [n: Rope.ROPE] = {
file: FS.OpenFile;
n ← default;
file ← FS.OpenFileFromStream[s ! IO.Error => GOTO Oops];
n ← FS.GetName[file! FS.Error => GOTO Oops].fullFName;
EXITS Oops => n ← default
};
ReadOrientation: PUBLIC PROC [h: TokenIO.Handle] RETURNS [orientation: CD.Orientation] = {
i: NAT ← TokenIO.ReadInt[h];
IF Version[h]<=3 THEN {
IF i IN [0..15] THEN orientation ← VAL[i/4*2 + i MOD 2]
ELSE SIGNAL TokenIO.EncodingError;
}
ELSE
IF i IN [0..7] THEN orientation ← VAL[i]
ELSE SIGNAL TokenIO.EncodingError
};
MakeName: PUBLIC PROC [base: Rope.ROPE, ext: Rope.ROPENIL, wDir: Rope.ROPENIL, modifier: Rope.ROPENIL] RETURNS [Rope.ROPE] = {
RETURN [CDEnvironment.MakeName[base, ext, wDir, modifier]];
};
SetWorkingDirectory: PUBLIC PROC [design: REF, wDir: Rope.ROPE] = {
CDEnvironment.SetWorkingDirectory[design, wDir];
};
GetWorkingDirectory: PUBLIC PROC [design: REF] RETURNS [wDir: Rope.ROPENIL] = {
RETURN [CDEnvironment.GetWorkingDirectory[design]];
};
MakeShortName: PUBLIC PROC [design: CD.Design] RETURNS [name: Rope.ROPENIL] = {
TrailingDot: PROC [base: Rope.ROPE] RETURNS [INT] = {
--position of last dot
len: INT ← Rope.Length[base];
pos: INT ← len;
WHILE pos > 0 DO
SELECT Rope.Fetch[base, pos ← pos - 1] FROM
'. => RETURN [pos];
'!, '], '>, '/ => EXIT;
ENDCASE;
ENDLOOP;
RETURN [len];
};
SuggestedModule: PROC [base: Rope.ROPE] RETURNS [Rope.ROPE] = {
--given a filename, suggests a modulename
len, dot: INT;
base ← FileNames.GetShortName[base];
len ← Rope.Length[base];
dot ← TrailingDot[base];
IF len>dot AND Rope.Equal[Rope.Substr[base, dot+1], "dale", FALSE] THEN
base ← Rope.Substr[base, 0, dot];
RETURN [base]
};
--MakeShortName
WITH CDValue.Fetch[boundTo: design, key: $CDxFromFile] SELECT FROM
r: Rope.ROPE => name ← SuggestedModule[r];
ENDCASE => NULL;
IF name=NIL THEN name ← design.name;
IF name=NIL THEN name ← "noname"
};
CD18Input: Commander.CommandProc = {
--fix an old old problem
specialForVersion4 ← ~specialForVersion4;
IF specialForVersion4 THEN
cmd.out.PutRope["Fileformat: switch to old version of cd18\n"]
ELSE
cmd.out.PutRope["Fileformat: switch to last version of cd18\n"];
};
InlineDesignInReadOperation: PUBLIC PROC [h: TokenIO.Handle] RETURNS [CD.Design] = INLINE {
RETURN [NARROW[h.clientData]]
};
VersionKey: PUBLIC PROC [h: TokenIO.Handle] RETURNS [INT] = {
WITH CDProperties.GetProp[h.properties, $VersionKey] SELECT FROM
i: REF INT => RETURN [i^];
ENDCASE => RETURN [0];
};
readEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$ReadTechnologyPrivate];
afterInputEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$AfterInput];
Commander.Register["///Commands/CD18InputToggle", CD18Input, "toggle input mode of cd18"];
END.
Version history
versionKey 0
versionKey 1:
objects with children carry names
versionKey 2:
versionKey 3: June 15, 1984 3:46:13 pm PDT;
instances position is its innerrect; this allows to shrink or grow the nwell from cmos
versionKey 4: October 20, 1984 9:36:34 am PDT;
orientation changed
probably while lifetime of 4:
properties which are propertylists are automatically included
versionKey 5: December 14, 1984 10:07:59 am PST;
insiderect for cells no more done with properties; key is removed
versionKey 6: February 1, 1985 4:43:29 pm PST;
properties which are layers are automatically included
versionKey 7: March 26, 1985 12:33:22 pm PST;
file versionkey property included
versionKey 8: April 15, 1985 3:26:35 pm PST;
cd-coords base to file again...
cells get origin and interestrect
imports get interestrect
versionKey 9: May 29, 1985 7:51:45 pm PDT;
CD21
versionKey 10: May 29, 1985 7:51:45 pm PDT;
CD22
Atomicobject have the interest rect on the file
versionKey 11: May 29, 1985 7:51:45 pm PDT;
(CD22)
pushed records get the default interest rect
versionKey 12: January 28, 1986 2:23:27 pm PST;
(CD22)
default properties get $DefaultProperty key
versionKey 13: March 11, 1986 4:17:16 pm PST;
(CD23)
cells may have drawBorder field
gbb April 4, 1986 3:19:31 pm PST
The atoms for the keys of the technology independent layers have changed.
changes to: ReadLayer: if versionKey[]<=12 translate atoms.
versionKey 15: June 20, 1986 9:53:19 am PDT;
Global changes
Number of object for object table is now inside object definition
Directory include is performed for all objects in directory, independent of source.
Objects not in directory have special option to be put in table.
versionKey 16: September 11, 1986 11:40:52 am PDT;
CD2.4.
New TokenIO
New object r instead of size