SchematicExtractorImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last Edited by: Jacobi, August 13, 1985 4:44:22 pm PDT
Last Edited by: Jacobi, September 24, 1985 6:50:23 pm PDT
Last Edited by: Jacobi, October 4, 1985 5:32:59 pm PDT
DIRECTORY
AMBridge,
AMTypes,
Ascii,
Atom,
Core,
CoreOps,
CoreCreate,
CD,
CDBasics,
CDCells,
CDCommandOps,
CDDirectory,
CDExtras,
CDImports,
CDInstances,
CDMenus,
CDOps,
CDOrient,
CDPinObjects,
CDProperties,
CDSequencer,
CDTexts,
Interpreter,
IO,
RefTab,
Rope,
RuntimeError,
SchematicExtractor,
SymTab,
TerminalIO,
CDSil;
SchematicExtractorImpl: CEDAR PROGRAM
IMPORTS AMBridge, AMTypes, Ascii, Atom, Core, CoreOps, CoreCreate, CD, CDBasics, CDCells, CDCommandOps, CDDirectory, CDExtras, CDImports, CDInstances, CDMenus, CDOps, CDOrient, CDPinObjects, CDProperties, CDSequencer, Interpreter, IO, RefTab, Rope, RuntimeError, SymTab, TerminalIO, CDSil
EXPORTS SchematicExtractor =
BEGIN
wireLayer: CD.Layer ← CDSil.xneutral;
failCheck: ERROR = CODE;
Failed: PROC [r: Rope.ROPENIL] =
BEGIN
TerminalIO.WriteRope[Rope.Cat["**failed: ", r, "\n"]];
END;
--electrical equipotential region, local to some hierarchical structure
Node: TYPE = REF NodeRec;
NodeRec: TYPE = RECORD [
replaceMeBy: Node ← NIL,
naming: Rope.ROPENIL
];
--point which causes connection to any wire touching the point
Connect: TYPE = REF ConnectRec;
ConnectRec: TYPE = RECORD [
r: CD.Rect,
node: Node
];
SubCell: TYPE = REF SubCellRec;
SubCellRec: TYPE = RECORD [
inst: CD.Instance,
bindings: LIST OF Binding←NIL
];
--a binding must know implicitely which SubCell it binds
Binding: TYPE = REF BindingRec;
BindingRec: TYPE = RECORD [
name: REF, --wire name
node: Node
];
State: TYPE = REF StateRec;
StateRec: TYPE = RECORD [
--permanent state
design: CD.Design,
lambda: CD.Number,
coreDesign: Core.Design,
cdToCore: RefTab.Ref, -- CD.Object => Core.CellType
cdHandled: RefTab.Ref, --to prevent recursion
numberForNaming: INT ← 0,
--temporary state while analyzing ob
ob: CD.Object ← NIL,
nodeByName: SymTab.Ref ← NIL,
subCells: LIST OF SubCell ← NIL,
connects: LIST OF Connect ← NIL,
nodeTab: RefTab.Ref, --set up only after connects is finished
numberOfInstances: INT ← 0
];
MakeName: PROC [state: State, prefix: Rope.ROPENIL] RETURNS [name: Rope.ROPE] =
BEGIN
state.numberForNaming ← state.numberForNaming+1;
IF prefix=NIL THEN prefix ← "NoName";
name ← Name[IO.PutFR["%g%g", IO.rope[prefix], IO.int[state.numberForNaming]]];
END;
Ident: PROC [proposed: Rope.ROPENIL] RETURNS [r: Rope.ROPE] =
--given a rope, makes an identifier
BEGIN
Trans: Rope.TranslatorType =
BEGIN
IF Ascii.Letter[old] THEN new ← old
ELSE IF Ascii.Digit[old] AND ~first THEN new ← old
ELSE new ← 'x;
first ← FALSE
END;
first: BOOLTRUE;
r ← Rope.Translate[base: proposed, translator: Trans];
IF Rope.IsEmpty[r] THEN r ← "x";
END;
Name: PROC [x: REFNIL] RETURNS [name: Rope.ROPE] =
BEGIN
name ← Ident[CDExtras.ToRope[x]]
END;
IdentFromProp: PROC [what: REF, key: ATOM] RETURNS [n: Rope.ROPENIL] =
--or NIL
BEGIN
n ← CDExtras.ToRope[ CDProperties.GetProp[what, key] ];
IF Rope.IsEmpty[n] THEN n ← NIL ELSE n ← Name[n]
END;
ResetState: PROC [state: State, ob: CD.Object ← NIL] =
BEGIN
state.connects ← NIL;
state.subCells ← NIL;
state.nodeTab ← RefTab.Create[];
state.nodeByName ← SymTab.Create[];
state.ob ← ob;
state.numberOfInstances ← 0;
END;
NewState: PROC [design: CD.Design, coreDesign: Core.Design←NIL] RETURNS [state: State] =
--and initializes the permanent variables
BEGIN
MyCoreCreateDesign: PROC [name: Rope.ROPENIL] RETURNS [coreDesign: Core.Design] =
BEGIN
coreDesign ← CoreOps.CreateDesign[Name[name] ! Core.StructureError => RESUME];
END;
IF coreDesign=NIL THEN coreDesign ← MyCoreCreateDesign[];
state ← NEW[StateRec ← [
design: design,
lambda: design.technology.lambda,
coreDesign: coreDesign,
cdToCore: RefTab.Create[],
cdHandled: RefTab.Create[],
numberForNaming: 0
]];
ResetState[state];
END;
NewNode: PROC [] RETURNS [node: Node] =
BEGIN
node ← NEW[NodeRec];
END;
NewConnect: PROC [r: CD.Rect] RETURNS [connect: Connect] =
BEGIN
node: Node ← NewNode[];
connect ← NEW[ConnectRec ← [r: r, node: node]];
END;
NewSubCell: PROC [state: State, inst: CD.Instance] RETURNS [subCell: SubCell] =
BEGIN
subCell ← NEW[SubCellRec←[inst: inst, bindings: NIL]];
state.subCells ← CONS[subCell, state.subCells];
END;
RealNode: PROC [n: Node] RETURNS [use: Node] =
BEGIN
use ← n;
IF use.replaceMeBy#NIL THEN {
name: Rope.ROPE ← use.naming;
WHILE use.replaceMeBy#NIL DO
use ← use.replaceMeBy;
IF use.naming#NIL THEN name ← use.naming;
ENDLOOP;
use.naming ← name;
WHILE n#use DO
remember: Node ← n.replaceMeBy;
n.replaceMeBy ← use;
n ← remember;
ENDLOOP;
};
END;
Aequipotential: PROC [a, b: Connect] =
BEGIN
use: Node ← RealNode[b.node];
other: Node ← RealNode[a.node];
IF use#other THEN other.replaceMeBy ← use;
a.node ← b.node ← use;
END;
IntroduceWire: PROC [state: State, inst: CD.Instance] =
BEGIN
r: CD.Rect ← CDInstances.InstRectI[inst];
connect: Connect ← IncludeConnect[state, r];
IF connect.node.naming=NIL THEN connect.node.naming ← IdentFromProp[inst, $SignalName];
END;
IncludeConnect: PROC[state: State, r: CD.Rect] RETURNS [connect: Connect] =
BEGIN
PseudoTouch: PROC [a, b: CD.Rect] RETURNS [BOOL] =
--a, b must have common point
INLINE BEGIN
RETURN [
a.x1=b.x1 OR a.x2=b.x2 OR --a.x1=b.x2 OR a.x2=b.x1 OR
a.y1=b.y1 OR a.y2=b.y2 --OR a.y1=b.y2 OR a.y2=b.y1
]
END;
connect ← NewConnect[r];
FOR cpl: LIST OF Connect ← state.connects, cpl.rest WHILE cpl#NIL DO
IF CDBasics.Intersect[r, cpl.first.r] THEN {
common: CD.Rect ← CDBasics.Intersection[r, cpl.first.r];
sz: CD.Position ← CDBasics.SizeOfRect[common];
IF sz.x<state.lambda OR sz.y<state.lambda OR PseudoTouch[r, cpl.first.r] OR CDBasics.Inside[r, cpl.first.r] OR CDBasics.Inside[cpl.first.r, r] THEN Aequipotential[connect, cpl.first];
--else this is a crossing whithout connection
};
ENDLOOP;
state.connects ← CONS[connect, state.connects];
END;
RectDist: PROC [a, b: CD.Rect] RETURNS [n: CD.Number] =
BEGIN
w, h: CD.Number;
IF a.x1>b.x1 THEN w ← a.x1-b.x2 ELSE w ← b.x1-a.x2;
IF a.y1>b.y1 THEN h ← a.y1-b.y2 ELSE h ← b.y1-a.y2;
n ← MAX[0, w, h];
END;
IntroduceName: PROC [state: State, inst: CD.Instance] =
--should be called after all the connects are made...
BEGIN
tp: CDTexts.TextPtr ← NARROW[inst.ob.specificRef];
name: Rope.ROPE ← Name[tp.text];
minDist: CD.Number = 100;
nameR: CD.Rect ← CDInstances.InstRectI[inst];
use: Node ← NIL;
min: INT ← minDist;
IF ~Rope.Equal[name, tp.text] THEN
Failed[Rope.Cat["name: ", tp.text, " replaced by ", name]];
FOR cl: LIST OF Connect ← state.connects, cl.rest WHILE cl#NIL DO
d: INT ← RectDist[nameR, cl.first.r];
IF d<=min THEN {
IF d<min THEN {
min ← d;
use ← cl.first.node ← RealNode[cl.first.node];
}
ELSE --IF d=min THEN-- {
--don't know which node should get the name, if the nodes are really different
cl.first.node ← RealNode[cl.first.node];
IF use#cl.first.node THEN use ← NIL;
}
}
ENDLOOP;
IF use#NIL THEN {
IF Rope.IsEmpty[use.naming] THEN use.naming ← name
ELSE IF ~Rope.Equal[use.naming, name] THEN
Failed[Rope.Cat["node has multiple names: ", name, " ", use.naming]]
}
ELSE Failed[Rope.Cat["did not find object to name ", name]]
END;
CheckPinsWithCore: PROC [state: State, ob: CD.Object, coreCell: Core.CellType] =
--raises failCheck
BEGIN
ToBad: PROC [r: Rope.ROPENIL] =
BEGIN
Failed[Rope.Cat["in subcell ", CDDirectory.Name[ob], " ", r]];
ERROR failCheck;
END;
EachPin: PROC [inst: CD.Instance] RETURNS [quit: BOOLFALSE] =
BEGIN
name: Rope.ROPE ← Name[GetGates32ConnectName[inst]];
--sorry right now only one pin per wire
IF ~SymTab.Store[names, name, $occurs] THEN ToBad["multiple pins"];
END;
EachWire: CoreOps.EachWireProc =
BEGIN
IF wire#coreCell.publicWire THEN {
wireCount ← wireCount+1;
IF SymTab.Fetch[names, wire.name].val#$occurs THEN
ToBad[Rope.Cat["wire ", wire.name, " has no corresponding pin"]];
[] ← SymTab.Store[names, wire.name, $found];
}
END;
wireCount: INT ← 0;
names: SymTab.Ref ← SymTab.Create[];
IF coreCell.publicWire.structure#record THEN ToBad["wire not of record structure"];
--build symtab with entry=pin name
FOR rL: LIST OF Rope.ROPE ← GetRopeList[ob, $ConnectByName], rL.rest WHILE rL#NIL DO
IF ~SymTab.Store[names, rL.first, $occurs] THEN ToBad["multiple pins"];
ENDLOOP;
[] ← CDPinObjects.EnumeratePins[ob: ob, eachPin: EachPin];
[] ← EnumerateGates32Connects[ob: ob, eachConnect: EachPin, lambda: state.lambda];
--check if each wire is in symtab
CoreOps.VisitWire[coreCell.publicWire, EachWire];
IF wireCount#names.size THEN ToBad["wire number does not match"];
END;
CreateCoreCellType: PROC [coreDesign: Core.Design, name: Rope.ROPE] RETURNS [cellType: Core.CellType] =
BEGIN
use: Rope.ROPE ← Name[name];
cellType ← CoreOps.FetchCellType[coreDesign, use];
IF cellType#NIL THEN {
WHILE cellType#NIL DO
use ← Rope.Cat[use, "x"];
cellType ← CoreOps.FetchCellType[coreDesign, use];
ENDLOOP;
Failed[Rope.Cat["CellType ", Name[name], " already exists; name modified to ", use]];
};
cellType ← CoreCreate.CreateRecordCell[design: coreDesign, name: use];
END;
GetGates32ConnectName: PROC [connInst: CD.Instance] RETURNS [r: Rope.ROPENIL] =
BEGIN
IF CDPinObjects.IsPinOb[connInst.ob] THEN r ← CDPinObjects.GetName[connInst]
ELSE IF IsGates32Connector[connInst.ob]#none THEN {
WITH CDProperties.GetPropFromInstance[connInst, gates32PinProp] SELECT FROM
n: Rope.ROPE => r ← n
ENDCASE => NULL
}
END;
CreateCoreCellUsingPins: PROC [state: State, ob: CD.Object] RETURNS [coreCell: Core.CellType] =
--creates a Core CellType with the public wire corresponding to ob's pins
BEGIN
EachPin: PROC [inst: CD.Instance] RETURNS [quit: BOOLFALSE] =
BEGIN
name: Rope.ROPE ← Name[GetGates32ConnectName[inst]];
[] ← CoreCreate.CreatePublicWire[design: state.coreDesign, on: coreCell, name: name];
END;
name: Rope.ROPE ← Name[Rope.Cat[CDDirectory.Name[ob], "Substitute"]];
coreCell ← CreateCoreCellType[coreDesign: state.coreDesign, name: name];
[] ← CDPinObjects.EnumeratePins[ob: ob, eachPin: EachPin];
[] ← EnumerateGates32Connects[ob, EachPin, state.lambda];
END;
Side: TYPE = {bottom, right, top, left, none};
gates32PinProp: ATOM ← $SignalName;
IsGates32Connector: PROC [ob: CD.Object] RETURNS [side: Side ← none] =
BEGIN
WITH ob.specificRef SELECT FROM
tp: CDTexts.TextPtr =>
IF Rope.Equal[tp.cdFont.supposedName, "Xerox/TiogaFonts/Gates32", FALSE] THEN {
SELECT TRUE FROM
Rope.Equal[tp.text, "Q"] => side ← top;
Rope.Equal[tp.text, "R"] => side ← left;
Rope.Equal[tp.text, "S"] => side ← bottom;
Rope.Equal[tp.text, "T"] => side ← right;
ENDCASE => NULL;
}
ENDCASE => NULL;
END;
Gates32ConnectorRect: PROC [side: Side, lambda: CD.Number] RETURNS [CD.Rect] =
BEGIN
RETURN [SELECT side FROM
bottom => [x1: lambda, y1: 28*lambda, x2: 2*lambda, y2: 30*lambda],
left => [x1: 0, y1: 27*lambda, x2: 2*lambda, y2: 28*lambda],
top => [x1: lambda, y1: 30*lambda, x2: 2*lambda, y2: 32*lambda],
right => [x1: 2*lambda, y1: 27*lambda, x2: 4*lambda, y2: 28*lambda],
ENDCASE => CDBasics.empty]
END;
EnumerateGates32Connects: PROC [ob: CD.Object←NIL, eachConnect: CDPinObjects.InstanceEnumerator, lambda: CD.Number] RETURNS [quit: BOOLFALSE] =
BEGIN
makeNames: BOOLFALSE;
cp: CD.CellPtr;
Text: PROC [ob: CD.Object] RETURNS [r: Rope.ROPENIL] =
BEGIN
WITH ob.specificRef SELECT FROM
tp: CDTexts.TextPtr => r ← tp.text
ENDCASE => NULL;
END;
IsHelvetica7: PROC [ob: CD.Object] RETURNS [yes: BOOLFALSE] =
BEGIN
WITH ob.specificRef SELECT FROM
tp: CDTexts.TextPtr =>
yes ← Rope.Equal[tp.cdFont.supposedName, "Xerox/TiogaFonts/Helvetica7", FALSE]
ENDCASE => NULL;
END;
FindnameFor: PROC [inst: CD.Instance, lambda: CD.Number] =
--inst must be connector
--uses global variables cp for context of inst
BEGIN
name: Rope.ROPENIL;
dist: CD.Number ← LAST[INTEGER];
cRect: CD.Rect;
WITH CDProperties.GetPropFromInstance[inst, gates32PinProp] SELECT FROM
r: Rope.ROPE => IF ~Rope.IsEmpty[r] THEN RETURN;
ENDCASE => NULL;
cRect ← CDOrient.MapRect[ --connector Rect
itemInCell: Gates32ConnectorRect[IsGates32Connector[inst.ob], lambda],
cellSize: inst.ob.size,
cellInstOrient: inst.orientation,
cellInstPos: inst.location];
FOR list: CD.InstanceList ← cp.contents, list.rest WHILE list#NIL DO
IF IsHelvetica7[list.first.ob] THEN {
d: CD.Number;
tRect: CD.Rect ← CD.InterestRect[list.first.ob]; --text Rect
tRect.y2 ← (tRect.y1+tRect.y2)/2; --shrink it to have less texts
tRect.y1 ← tRect.y2-1;
tRect ← CDOrient.MapRect[
itemInCell: tRect,
cellSize: list.first.ob.size,
cellInstOrient: list.first.orientation,
cellInstPos: list.first.location
];
d ← RectDist[cRect, tRect];
IF d<dist THEN {
name ← Text[list.first.ob];
dist ← d;
}
};
ENDLOOP;
IF name#NIL THEN CDProperties.PutPropOnInstance[inst, gates32PinProp, name];
END;
WITH ob.specificRef SELECT FROM
c: CD.CellPtr => cp ← c;
ip: CDImports.ImportPtr => { -- HACKK until imports handle pins reasonably
IF ip.boundInstance=NIL THEN RETURN [TRUE];
quit ← EnumerateGates32Connects[ip.boundInstance.ob, eachConnect, lambda];
RETURN
};
ENDCASE => RETURN [TRUE];
makeNames ← CDProperties.GetPropFromObject[ob, gates32PinProp]#$ok;
FOR list: CD.InstanceList ← cp.contents, list.rest WHILE (list#NIL AND ~quit) DO
IF IsGates32Connector[list.first.ob]#none THEN {
IF makeNames THEN FindnameFor[list.first, lambda];
quit ← eachConnect[list.first]; -- do NOT catch errors
};
ENDLOOP;
IF ~quit AND makeNames THEN
CDProperties.PutPropOnObject[ob, gates32PinProp, $ok];
END;
RopePair: TYPE = RECORD [r1, r2: Rope.ROPE];
ScanRopePair: PROC [r: Rope.ROPE] RETURNS [p: RopePair ← [NIL, NIL]] =
--given a rope, splits it into the first identifier r1 and the remainder r2
BEGIN
s: IO.STREAMIO.RIS[r];
p.r1 ← IO.GetID[s ! IO.EndOfStream, IO.Error => GOTO ioErr];
p.r2 ← IO.GetLineRope[s ! IO.EndOfStream, IO.Error => GOTO ioErr];
EXITS ioErr => NULL;
END;
GetRopeList: PROC [ob: CD.Object, key: ATOM] RETURNS [rList: LIST OF Rope.ROPENIL] =
--gets a list of identifiers hanging on ob's key property
BEGIN
r: Rope.ROPE ← IdentFromProp[ob, key];
WHILE ~Rope.IsEmpty[r] DO
p: RopePair ← ScanRopePair[r];
IF Rope.IsEmpty[p.r1] THEN Failed["bad rope list"]
ELSE {
rList ← CONS[p.r1, rList];
r ← p.r2;
}
ENDLOOP
END;
FindOrCreateCoreCell: PROC [state: State, ob: CD.Object] RETURNS [coreCell: Core.CellType←NIL] =
--XXX should use instance instead of object, Core and ChipNDale are not parallel here
BEGIN
Problem: PROC [r: Rope.ROPE] =
BEGIN
TerminalIO.WriteRope[Rope.Cat["Core description for ", obName, ": ", r, "\n"]];
END;
EvalToCore: PROC [state: State, ob: CD.Object, r: Rope.ROPE] RETURNS [coreCell: Core.CellType←NIL] =
BEGIN
errorRope: Rope.ROPE;
noResult: BOOL;
tv: AMTypes.TVNIL;
symTab: SymTab.Ref ← SymTab.Create[];
SetTV: PROC [name: Rope.ROPE, ref: REF] = TRUSTED {
refRef: REF REFNEW[REF ← ref];
[] ← SymTab.Store[symTab, name, AMBridge.TVForReferent[refRef]];
};
TerminalIO.WriteRope[Rope.Cat["Feeds """, r, """ to the interpreter\n"]];
SetTV["&design", state.design];
SetTV["&coreDesign", state.coreDesign];
SetTV["&ob", ob];
BEGIN
ENABLE {
UNWIND => GOTO iUnwind;
RuntimeError.UNCAUGHT => {
TerminalIO.WriteRope["** some while error interpreting; abort to free lock on design\n"];
REJECT
};
};
[tv, errorRope, noResult] ← Interpreter.Evaluate[rope: r, symTab: symTab];
END;
IF noResult OR tv=NIL OR ~Rope.IsEmpty[errorRope] THEN {
Problem[Rope.Cat[" has bad interpretation: ", errorRope]];
RETURN
};
IF AMTypes.UnderClass[AMTypes.TVType[tv]]=ref THEN TRUSTED {
WITH AMBridge.SomeRefFromTV[tv] SELECT FROM
c: REF REF Core.CellType => {coreCell ← c^^};
c: REF Core.CellType => {coreCell ← c^};
c: Core.CellType => {coreCell ← c};
ENDCASE => Problem[" interpreter returns wrong type"];
}
ELSE Problem[" interpreter returns wrong type class"];
EXITS iUnwind => TerminalIO.WriteRope["** UNWIND\n"];
END;
IncludeEvalToCore: PROC [state: State, ob: CD.Object, r: Rope.ROPE] RETURNS [coreCell: Core.CellType←NIL] =
BEGIN
coreCell ← EvalToCore[state, ob, r];
IF coreCell#NIL THEN {
ct: Core.CellType ← CoreOps.FetchCellType[state.coreDesign, coreCell.name];
IF ct#coreCell THEN
CoreOps.InsertCellType[state.coreDesign, coreCell ! Core.StructureError=> {
Problem[Rope.Cat[" cell with duplicate name """, coreCell.name, """ included"]];
RESUME
}];
};
END;
obName: Rope.ROPE ← Name[CDDirectory.Name[ob]];
WITH RefTab.Fetch[state.cdToCore, ob].val SELECT FROM
coreCt: Core.CellType => RETURN [coreCt];
ENDCASE => {
x: REF ← CDProperties.GetPropFromObject[ob, $Represents];
IF x=NIL THEN {
IF CDImports.IsImport[ob] THEN {
rp: CDImports.ImportPtr ← NARROW[ob.specificRef];
IF rp.boundInstance#NIL THEN {
coreCell ← FindOrCreateCoreCell[state, rp.boundInstance.ob];
[] ← RefTab.Store[state.cdToCore, ob, coreCell];
RETURN
}
};
Problem[" object has no $Represents property"];
coreCell ← CoreOps.FetchCellType[state.coreDesign, obName];
}
ELSE WITH x SELECT FROM
r: Rope.ROPE => {
rp: RopePair ← ScanRopePair[r];
SELECT TRUE FROM
Rope.Equal[rp.r1, "interpret", FALSE] => {
IF Rope.IsEmpty[rp.r2] THEN Problem[" empty call"]
ELSE coreCell ← IncludeEvalToCore[state, ob, rp.r2];
};
Rope.Equal[rp.r1, "fetch", FALSE] => {
IF Rope.IsEmpty[rp.r2] THEN Problem[" empty call"]
ELSE coreCell ← CoreOps.FetchCellType[state.coreDesign, Name[rp.r2]];
};
Rope.Equal[rp.r1, "extract", FALSE] => {
IF Rope.IsEmpty[rp.r2] THEN coreCell ← FindRecursive[state, ob]
ELSE coreCell ← RecursiveCall[state, rp.r2];
};
ENDCASE => {
Problem[" key is unknown"];
};
};
ENDCASE => Problem[" key has bad type"];
IF coreCell=NIL THEN Problem[" not found"]
ELSE {
CheckPinsWithCore[state, ob, coreCell ! failCheck => {coreCell←NIL; CONTINUE}];
IF coreCell=NIL THEN Problem[" not valid"];
};
IF coreCell=NIL THEN coreCell ← CreateCoreCellUsingPins[state, ob];
[] ← RefTab.Store[state.cdToCore, ob, coreCell];
};
END;
FindRecursive: PROC [state: State, ob: CD.Object] RETURNS [coreCell: Core.CellType←NIL] =
BEGIN
EachEntry: PROC [name: Rope.ROPE, ob: CD.Object] RETURNS [quit: BOOLFALSE] = {
IF ob.class.inDirectory THEN {
IF Rope.Equal[IdentFromProp[ob, $Implements], iconName] THEN {
IF state.cdHandled.Insert[ob, $x] THEN {
DoExtraction[state, ob];
WITH RefTab.Fetch[state.cdToCore, ob].val SELECT FROM
coreCt: Core.CellType => coreCell ← coreCt;
ENDCASE => Failed[Rope.Cat["extraction of ", iconName, " failed"]];
}
ELSE Failed[Rope.Cat[CDDirectory.Name[ob], " introduces recursion"]];
quit ← TRUE;
}
}
};
iconName: Rope.ROPE ← Name[CDDirectory.Name[ob]];
IF ~CDDirectory.Enumerate[design: state.design, action: EachEntry].quit THEN
Failed[Rope.Cat["no object claims to implement ", iconName]];
END;
RecursiveCall: PROC [state: State, name: Rope.ROPE] RETURNS [coreCell: Core.CellType←NIL] =
BEGIN
ob: CD.Object ← CDDirectory.Fetch[state.design, name].object;
IF ob=NIL THEN Failed[Rope.Cat[name, " not found"]]
ELSE IF state.cdHandled.Insert[ob, $x] THEN {
DoExtraction[state, ob];
WITH RefTab.Fetch[state.cdToCore, ob].val SELECT FROM
coreCt: Core.CellType => RETURN [coreCt];
ENDCASE => Failed[Rope.Cat["extraction of ", name, " failed"]];
}
ELSE Failed[Rope.Cat[name, " introduces recursion"]];
END;
IncludeBinding: PROC [subCell: SubCell, nameInSubCell: REF, node: Node] =
--nameInSubCell: formal wire/pin name in subCell
--node: actual node
BEGIN
binding: Binding;
name: Rope.ROPE ← Name[nameInSubCell];
FOR bl: LIST OF Binding ← subCell.bindings, bl.rest WHILE bl#NIL DO
IF Rope.Equal[Name[bl.first.name], name] THEN {
IF RealNode[node]=RealNode[bl.first.node] THEN RETURN;
Failed[Rope.Cat["pin ", name, " in subcell ", CDDirectory.Name[subCell.inst.ob],
"connected to different nodes"]];
};
ENDLOOP;
binding ← NEW[BindingRec ← [name: nameInSubCell, node: node]];
subCell.bindings ← CONS[binding, subCell.bindings];
END;
IntroduceSubcircuit: PROC [state: State, subInst: CD.Instance] =
BEGIN
EachPin: PROC [inst: CD.Instance] RETURNS [quit: BOOLFALSE] =
BEGIN
pinName: Rope.ROPE ← Name[GetGates32ConnectName[inst]];
connect: Connect;
r: CD.Rect;   -- connecting rect in coords of inst
globalR: CD.Rect; -- connecting rect in coords containing cell
IF CDPinObjects.IsPinOb[inst.ob] THEN r ← CDInstances.InstRectI[inst]
ELSE r ← CDOrient.MapRect[ --connector Rect
itemInCell: Gates32ConnectorRect[IsGates32Connector[inst.ob], state.lambda],
cellSize: inst.ob.size,
cellInstOrient: inst.orientation,
cellInstPos: inst.location];
globalR ← CDOrient.MapRect[
itemInCell: r,
cellSize: subInst.ob.size,
cellInstOrient: subInst.orientation,
cellInstPos: subInst.location
];
connect ← IncludeConnect[state, globalR];
IncludeBinding[subCell, pinName, connect.node];
END;
coreCell: Core.CellType ← FindOrCreateCoreCell[state, subInst.ob];
subCell: SubCell ← NewSubCell[state, subInst];
[] ← CDPinObjects.EnumeratePins[ob: subInst.ob, eachPin: EachPin];
[] ← EnumerateGates32Connects[ob: subInst.ob, eachConnect: EachPin, lambda: state.lambda];
END;
BuildNodeTable: PROC [state: State] =
--[builds state.nodeTab] assume the state.connects already built up completely
BEGIN
CleanupSubCell: PROC [subCell: SubCell] = {
FOR b: LIST OF Binding ← subCell.bindings, b.rest WHILE b#NIL DO
b.first.node ← RealNode[b.first.node];
ENDLOOP;
};
CleanupBindings: PROC [state: State] = {
FOR s: LIST OF SubCell ← state.subCells, s.rest WHILE s#NIL DO
CleanupSubCell[s.first];
ENDLOOP;
};
CleanupBindings[state];
state.nodeTab ← RefTab.Create[state.numberOfInstances];
FOR c: LIST OF Connect ← state.connects, c.rest WHILE c#NIL DO
c.first.node ← RealNode[c.first.node];
[] ← RefTab.Insert[state.nodeTab, c.first.node, $Internal];
ENDLOOP;
END;
MakeNodePublic: PROC [state: State, inst: CD.Instance] =
BEGIN
name: Rope.ROPE ← Name[CDPinObjects.GetName[inst]];
r: CD.Rect ← CDInstances.InstRectI[inst];
FOR c: LIST OF Connect ← state.connects, c.rest WHILE c#NIL DO
IF CDBasics.Intersect[r, c.first.r] THEN {
[] ← RefTab.Store[state.nodeTab, c.first.node, $Public];
IF c.first.node.naming=NIL THEN c.first.node.naming ← name;
};
ENDLOOP;
END;
FinishCore: PROC [state: State] =
--finish the Core representation by using the internal data structures from state
BEGIN
EachNode: RefTab.EachPairAction =
BEGIN
node: Node ← NARROW[key];
name: Rope.ROPE ← node.naming;
IF Rope.IsEmpty[name] THEN name ← node.naming ← MakeName[state, "node"];
[] ← SymTab.Store[state.nodeByName, name, node];
IF val=$Public THEN
[] ← CoreCreate.CreatePublicWire[design: state.coreDesign, on: coreCell, name: name]
ELSE
[] ← CoreCreate.CreateWire[design: state.coreDesign, in: coreCell, name: name];
quit ← FALSE;
END;
EachConnectByNameNode: SymTab.EachPairAction =
BEGIN
IF val=$noWireFoundYet THEN
[] ← CoreCreate.CreateWire[design: state.coreDesign, in: coreCell, name: key];
quit ← FALSE;
END;
coreCell: Core.CellType;
name: Rope.ROPE;
--create Core cellType
name ← IdentFromProp[state.ob, $Implements];
IF name=NIL THEN name ← Name[CDDirectory.Name[state.ob]];
coreCell ← CreateCoreCellType[coreDesign: state.coreDesign, name: name];
--introduce nodes
[] ← RefTab.Pairs[state.nodeTab, EachNode];
[] ← SymTab.Pairs[state.nodeByName, EachConnectByNameNode];
--introduce instances
FOR s: LIST OF SubCell ← state.subCells, s.rest WHILE s#NIL DO
coreBind: Rope.ROPE NIL;
coreInstCellType: Core.CellType ← FindOrCreateCoreCell[state, s.first.inst.ob];
AddBinding: PROC [formal, actual: Rope.ROPE] = {
--adds a binding to the rope coreBind
IF coreBind#NIL THEN coreBind ← Rope.Concat[coreBind, ", "];
coreBind ← Rope.Cat[coreBind, formal, ": ", actual];
};
--bindings with nodes found in drawing
FOR b: LIST OF Binding ← s.first.bindings, b.rest WHILE b#NIL DO
AddBinding[Name[b.first.name], b.first.node.naming];
ENDLOOP;
--bindings found through properties
FOR rL: LIST OF Rope.ROPE ← GetRopeList[s.first.inst.ob, $ConnectByName], rL.rest WHILE rL#NIL DO
name: Rope.ROPE;
IF SymTab.Fetch[state.nodeByName, rL.first].found THEN name ← rL.first
ELSE {
name ← MakeName[state, "IllegalNode"];
Failed[Rope.Cat["don't know where to connect ", rL.first, " from ", CDDirectory.Name[s.first.inst.ob]]];
[] ← CoreCreate.CreateWire[design: state.coreDesign, in: coreCell, name: name];
};
AddBinding[rL.first, name];
ENDLOOP;
[] ← CoreCreate.CreateCellInstance[design: state.coreDesign,
type: coreInstCellType,
in: coreCell,
bind: coreBind,
name: IdentFromProp[s.first.inst, $InstanceName]
! CoreCreate.CreateError => {
Failed[Rope.Cat["while creating instance: ", message]];
CONTINUE
}
];
ENDLOOP;
[] ← RefTab.Store[state.cdToCore, state.ob, coreCell];
END;
GuaranteeChildren: PROC [state: State, ob: CD.Object] =
--Makes sure all children are extracted.
--We extract the children first, before we build the data structure to extract ob:
--therefor, only the data structure for one extraction requires memory anytime
BEGIN
GuaranteeOneChild: PROC [me: CD.Object, x: REF] = {
IF me.class.inDirectory THEN {
IF CDImports.IsImport[me] THEN {
rp: CDImports.ImportPtr ← NARROW[me.specificRef];
IF rp.boundInstance=NIL THEN {
Failed[Rope.Cat[CDOps.Info[me], " not bound"]];
RETURN
}
ELSE me ← rp.boundInstance.ob
};
IF IdentFromProp[me, $Implements]#NIL THEN {
Failed[Rope.Cat[CDDirectory.Name[me], " is implementing ", IdentFromProp[me, $Implements], " but is used as icon"]];
}
ELSE
WITH RefTab.Fetch[state.cdToCore, me].val SELECT FROM
coreCt: Core.CellType => RETURN;
ENDCASE => [] ← FindOrCreateCoreCell[state, me];
}
};
CDDirectory.EnumerateChildObjects[me: ob, p: GuaranteeOneChild, x: state]
END;
DoExtraction: PROC [state: State, ob: CD.Object] =
--main procedure to do the extraction
--assumes state set up
BEGIN
ob1: CD.Object ← ob;
cellPtr: CD.CellPtr;
IF IdentFromProp[ob, $Implements]=NIL THEN TerminalIO.WriteRope[Rope.Cat["Warning: ", CDDirectory.Name[ob], " has no $Implements property\n"]];
--extract children before data structure gets big
GuaranteeChildren[state, ob];
--start extraction; knows only jow to deal with cells
ResetState[state, ob];
WHILE ~CDCells.IsCell[ob1] DO
ob2: CD.Object ← CDDirectory.ExpandHard[ob1, IF ob=ob1 THEN state.design ELSE NIL, NIL];
IF ob2#NIL AND ob2#ob1 THEN ob1 ← ob2
ELSE {
Failed[Rope.Cat["Can not extract ", CDOps.Info[ob], "; has wrong object class"]];
RETURN
}
ENDLOOP;
cellPtr ← NARROW[ob1.specificRef];
--find nodes to be connected by name
FOR rL: LIST OF Rope.ROPE ← GetRopeList[ob, $ConnectByName], rL.rest WHILE rL#NIL DO
[] ← SymTab.Store[state.nodeByName, rL.first, $noWireFoundYet];
ENDLOOP;
--introduce wires and subcircuits; test for unknown object classes
FOR list: CD.InstanceList ← cellPtr.contents, list.rest WHILE list#NIL DO
state.numberOfInstances ← state.numberOfInstances+1;
SELECT TRUE FROM
list.first.ob.class.wireTyped AND list.first.ob.layer=wireLayer =>
IntroduceWire[state, list.first];
list.first.ob.class.inDirectory => IntroduceSubcircuit[state, list.first];
ISTYPE[list.first.ob.specificRef, CDTexts.TextPtr] => NULL;
CDPinObjects.IsPinApp[list.first] => NULL;
ENDCASE => Failed[Rope.Cat["dont know what to do with ", CDOps.Info[list.first.ob]]];
ENDLOOP;
--recognize nodes and then find out which are public
BuildNodeTable[state];
FOR list: CD.InstanceList ← cellPtr.contents, list.rest WHILE list#NIL DO
IF CDPinObjects.IsPinApp[list.first] THEN {
MakeNodePublic[state, list.first]
}
ENDLOOP;
--handle names
FOR list: CD.InstanceList ← cellPtr.contents, list.rest WHILE list#NIL DO
IF ISTYPE[list.first.ob.specificRef, CDTexts.TextPtr] THEN {
IntroduceName[state, list.first]
}
ENDLOOP;
--finish the Core structure
FinishCore[state];
END;
CoreOutput: PROC [state: State] =
--prints the Core design onto Terminal
BEGIN
out: IO.STREAMIO.ROS[];
text: Rope.ROPE;
CoreOps.PrintDesign[state.coreDesign, out];
text ← IO.RopeFromROS[out];
TerminalIO.WriteRope["--start Core output\n"];
TerminalIO.WriteRope[text];
TerminalIO.WriteLn[];
TerminalIO.WriteRope["--end Core output\n"];
END;
Extract: PUBLIC PROC [design: CD.Design, what: REFNIL, into: Core.Design, mode: REFNIL] =
BEGIN
state: State;
ob: CD.Object;
WITH what SELECT FROM
o: CD.Object => ob←o;
i: CD.Instance => ob←i.ob;
ENDCASE => ERROR;
IF ~CDCells.IsCell[ob] THEN ERROR;
state ← NewState[design, into];
DoExtraction[state, ob];
--output and test output
Atom.PutProp[atom: $CoreFromCD, prop: $CoreFromCD, val: state.coreDesign];
IF mode=$output THEN CoreOutput[state];
ResetState[state]; --help the garbage collector
END;
ChipNSilExtractCommand: PROC [comm: CDSequencer.Command] =
BEGIN
inst: CD.Instance ← CDCommandOps.TheInstance[comm, "ChipNSil Circuit Extractor"];
IF inst#NIL THEN {
IF CDCells.IsCell[inst.ob] THEN {
coreDesign: Core.Design ← NIL;
IF comm.a=$TChipNSilExtract THEN
coreDesign ← NARROW[Atom.GetProp[$CoreFromCD, $CoreFromCD]];
Extract[design: comm.design, what: inst.ob, mode: $output, into: coreDesign];
TerminalIO.WriteRope["end CSE\n"];
}
ELSE TerminalIO.WriteRope["ChipNSil Circuit Extractor can extract only cells\n"];
}
END;
CDSequencer.ImplementCommand[a: $ChipNSilExtract, p: ChipNSilExtractCommand, queue: doQueue];
CDSequencer.ImplementCommand[a: $TChipNSilExtract, p: ChipNSilExtractCommand, queue: doQueue];
CDMenus.CreateEntry[menu: $ProgramMenu, entry: "ChipNSil Extraction", key: $ChipNSilExtract];
CDMenus.CreateEntry[menu: $ProgramMenu, entry: "TEST X", key: $TChipNSilExtract];
END.