PipalSinixImpl.mesa
Copyright Ó 1985, 1986, 1987, 1988 by Xerox Corporation. All rights reversed.
Created by Bertrand Serlet August 15, 1985 2:09:54 pm PDT
Bertrand Serlet May 8, 1988 0:29:50 am PDT
Pradeep Sindhu May 5, 1986 5:16:10 pm PDT
Barth, April 18, 1986 4:42:48 pm PST
gbb April 16, 1987 6:19:54 pm PDT
Jean-Marc Frailong January 17, 1988 9:07:29 pm PST
DIRECTORY
Core, CoreClasses, CoreOps, CoreProperties,
IO, MessageWindow,
Pipal, PipalConnect, PipalCore, PipalInt, PipalMos, PipalSinix,
RefTab, Rope, RopeList,
SymTab, TerminalIO;
PipalSinixImpl: CEDAR PROGRAM
IMPORTS CoreClasses, CoreOps, CoreProperties, IO, MessageWindow, Pipal, PipalConnect, PipalCore, PipalInt, PipalMos, RefTab, Rope, RopeList, SymTab, TerminalIO
EXPORTS PipalSinix
SHARES PipalCore =
BEGIN OPEN PipalSinix;
Type Aliases
CellType: TYPE = Core.CellType;
Wire: TYPE = Core.Wire;
WireSeq: TYPE = Core.WireSeq;
Wires: TYPE = Core.Wires;
Properties: TYPE = Core.Properties;
ROPE: TYPE = Core.ROPE;
ROPES: TYPE = LIST OF ROPE;
Object: TYPE = Pipal.Object;
Objects: TYPE = Pipal.Objects;
rect: PROC [r: PipalInt.Rectangle] RETURNS [IO.Value] = {
RETURN [IO.rope[PipalInt.RectangleToRope[r]]];
};
Wire Fusion
CreateRoot: PUBLIC PROC [fused: RefTab.Ref, size: NAT] RETURNS [wire: Wire] = {
wire ← CoreOps.CreateWires[size: size];
[] ← RefTab.Store[fused, wire, NIL];
};
The following PROC implements Fisher-Galler fusion, not for efficiency, but for simplicity
RootWire: PUBLIC PROC [fused: RefTab.Ref, wire: Wire] RETURNS [rootWire: Wire] = {
IF wire=NIL THEN SIGNAL InternalBug[];
rootWire ← NARROW [RefTab.Fetch[fused, wire].val];
IF rootWire=NIL THEN RETURN [wire];
IF rootWire=wire THEN SIGNAL InternalBug[];
rootWire ← RootWire[fused, rootWire];
[] ← RefTab.Replace[fused, wire, rootWire];
};
EnumerateRoots: PUBLIC PROC [fused: RefTab.Ref, each: PROC [wire: Wire]] = {
EachPair: RefTab.EachPairAction = {IF val=NIL THEN each[NARROW [key]]};
[] ← RefTab.Pairs[fused, EachPair];
};
This mechanism could be exported if we wanted that.
PropFusionProc: TYPE = PROC [object: Object, prop: ATOM, value1, value2: REF ANY] RETURNS [value: REF ANY];
NameFusion: PropFusionProc = {
value ← OrNames[object, NARROW [value1], NARROW [value2]];
};
DefaultFusion: PropFusionProc = {
IF value1#NIL AND value2#NIL AND value1#value2 THEN SIGNAL FusionPropMismatch[object, prop, value1, value2];
value ← IF value1=NIL THEN value2 ELSE value1;
};
Appends the properties of fused to the ones of root, but treating short names specially
FuseProperties: PUBLIC PROC [mode: Mode, object: Object, fused, root: Wire] = {
EachProperty: PROC [prop: ATOM, val: REF ANY] = {
rootValue: REF ← CoreProperties.GetWireProp[root, prop];
SELECT prop FROM
CoreOps.nameProp    => CoreProperties.PutWireProp[root, prop, NameFusion[object, prop, val, rootValue]];
mode.decoration.geometryProp => PipalCore.AddGeometry[mode.decoration, root, PipalCore.GetGeometry[mode.decoration, fused]];
mode.decoration.portProp  => PipalCore.AddPort[mode.decoration, root, PipalCore.GetPort[mode.decoration, fused]]; -- this never happens during connector extraction, because pins are not yet there, but might occur when called from SisyphImpl.ProcessGlobalName
ENDCASE       => CoreProperties.PutWireProp[root, prop, DefaultFusion[object, prop, val, rootValue]];
};
CoreProperties.Enumerate[fused.properties, EachProperty];
};
This proc really does the fusion of fused and root, by wiping fused of some tables, and adding interesting properties of fused to root.
DeleteFused: PROC [mode: Mode, object: Object, fused: RefTab.Ref, loser, winner: Wire] = {
IF ~RefTab.Fetch[fused, loser].found THEN SIGNAL InternalBug[];
IF RootWire[fused, loser]#loser THEN SIGNAL InternalBug[];
IF ~RefTab.Fetch[fused, winner].found THEN SIGNAL InternalBug[];
IF RootWire[fused, winner]#winner THEN SIGNAL InternalBug[];
IF loser=winner THEN SIGNAL InternalBug[]; -- should never occur
FuseProperties[mode, object, loser, winner];
loser.properties ← NIL; -- to help GC
[] ← RefTab.Store[fused, loser, winner];
};
StructuredFusion: PUBLIC PROC [mode: Mode, object: Object, fused: RefTab.Ref, wire1, wire2: Wire] RETURNS [wire: Wire] = {
wire1 ← RootWire[fused, wire1];
wire2 ← RootWire[fused, wire2];
IF wire1=wire2 THEN RETURN [wire1];
SELECT TRUE FROM
wire1=wire2    => wire ← wire1;
wire1.size=0     => {DeleteFused[mode, object, fused, wire1, wire2]; wire ← wire2};
wire2.size=0    => {DeleteFused[mode, object, fused, wire2, wire1]; wire ← wire1};
wire1.size=wire2.size => {
wire ← CreateRoot[fused, wire1.size];
FOR i: NAT IN [0 .. wire.size) DO
wire[i] ← StructuredFusion[mode, object, fused, wire1[i], wire2[i]];
ENDLOOP;
DeleteFused[mode, object, fused, wire1, wire];
DeleteFused[mode, object, fused, wire2, wire];
};
ENDCASE     => SIGNAL FusionStructureMismatch[object, wire1, wire2];
};
Satellites and Names
OrNames: PROC [object: Object, name1, name2: ROPE] RETURNS [name: ROPENIL] = {
IF name1=NIL THEN RETURN [name2];
IF name2=NIL THEN RETURN [name1];
IF Rope.Equal[name1, name2] THEN RETURN [name1];
SIGNAL FusionPropMismatch[object, CoreOps.nameProp, name1, name2];
};
LayoutProcessSatellites: PROC [object: Object, satellites: LIST OF ROPE, props: Core.Properties] RETURNS [Core.Properties] = {
WHILE satellites#NIL DO
props ← LayoutProcessName[object, satellites.first, props];
satellites ← satellites.rest;
ENDLOOP;
RETURN [props];
};
LayoutProcessName: PROC [object: Object, name: ROPE, props: Core.Properties] RETURNS [Core.Properties] = {
name ← OrNames[object, name, NARROW [CoreProperties.GetProp[props, CoreOps.nameProp]]];
RETURN [CoreProperties.PutProp[props, CoreOps.nameProp, name]];
};
ComputeNameWires: PROC [mode: Mode, object: Object, fused: RefTab.Ref] RETURNS [nameToWires: SymTab.Ref] = {
EachWire: PROC [wire: Wire] = {
name: ROPE ← CoreOps.GetShortWireName[wire];
wires: Wires ← NARROW [SymTab.Fetch[nameToWires, name].val];
IF name=NIL OR CoreOps.Member[wires, wire] THEN RETURN;
wires ← CONS [wire, wires];
[] ← SymTab.Store[nameToWires, name, wires];
};
nameToWires ← SymTab.Create[mod: 3]; -- contains (for every name) the list of roots that have it for name
EnumerateRoots[fused, EachWire];
};
LayoutFusionByName: PUBLIC PostProcessProc = {
EachNameWires: SymTab.EachPairAction = {
name: ROPE = NARROW [key];
wires: Wires ← NARROW [val];
wire: Wire ← RootWire[fused, wires.first];
wires ← wires.rest;
WHILE wires#NIL DO
wire ← StructuredFusion[mode, object, fused, wire, wires.first];
PutF["Fusion by name for '%g'.\n", IO.rope[name]];
CoreProperties.PutWireProp[wire, $FusedByName, $FusedByName];
wires ← wires.rest;
ENDLOOP;
};
[] ← SymTab.Pairs[ComputeNameWires[mode, object, fused], EachNameWires];
};
NoFusionByName: PUBLIC PostProcessProc = {
EachNameWires: SymTab.EachPairAction = {
uniqueID: INT ← 0;
name: ROPE = NARROW [key];
wires: Wires ← NARROW [val];
wire: Wire ← RootWire[fused, wires.first];
[] ← CoreOps.SetShortWireName[wire, name];
wires ← wires.rest;
IF wires=NIL THEN RETURN;
PutF["NO fusion by name for '%g'.\n", IO.rope[name]];
WHILE wires#NIL DO
[] ← CoreOps.SetShortWireName[wires.first, IO.PutFR["%g$%g$", IO.rope[name], IO.int[uniqueID]]];
uniqueID ← uniqueID + 1;
wires ← wires.rest;
ENDLOOP;
};
[] ← SymTab.Pairs[ComputeNameWires[mode, object, fused], EachNameWires];
};
SchematicsFusionByName: PUBLIC PostProcessProc = {
EachNameWires: SymTab.EachPairAction = {
name: ROPE = NARROW [key];
hasComponents: BOOL = CoreOps.ParseWireName[name].components#NIL;
wires: Wires ← NARROW [val];
wire: Wire ← RootWire[fused, wires.first];
wires ← wires.rest;
WHILE wires#NIL DO
wire ← StructuredFusion[mode, object, fused, wire, wires.first];
PutF["Fusion by name for '%g'.\n", IO.rope[name]];
CoreProperties.PutWireProp[wire, $FusedByName, $FusedByName];
wires ← wires.rest;
ENDLOOP;
[] ← SymTab.Store[nameToWire, name, wire];
IF NOT hasComponents
THEN [] ← CoreOps.SetShortWireName[wire, name]
ELSE names ← CONS [name, names];
};
nameToWire: SymTab.Ref = SymTab.Create[mod: 11];
names: ROPESNIL;
We first fuse all the nameWire with same name, and at the same time prepare the list of all the names that have components
[] ← SymTab.Pairs[ComputeNameWires[mode, object, fused], EachNameWires];
We sort the names, using the trick that foo[2].mumble or foo[2][3] are after foo[2] in the lexicographic order
FOR list: ROPES ← RopeList.Sort[names, RopeList.Compare], list.rest WHILE list#NIL DO
name: ROPE ← list.first;
wire: Wire = RootWire[fused, NARROW [SymTab.Fetch[nameToWire, name].val]];
base: ROPE; components: ROPESNIL;
matchingWire: Wire;
[base, components] ← CoreOps.ParseWireName[name];
matchingWire ← NARROW [SymTab.Fetch[nameToWire, base].val];
WHILE components#NIL DO
index: INT ← -1;
IF matchingWire=NIL THEN SIGNAL FusionByNameMismatch[object, IO.PutFR["Path name %g does not correspond to any wire", IO.rope[name]], wire];
matchingWire ← RootWire[fused, matchingWire];
FOR i: NAT IN [0 .. matchingWire.size) DO
subWireName: ROPE ← CoreOps.GetShortWireName[matchingWire[i]];
IF subWireName=NIL THEN subWireName ← IF i<256 THEN numbers[i] ELSE IO.PutR1[IO.int[i]]; -- speedup hack to avoid allocating lots of ropes
IF Rope.Equal[subWireName, components.first] THEN {
IF index=-1 THEN index ← i ELSE FusionByNameMismatch[object, IO.PutFR["Current wire has 2 or more sub-wires with field `%g'", IO.rope[components.first]], wire];
};
ENDLOOP;
IF index=-1 THEN SIGNAL FusionByNameMismatch[object, IO.PutFR["Current wire does not have a sub-wire with field `%g'", IO.rope[components.first]], wire];
matchingWire ← matchingWire[index];
components ← components.rest;
ENDLOOP;
[] ← StructuredFusion[mode, object, fused, matchingWire, wire];
ENDLOOP;
};
Constructing WireSeq and CellTypes
FusionWire: PROC [mode: Mode, object: Object, fused: RefTab.Ref, publicToActual: RefTab.Ref, public: Wire, copyProps: BOOL] RETURNS [actual: Wire] = {
EachProperty: PROC [prop: ATOM, val: REF ANYNIL] = {
newVal: REF ANYSELECT prop FROM
mode.decoration.portProp, mode.decoration.geometryProp => NIL,
ENDCASE => val;
CoreProperties.PutWireProp[actual, prop, newVal];
};
actual ← NARROW [RefTab.Fetch[publicToActual, public].val];
IF actual#NIL THEN RETURN;
actual ← CreateRoot[fused, public.size];
IF copyProps THEN CoreProperties.Enumerate[public.properties, EachProperty];
FOR i: NAT IN [0 .. public.size) DO
actual[i] ← FusionWire[mode, object, fused, publicToActual, public[i], copyProps];
ENDLOOP;
[] ← RefTab.Store[publicToActual, public, actual];
};
FusionWireSeq: PROC [mode: Mode, object: Object, fused: RefTab.Ref, publicToActual: RefTab.Ref, public: WireSeq] RETURNS [actual: Wire] = {
actual ← CoreOps.CreateWires[public.size];
FOR i: NAT IN [0 .. actual.size) DO
actual[i] ← FusionWire[mode, object, fused, publicToActual, public[i], FALSE];
ENDLOOP;
};
Creates a DAG Wire from a RefTab, getting rid of wires that have their father also in the list.
CreateDAGWireSeq: PROC [table: RefTab.Ref] RETURNS [wire: WireSeq] = {
wires: LIST OF Wire ← NIL;
EachKeyDelete: RefTab.EachPairAction = {
WireDelete: PROC [wire: Wire] = {
IF ~RefTab.Delete[table, wire] THEN RETURN; -- already done
FOR i: NAT IN [0 .. wire.size) DO
WireDelete[wire[i]];
ENDLOOP;
};
wire: Wire ← NARROW [key];
FOR i: NAT IN [0 .. wire.size) DO
delete all the sons
WireDelete[wire[i]];
ENDLOOP;
};
index: NAT ← 0;
SummarizeWires: RefTab.EachPairAction = {
wire[index] ← NARROW [key];
index ← index+1;
};
[] ← RefTab.Pairs[table, EachKeyDelete];
wire ← CoreOps.CreateWires[RefTab.GetSize[table]];
[] ← RefTab.Pairs[table, SummarizeWires];
IF index#RefTab.GetSize[table] THEN SIGNAL InternalBug[];
};
MakeRecord: PROC [mode: Mode, object: Object, fused: RefTab.Ref, cellInstances: LIST OF CoreClasses.CellInstance] RETURNS [record: CellType] = {
publics: RefTab.Ref ← RefTab.Create[5];
internals: RefTab.Ref ← RefTab.Create[5];
WireDagIfy: PROC [wire: Wire, maxIter: NAT ← 32] = {
32 should be enough to avoid 815
IF maxIter=0 THEN SIGNAL StructuralLoop[object, wire]; -- probably loop in the Wire structure
IF RootWire[fused, wire]#wire THEN SIGNAL InternalBug[];
FOR i: NAT IN [0 .. wire.size) DO
wire[i] ← RootWire[fused, wire[i]];
WireDagIfy[wire[i], maxIter-1];
ENDLOOP;
};
InternalDagIfy: PROC [wire: Wire] = {
IF CoreProperties.GetWireProp[wire, $Public]=$Public THEN
{[] ← RefTab.Store[publics, wire, NIL]; CoreProperties.PutWireProp[wire, $Public, NIL]};
[] ← RefTab.Store[internals, wire, NIL];
WireDagIfy[wire];
};
We find out who are the internals, and we clean up wires
EnumerateRoots[fused, InternalDagIfy];
We replace in all instances wires by their roots
FOR list: LIST OF CoreClasses.CellInstance ← cellInstances, list.rest WHILE list#NIL DO
instance: CoreClasses.CellInstance ← list.first;
actual: Wire ← instance.actual;
FOR i: NAT IN [0 .. actual.size) DO
wire: Wire ← RootWire[fused, actual[i]];
IF ~CoreOps.CorrectConform[wire, instance.type.public[i]] THEN SIGNAL StructureMismatch[object, i, actual, instance.type.public];
actual[i] ← wire;
ENDLOOP;
ENDLOOP;
We build the CellType
record ← CoreClasses.CreateRecordCell[
public: CreateDAGWireSeq[publics], internal: CreateDAGWireSeq[internals],
instances: cellInstances,
giveNames: TRUE
];
};
Extraction
debugCache: BOOLFALSE;
objectCache: Pipal.ObjectCache ← Pipal.CreateObjectCache[];
Maps object -> LIST OF CacheData
CacheData: TYPE = RECORD [
mode: Mode, context: Context,
result: REF, props: Properties ← NIL
];
SearchCache: PROC [object: Object, mode: Mode, context: Context] RETURNS [found: BOOLFALSE, result: REF, props: Properties] = {
IF debugCache THEN RETURN;
FOR list: LIST OF CacheData ← NARROW [RefTab.Fetch[objectCache, object].val], list.rest WHILE list#NIL DO
IF list.first.mode=mode AND mode.objectEqual[object, list.first.context, context] THEN RETURN [found: TRUE, result: list.first.result, props: list.first.props];
ENDLOOP;
};
We fill the cache
AddInCache: PROC [object: Object, mode: Mode, context: Context, result: REF, props: Properties] = {
cache: LIST OF CacheData ← NARROW [RefTab.Fetch[objectCache, object].val];
cache ← CONS [[mode: mode, context: context, result: result, props: props], cache];
[] ← RefTab.Store[objectCache, object, cache];
};
Extract: PUBLIC ExtractProc = {
found: BOOL;
[found, result, props] ← SearchCache[object, mode, context];
IF found THEN RETURN;
[result, props] ← NonCachingExtract[object, mode, context];
AddInCache[object, mode, context, result, props];
};
NonCachingExtract: PUBLIC ExtractProc = {
refProc: REF ExtractProc;
refProc ← NARROW [Pipal.ObjectMethod[object, mode.extractMethod]];
[result, props] ← (IF refProc=NIL THEN ExtractConnectized ELSE refProc^)[object, mode, context];
We detect trivial causes of bugs!
IF result=NIL THEN RETURN;
WITH result SELECT FROM
wire: Wire    => IF props#NIL THEN SIGNAL CallerBug[];
wires: Wires    => IF props#NIL THEN SIGNAL CallerBug[];
cellType: CellType  =>
IF NOT PipalCore.HasObject[mode.decoration, cellType] THEN SIGNAL CallerBug[]; -- decorations missing!
ENDCASE    => IF result#NIL THEN SIGNAL CallerBug[]; -- probably some ExtractProc is grossly wrong
};
ExtractConnectized: PUBLIC ExtractProc = {
SELECT PipalConnect.GetType[object, mode.connectMode] FROM
null => result ← NIL;
leaf => IF PipalConnect.CountPorts[object, mode.connectMode, PipalInt.AbutBox[object]]=1
THEN {
wire: Wire ← CoreOps.CreateWire[];
PipalCore.PutPort[mode.decoration, wire, object];
result ← wire;
} ELSE {
wires: Wires ← NIL;
EachPort: PipalConnect.EachPortProc = {
wire: Wire ← CoreOps.CreateWire[];
IF port=Pipal.void THEN SIGNAL InternalBug[];
PipalCore.PutPort[mode.decoration, wire, PipalInt.TransformObject[transformation, port]];
wires ← CONS [wire, wires];
};
[] ← PipalConnect.EnumeratePorts[object, mode.connectMode, PipalInt.AbutBox[object], EachPort];
result ← wires;
};
composite => {
cc: PipalConnect.Composer ← PipalConnect.GetComposer[object, mode.connectMode, PipalInt.AbutBox[object]];
record: CellType ← ExtractConnector[mode, object, context, cc];
PipalCore.PutObject[mode.decoration, record, object];
result ← record;
};
ENDCASE => SIGNAL CallerBug[];
};
PortToWireSequence: TYPE = RECORD [SEQUENCE size: NAT OF Core.Wire];
Maps a portIndex (as obtained by PipalConnect.EnumeratePorts to wires).
SubInstanceSeq: TYPE = RECORD [SEQUENCE size: NAT OF REF PortToWireSequence];
SetSubPorts: PROC [publicToActual: RefTab.Ref, child: Object, mode: Mode, childTrans: PipalInt.Transformation, addGeometry: BOOL] RETURNS [subPorts: REF PortToWireSequence] = {
SearchWire: PipalConnect.EachPortProc = {
EachWirePair: RefTab.EachPairAction = {
pub: Wire = NARROW [key];
act: Wire = NARROW [val];
pubGeom: Object = PipalCore.GetPort[mode.decoration, pub];
IF pubGeom=Pipal.void THEN RETURN;
IF NOT mode.connectMode.touch[mode.connectMode.touch, childTrans, pubGeom, transformation, port] THEN RETURN;
subPorts[portIndex] ← act;
IF NOT addGeometry THEN RETURN;
PipalCore.AddGeometry[mode.decoration, act, PipalInt.TransformObject[childTrans, pubGeom]];
};
IF port=Pipal.void THEN SIGNAL InternalBug[];
subPorts[portIndex] ← NIL;
[] ← RefTab.Pairs[publicToActual, EachWirePair];
IF subPorts[portIndex] = NIL THEN SIGNAL InternalBug[];
};
subPorts ← NEW [PortToWireSequence[PipalConnect.CountPorts[child, mode.connectMode, PipalInt.AbutBox[child]]]];
[] ← PipalConnect.EnumeratePorts[child, mode.connectMode, PipalInt.AbutBox[child], SearchWire, childTrans];
};
ExtractConnector: PROC [mode: Mode, object: Object, context: Context, cc: PipalConnect.Composer] RETURNS [record: CellType] = {
index: NAT ← 0;
portsToWires: REF PortToWireSequence;
fused: RefTab.Ref ← RefTab.Create[3];
subInstances: REF SubInstanceSeq;
currentInstances: LIST OF CoreClasses.CellInstance ← NIL;
EachChild: PipalInt.EachChildProc = {
subResult: REF; subProps: Properties;
subType: PipalConnect.Type ← PipalConnect.GetType[child, mode.connectMode];
What about computing subContext here, such as the overlap?
[subResult, subProps] ← Extract[child, mode, context];
IF subResult=NIL
THEN {IF subType#null THEN SIGNAL CallerBug[]}
ELSE WITH subResult SELECT FROM
subWire: Wire    => {
dagTable: RefTab.Ref ← RefTab.Create[1];
[] ← FusionWire[mode, object, fused, dagTable, subWire, TRUE];
subInstances[index] ← SetSubPorts[dagTable, child, mode, transformation, TRUE];
};
subWires: Wires    => {
dagTable: RefTab.Ref ← RefTab.Create[9];
WHILE subWires#NIL DO
[] ← FusionWire[mode, object, fused, dagTable, subWires.first, TRUE];
subWires ← subWires.rest;
ENDLOOP;
subInstances[index] ← SetSubPorts[dagTable, child, mode, transformation, TRUE];
};
subCellType: CellType => {
publicToActual: RefTab.Ref ← RefTab.Create[(2*subCellType.public.size+3)/2];
instance: CoreClasses.CellInstance ← CoreClasses.CreateInstance[
actual: FusionWireSeq[mode, object, fused, publicToActual, subCellType.public],
type: subCellType, props: subProps
];
it is impossible here to check for conformance, since fusion might have been done differently in different parts of the DAG
PipalCore.PutTrans[mode.decoration, instance, transformation];
subInstances[index] ← SetSubPorts[publicToActual, child, mode, transformation, FALSE];
currentInstances ← CONS [instance, currentInstances];
};
ENDCASE    => SIGNAL InternalBug[];
index ← index + 1;
};
PutF["Extracting [%g] cell.\n", IO.rope[mode.decoration.name]];
subInstances ← NEW [SubInstanceSeq[PipalInt.CountChildren[cc.object]]];
portsToWires ← NEW [PortToWireSequence[cc.ports.size]];
What about modifying the context!?
[] ← PipalInt.Enumerate[cc.object, EachChild];
FOR i: NAT IN [0 .. cc.size) DO
node: PipalConnect.Node = cc[i];
wire: Wire ← NIL;
FOR bb: NAT IN [0 .. node.size) DO
binding: PipalConnect.Binding ← node[bb];
actual: Wire ← subInstances[binding.childIndex][binding.nodeIndex];
wire ← IF wire = NIL THEN actual ELSE StructuredFusion[mode, object, fused, wire, actual];
ENDLOOP;
IF wire=NIL THEN wire ← CreateRoot[fused, 0];
IF i<cc.ports.size THEN portsToWires[i] ← wire; -- but remember: it's not the final Root!
ENDLOOP;
mode.postProcessFused[mode, object, context, fused, currentInstances];
We set portsToWires, once all fusion is over
FOR i: NAT IN [0 .. cc.ports.size) DO
wire: Wire ← RootWire[fused, portsToWires[i]];
portsToWires[i] ← wire; -- useless of course!
CoreProperties.PutWireProp[wire, $Public, $Public];
PipalCore.AddPort[mode.decoration, wire, cc.ports[i]];
ENDLOOP;
record ← MakeRecord[mode, object, fused, currentInstances];
PutF["Extracted [%g] cell (%g instances)\n", IO.rope[mode.decoration.name], IO.int[PipalInt.CountChildren[cc.object]]];
};
Some Extract Procs
registeredExtractProcs: RefTab.Ref ← RefTab.Create[];
RegisterExtractProc: PUBLIC PROC [key: ATOM, extractProc: ExtractProc] = {
IF NOT RefTab.Store[registeredExtractProcs, key, NEW [ExtractProc ← extractProc]] THEN TerminalIO.PutF["ExtractProc overwritten for $%g.\n", IO.atom[key]];
};
FetchExtractProc: PUBLIC PROC [key: ATOM] RETURNS [extractProc: ExtractProc ← NIL] = {
refProc: REF ExtractProc ← NARROW [RefTab.Fetch[registeredExtractProcs, key].val];
IF refProc#NIL THEN RETURN [refProc^];
};
LayoutExtractAnnotation: ExtractProc = {
annotation: Pipal.Annotation = NARROW [object];
SELECT annotation.key FROM
mode.extractAnnotationProp => {
atom: ATOM = NARROW [annotation.value];
proc: ExtractProc ← FetchExtractProc[atom];
IF proc=NIL THEN {
TerminalIO.PutF["*** ExtractProc $%g not registered. You must run the program defining it.\n", IO.atom[atom]]; SIGNAL CallerBug[];
};
[result, props] ← proc[annotation.child, mode, context];
};
PipalMos.indirectProp => {
publicToActual: RefTab.Ref ← RefTab.Create[];
CopyPins: CoreOps.EachWirePairProc = {
PipalCore.PutPort[mode.decoration, actualWire, PipalCore.GetPort[mode.decoration, publicWire]];
[] ← RefTab.Store[publicToActual, publicWire, actualWire];
};
indCT, icon: CellType;
[result, props] ← Extract[annotation.child, mode, context];
indCT ← NARROW [result];
icon ← CreateIcon[indCT];
PipalCore.PutObject[mode.decoration, icon, object];
[] ← CoreOps.VisitBindingSeq[actual: icon.public, public: indCT.public, eachWirePair: CopyPins];
result ← icon;
};
PipalMos.transistorProp => RETURN ExtractTransistor[object, mode, context];
Pipal.nameProp => {
name: ROPENARROW [annotation.value];
[result, props] ← NonCachingExtract[annotation.child, mode, context];
IF result=NIL THEN RETURN;
WITH result SELECT FROM
subWire: Wire    =>
subWire.properties ← LayoutProcessName[object, name, subWire.properties];
subWires: Wires   => SIGNAL CallerBug[]; -- what to do with that name!
subCellType: CellType =>
subCellType.properties ← LayoutProcessName[object, name, subCellType.properties];
ENDCASE     => SIGNAL InternalBug[];
};
ENDCASE => [result, props] ← ExtractConnectized[object, mode, context];
};
LayoutExtractStar: ExtractProc = {
star: PipalMos.Star = NARROW [object];
satellites: LIST OF ROPE ← PipalMos.GetNonItalicRopes[star];
IF NOT star.overlayStar THEN {
[result, props] ← Extract[star.master, mode, context];
IF result=NIL THEN RETURN;
WITH result SELECT FROM
subWire: Wire    => {
wire: Wire ← CoreOps.CopyWire[subWire];
PipalCore.PutPort[mode.decoration, wire, object];
wire.properties ← LayoutProcessSatellites[object, satellites, wire.properties];
result ← wire;
};
subWires: Wires   => SIGNAL CallerBug[]; -- what to do with that name!
subCellType: CellType => props ← LayoutProcessSatellites[object, satellites, props];
ENDCASE     => SIGNAL InternalBug[];
} ELSE {
[result, props] ← NonCachingExtract[star.master, mode, context];
IF result=NIL THEN RETURN;
WITH result SELECT FROM
subWire: Wire    => SIGNAL CallerBug[]; -- object satellite!?
subWires: Wires   => SIGNAL CallerBug[]; -- what to do with that name!
subCellType: CellType => subCellType.properties ← LayoutProcessSatellites[object, satellites, subCellType.properties];
ENDCASE     => SIGNAL InternalBug[];
};
};
ExtractTransistor: PUBLIC ExtractProc = {
Decorate: PROC [port: CoreClasses.TransistorPort, geom: Object] = {
wire: Wire = cellType.public[ORD [port]];
PipalCore.PutPort[mode.decoration, wire, geom];
PipalCore.PutGeometry[mode.decoration, wire, geom];
};
type: PipalMos.TransistorType;
ch1, ch2, gate, bulk: Object;
width, length: INT;
coreType: CoreClasses.TransistorType;
cellType: CellType;
[type, ch1, ch2, gate, bulk, width, length] ← PipalMos.ExtractTransistor[object];
coreType ← SELECT type FROM
nE => nE, pE => pE, ENDCASE => ERROR;
cellType ← CoreClasses.CreateTransistor[
type: coreType, length: length, width: width
];
Decorate[gate, gate];
Decorate[ch1, ch1];
Decorate[ch2, ch2];
IF bulk#Pipal.void THEN Decorate[Vdd, bulk];
PipalCore.PutObject[mode.decoration, cellType, object];
result ← cellType;
};
ExtractCellAsWire: PUBLIC ExtractProc = {
wire: Wire ← CoreOps.CreateWire[];
PipalCore.PutPort[mode.decoration, wire, object];
result ← wire;
};
ExtractNull: PUBLIC ExtractProc = {result ← NIL};
Extraction mode procs
AlwaysTrue: PROC [Object, Context, Context] RETURNS [BOOLTRUE] = {};
Icon class
iconClass: PUBLIC Core.CellClass ← CoreOps.SetClassPrintProc[NEW [Core.CellClassRec ← [name: "Icon", recast: RecastIcon, layersProps: TRUE]], PrintIcon];
CreateIcon: PUBLIC PROC [cellType: CellType, name: ROPENIL, props: Properties ← NIL] RETURNS [icon: CellType] = {
icon ← CoreOps.CreateCellType[
class: iconClass, public: CoreOps.CopyWire[cellType.public],
data: cellType, name: name, props: props
];
};
RecastIcon: Core.RecastProc = {new ← NARROW [me.data]};
PrintIcon: CoreOps.PrintClassProc = {
ct: CellType ← NARROW [data];
CoreOps.PrintIndent[indent, out];
out.PutF["Icon of `%g':\n", IO.rope[CoreOps.GetCellTypeName[ct]]];
CoreOps.PrintCellType[cellType: ct, out: out, indent: indent, level: level];
};
Exceptions
InternalBug: PUBLIC SIGNAL [] = CODE;
CallerBug: PUBLIC SIGNAL [] = CODE;
FusionPropMismatch: PUBLIC SIGNAL [object: Object, prop: ATOM, value1, value2: REF] = CODE;
FusionStructureMismatch: PUBLIC SIGNAL [object: Object, wire1, wire2: Wire] = CODE;
StructureMismatch: PUBLIC SIGNAL [object: Object, index: NAT, actual, subPublic: WireSeq] = CODE;
FusionByNameMismatch: PUBLIC SIGNAL [object: Object, msg: ROPE, wire: Wire] = CODE;
StructuralLoop: PUBLIC SIGNAL [object: Object, wire: Wire] = CODE;
Progress Report
OutputType: TYPE = {none, terminal, messageWindow};
outputFlag: OutputType ← terminal;
PutF: PUBLIC PROC [format: ROPE, v1, v2, v3, v4, v5: IO.Value ← [null[]]] = {
SELECT outputFlag FROM
terminal => TerminalIO.PutF[format, v1, v2, v3, v4, v5];
messageWindow => MessageWindow.Append[IO.PutFR[format, v1, v2, v3, v4, v5], TRUE];
ENDCASE => {};
};
Some Extraction Modes
layoutMode: PUBLIC Mode ← NEW [ModeRec ← [
decoration: PipalCore.layoutDecoration,
extractMethod: Pipal.RegisterMethod["LayoutExtraction"],
connectMode: PipalConnect.layoutMode,
extractAnnotationProp: $CMosBExtractProc, -- for the sake of compatibility!
objectEqual: AlwaysTrue,
postProcessFused: LayoutFusionByName
]];
schematicsMode: PUBLIC Mode ← NIL;
rawLayoutMode: PUBLIC Mode ← NIL;
Initialization
RopeArray: TYPE = ARRAY [0 .. 256) OF ROPE;
numbers: REF RopeArray ← NEW [RopeArray];
FOR i: NAT IN [0 .. 256) DO numbers[i] ← IO.PutR1[IO.int[i]] ENDLOOP;
RegisterExtractProc[$ExtractCellAsWire, ExtractCellAsWire];
RegisterExtractProc[$ExtractNull, ExtractNull];
Layer properties
PipalCore.RegisterRoutingLayer[$Ndif];
PipalCore.RegisterRoutingLayer[$Pdif];
PipalCore.RegisterRoutingLayer[$Pol];
PipalCore.RegisterRoutingLayer[$Met];
PipalCore.RegisterRoutingLayer[$Met2];
PipalCore.RegisterRoutingLayer[$Ovg];
Pipal.PutClassMethod[Pipal.annotationClass, layoutMode.extractMethod, NEW [ExtractProc ← LayoutExtractAnnotation]];
Pipal.PutClassMethod[PipalMos.starClass, layoutMode.extractMethod, NEW [ExtractProc ← LayoutExtractStar]];
END.