LichenReadExt.Mesa
Last Edited by: Spreitzer, July 11, 1985 9:30:00 pm PDT
DIRECTORY
Asserting USING [Assertions, Assertion, Terms, Assert, AssertFn, AssertFn1, FnVal],
AssertingIO, Atom, Basics, BasicTime, LichenDataStructure, LichenOps, FS, IO, List, ProcessProps, RedBlackTree, Rope;
LichenReadExt: CEDAR PROGRAM
IMPORTS Asserting, AssertingIO, Atom, BasicTime, LichenDataStructure, LichenOps, FS, IO, List, ProcessProps, RedBlackTree, Rope
= BEGIN OPEN Asserting, LichenDataStructure, LichenOps;
Reader: TYPE = REF ReaderRep;
ReaderRep: TYPE = RECORD [
keyword: ROPE,
read: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading],
data: REF ANY];
readers: SymbolTable ← RedBlackTree.Create[GetReaderKey, CompareReaders];
DesignReading: TYPE = REF DesignReadingRep;
DesignReadingRep: TYPE = RECORD [
fetTypes: SymbolTable];
CellReading: TYPE = REF CellReadingRep;
CellReadingRep: TYPE = RECORD [
dr: DesignReading,
rScale: REAL--ohms-- ← 1.0E-3,
cScale: REAL--farads-- ← 1.0E-18,
lUnits: REAL--meters-- ← 1.0E-8,
scalingDefined: BOOLFALSE,
fetCount: INT ← 0];
Path: TYPE = LIST OF REF ANY--UNION [Vertex, VertexArray]--;
VertexArray: TYPE = REF VertexArrayRep;
VertexArrayRep: TYPE = RECORD [
shape: ARRAY Dim OF NAT,
vertices: SEQUENCE length: NAT OF Vertex];
Dim: TYPE = {X, Y};
FetTerminal: TYPE = RECORD [
name: ROPE,
length: INT,
attrs: Assertions];
Box: TYPE = RECORD [xmin, ymin, xmax, ymax: INT];
TransformAsTerms: TYPE = Terms;
ReadDesign: PROC [rootCellFileName: ROPE, keepAll: BOOLFALSE] RETURNS [design: Design] =
BEGIN
dr: DesignReading ← NEW [DesignReadingRep ← [
fetTypes: RedBlackTree.Create[GetFetKey, CompareFetTypes]
]];
cp: FS.ComponentPositions;
fullFName, wDir: ROPE;
Doit: PROC = {[] ← ReadCellType[design, rootCellFileName, dr]};
[fullFName, cp, ] ← FS.ExpandName[rootCellFileName];
wDir ← fullFName.Substr[len: cp.base.start];
design ← NEW [DesignRep ← [
name: fullFName.Substr[start: cp.base.start, len: cp.base.length],
cellTypesByName: RedBlackTree.Create[GetAliasKey, CompareAliases],
cellTypesByAddress: RedBlackTree.Create[GetIDKey, CompareByAddress],
allKept: keepAll,
other: AssertFn1[$DesignReading, dr, NIL]
]];
ProcessProps.PushPropList[List.PutAssoc[$WorkingDirectory, wDir, NIL], Doit];
END;
GetDesignReading: PROC [design: Design] RETURNS [dr: DesignReading] =
{dr ← NARROW[FnVal[$DesignReading, design.other]]};
ProperNames: PROC [name: ROPE] RETURNS [names: Names] = {
names ← IF name.Fetch[name.Length[]-1] = '# THEN [progged: LIST[name]] ELSE [designed: LIST[name]];
};
ReadCellType: PROC [design: Design, cellFileName: ROPE, dr: DesignReading] RETURNS [ct: CellType] = {
cp: FS.ComponentPositions;
fullFName, cellTypeName: ROPE;
from: IO.STREAM;
s: Source;
cr: CellReading ← NEW[CellReadingRep ← [dr: dr]];
[fullFName, cp] ← ExpandName[cellFileName, "ext"];
cellTypeName ← fullFName.Substr[start: cp.base.start, len: cp.base.length];
ct ← NEW [CellTypeRep ← [
design: design,
names: ProperNames[cellTypeName],
file: NIL,
ports: NEW [PortSeq[0]],
parts: RedBlackTree.Create[GetAliasKey, CompareAliases],
otherPrivate: AssertFn1[$CellReading, cr, NIL]
]];
s ← [from ← FS.StreamOpen[fullFName], fullFName];
DO
keyword: ROPE;
reader: Reader;
[] ← from.SkipWhitespace[];
IF from.EndOf[] THEN EXIT;
keyword ← from.GetTokenRope[TokenBreak].token;
reader ← NARROW[readers.Lookup[keyword]];
IF reader # NIL
THEN reader.read[s, ct, reader, cr]
ELSE {
terms: Terms ← GetLineTerms[from];
reln: ATOM ← Atom.MakeAtom[keyword];
ct.otherPublic ← Assert[reln, terms, ct.otherPublic];
};
[] ← from.GetLineRope[];
ENDLOOP;
IF ct.parts # NIL AND ct.mirror = NIL THEN AddWorld[ct];
ct.publicKnown ← TRUE;
ct.privateKnown ← TRUE;
from.Close[];
AddCellType[ct];
};
GetLineTerms: PROC [from: IO.STREAM] RETURNS [terms: Terms] = {
tail: Terms ← terms ← NIL;
WHILE NOT from.EndOf[] DO
peek: CHAR ← from.PeekChar[];
SELECT peek FROM
'\n => RETURN;
IN [0C .. ' ] => IF from.GetChar[] # peek THEN ERROR;
ENDCASE => {
this: LORALIST[from.GetRefAny[]];
IF tail = NIL THEN terms ← this ELSE tail.rest ← this;
tail ← this};
ENDLOOP;
};
ExpandName: PROC [fileName, defaultExtension: ROPE] RETURNS [fullFName: ROPE, cp: FS.ComponentPositions] = {
[fullFName, cp, ] ← FS.ExpandName[fileName];
IF defaultExtension.Length[] > 0 AND cp.ext.length = 0 THEN {
fileName ← FS.ConstructFName[[
server: fullFName.Substr[cp.server.start, cp.server.length],
dir: fullFName.Substr[cp.dir.start, cp.dir.length],
subDirs: fullFName.Substr[cp.subDirs.start, cp.subDirs.length],
base: fullFName.Substr[cp.base.start, cp.base.length],
ext: defaultExtension,
ver: fullFName.Substr[cp.ver.start, cp.ver.length]
]];
[fullFName, cp, ] ← FS.ExpandName[fileName];
};
};
GetReading: PROC [ct: CellType] RETURNS [cr: CellReading] =
{cr ← NARROW[FnVal[$CellReading, ct.otherPrivate]]};
GetName: PROC [s: Source] RETURNS [name: ROPE] = {
from: IO.STREAM = s.stream;
[] ← from.SkipWhitespace[];
SELECT from.PeekChar[] FROM
'" => name ← from.GetRopeLiteral[];
ENDCASE => name ← from.GetTokenRope[TokenBreak].token;
};
TokenBreak: PROC [char: CHAR] RETURNS [cc: IO.CharClass] =
{cc ← SELECT char FROM IN [0C .. ' ] => sepr, ENDCASE => other};
ReadTech: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading] = {
from: IO.STREAM = s.stream;
techname: ROPE ← GetName[s];
IF ct.design.allKept THEN ct.otherPublic ← Assert[$tech, LIST[techname], ct.otherPublic];
};
ReadTimestamp: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading] = {
from: IO.STREAM = s.stream;
unixTime: INT ← from.GetInt[];
time: BasicTime.GMT ← BasicTime.Update[unixOrigin, unixTime];
ct.otherPublic ← Assert[$Source, LIST[ct.names.designed.first.Cat[".mag"], IO.PutFR["%g", IO.time[time]]], ct.otherPublic];
};
unixOrigin: BasicTime.GMT ← BasicTime.Pack[[
year: 1970,
month: January,
day: 1,
hour: 0,
minute: 0,
second: 0,
zone: 0--GMT, I hope--,
dst: no]];
ReadVersion: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading] = {
from: IO.STREAM = s.stream;
version: ROPE ← GetName[s];
deriver: ROPE = "UCB's Magic .extractor";
ct.otherPublic ← Assert[$DerivingProgram, LIST[deriver, version], ct.otherPublic];
};
ReadScale: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading] = {
from: IO.STREAM = s.stream;
rscale: INT ← from.GetInt[];
cscale: INT ← from.GetInt[];
lscale: INT ← from.GetInt[];
meters: ROPE = "meters";
IF cr.scalingDefined THEN Warn[s, "More than one scale statment"];
cr.scalingDefined ← TRUE;
cr.rScale ← rscale * cr.rScale;
cr.cScale ← cscale * cr.cScale;
cr.lUnits ← lscale * cr.lUnits;
ct.otherPublic ← AssertFn[$scale, LIST[NEW[REAL𡤌r.lUnits], meters], ct.otherPublic];
};
ReadNode: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading] = {
from: IO.STREAM = s.stream;
nodeName: ROPE ← GetName[s];
R: INT ← from.GetInt[];
C: INT ← from.GetInt[];
x: INT ← from.GetInt[];
y: INT ← from.GetInt[];
attrs: Assertions ← ReadAttrs[s];
nv: Vertex ← NEW [VertexRep ← [
names: ProperNames[nodeName],
parent: ct,
class: net,
other:
Assert[$R, LIST[NEW[REALR*cr.rScale]],
Assert[$C, LIST[NEW[REALC*cr.cScale]],
Assert[$locHint, LIST[NEW[INT←x], NEW[INT←y], $UnspecifiedLayer],
attrs ]]]
]];
AddVertex[nv];
};
ReadAttrs: PROC [s: Source, zeroNIL: BOOLFALSE] RETURNS [allTogetherNow: Assertions] = {
from: IO.STREAM = s.stream;
allTogetherNow ← NIL;
IF zeroNIL THEN {
[] ← from.SkipWhitespace[];
IF from.PeekChar[] = '0 THEN {
IF from.GetChar[] # '0 THEN ERROR;
RETURN};
};
DO
toke: ROPE ← from.GetTokenRope[AttrBreak !IO.EndOfStream => GOTO Dun].token;
attr: ROPENIL;
IF toke.Equal[","] THEN {Warn[s, "Extra comma"]; LOOP};
IF toke.Equal["\n"] THEN GOTO Return;
IF NOT toke.Equal["\""] THEN EXIT;
from.Backup['"];
attr ← from.GetRopeLiteral[ !IO.Error, IO.EndOfStream => {Warn[s, "not a rope literal"]; CONTINUE}];
IF attr # NIL THEN allTogetherNow ← Assert[$attr, LIST[attr], allTogetherNow];
toke ← from.GetTokenRope[AttrBreak !IO.EndOfStream => EXIT].token;
IF toke.Equal["\n"] THEN GOTO Return;
IF NOT toke.Equal[","] THEN EXIT;
ENDLOOP;
EXITS
Return => s.stream.Backup['\n];
Dun => NULL;
};
AttrBreak: PROC [char: CHAR] RETURNS [cc: IO.CharClass] =
{cc ← SELECT char FROM ',, '\n, '" => break, ENDCASE => sepr};
ReadEquiv: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading] = {
from: IO.STREAM = s.stream;
name1: ROPE ← GetName[s];
name2: ROPE ← GetName[s];
nv: Vertex ← ToVertex[ct, name1];
news: Names;
IF nv # NIL
THEN {news ← ProperNames[name2]}
ELSE {nv ← ToVertex[ct, name2]; news ← ProperNames[name1]};
AddNames[nv, news];
};
ReadFet: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading] = {
from: IO.STREAM = s.stream;
type: ROPE ← GetName[s];
xl: INT ← from.GetInt[];
yl: INT ← from.GetInt[];
xh: INT ← from.GetInt[];
yh: INT ← from.GetInt[];
area: INT ← from.GetInt[];
perim: INT ← from.GetInt[];
sub: ROPE ← GetName[s];
GATE: FetTerminal ← GetFetTerminal[s];
T1: FetTerminal ← GetFetTerminal[s];
T2: FetTerminal ← GetFetTerminal[s];
sct: CellType;
t: TransformAsTerms;
tv: Vertex;
DoTerm: PROC [portIndex: PortIndex, ft: FetTerminal] = {
na: VertexArray ← GetNets[s, ct, ft.name];
nv: Vertex ← na[0];
IF na.shape # [1, 1] THEN ERROR;
Connect[tv, nv, portIndex];
tv.other ← AssertFn1[$TermLen, NEW[INT𡤏t.length], tv.other, LIST[fetTerms[portIndex]], TRUE];
IF ft.attrs # NIL THEN tv.other ← AssertFn1[$TermAttrs, ft.attrs, tv.other, LIST[fetTerms[portIndex]], TRUE];
};
[sct, t] ← GetFetType[ct.design, type, [xl, yl, xh, yh], area, perim, T1.length+T2.length];
tv ← NEW [VertexRep ← [
names: [progged: LIST[IO.PutFR["Q%g", IO.int[cr.fetCount ← cr.fetCount + 1]]]],
type: sct,
parent: ct,
class: cell,
other: Assert[$t6, t, NIL]
]];
DoTerm[0, GATE];
DoTerm[1, T1];
DoTerm[2, T2];
AddVertex[tv];
};
fetTerms: ARRAY PortIndex[0 .. 2] OF ATOM = [$gate, $ch1, $ch2];
GetFetTerminal: PROC [s: Source] RETURNS [ft: FetTerminal] = {
from: IO.STREAM = s.stream;
ft.name ← GetName[s];
ft.length ← from.GetInt[];
ft.attrs ← ReadAttrs[s, TRUE];
};
GetFetType: PROC [design: Design, className: ROPE, innerGate: Box, area, perim, sumChannelLengths: INT] RETURNS [ct: CellType, tat: TransformAsTerms] = {
dr: DesignReading ← GetDesignReading[design];
ft: FetType ← NEW [FetTypeRep ← [className, area, perim, sumChannelLengths]];
rft: FetType;
rft ← NARROW[dr.fetTypes.Lookup[ft]];
IF rft = NIL THEN {
Set: PROC [type, mode: ATOM] = {
ft.ct.otherPublic ← AssertFn1[$MOSFETFlavor, LIST[type, mode], ft.ct.otherPublic];
ft.ct.equivClass ← Rope.Cat["MOSFET", Atom.GetPName[type], Atom.GetPName[mode]];
};
rft ← ft;
ft.ct ← NEW [CellTypeRep ← [
design: design,
names: [designed: LIST[IO.PutFR["%g[%g,%g,%g]", IO.rope[ft.className], IO.int[ft.area], IO.int[ft.perim], IO.int[ft.twiceLength]]]],
publicKnown: TRUE,
privateKnown: TRUE,
ports: FetPorts[],
otherPublic: AssertFn1[$MOSFETShape, LIST[NEW[REAL ← ft.twiceLength/2.0], NEW[REAL ← area*2.0/ft.twiceLength]], NIL]
]];
SELECT TRUE FROM
className.Equal["nfet"] => Set[$n, $E];
className.Equal["pfet"] => Set[$p, $E];
ENDCASE => ERROR;
dr.fetTypes.Insert[ft, ft];
AddCellType[ft.ct];
};
ct ← rft.ct;
tat ← MakeTAT[1, 0, innerGate.xmin, 0, 1, innerGate.ymin];
};
FetPorts: PROC RETURNS [fp: PortS] = {
fp ← NEW [PortSeq[3]];
fp[0] ← [names: [designed: LIST["gate"]] ];
fp[1] ← [names: [designed: LIST["ch1"]], equivClass: "channel" ];
fp[2] ← [names: [designed: LIST["ch2"]], equivClass: "channel" ];
};
MakeTAT: PROC [dxdx, dxdy, dx, dydx, dydy, dy: INT] RETURNS [tat: TransformAsTerms] = {
tat ← LIST[
NEW[INT ← dxdx],
NEW[INT ← dxdy],
NEW[INT ← dx],
NEW[INT ← dydx],
NEW[INT ← dydy],
NEW[INT ← dy]
];
};
FetType: TYPE = REF FetTypeRep;
FetTypeRep: TYPE = RECORD [
className: ROPE,
area, perim, twiceLength: INT,
ct: CellType ← NIL];
GetFetKey: PROC [data: REF ANY] RETURNS [key: REF ANY] --RedBlackTree.GetKey-- =
{key ← data};
CompareFetTypes: PROC [k, data: REF ANY] RETURNS [c: Basics.Comparison] = {
ft1: FetType ← NARROW[k];
ft2: FetType ← NARROW[data];
IF (c ← ft1.className.Compare[ft2.className]) # equal THEN RETURN;
IF (c ← CompareInts[ft1.area, ft2.area]) # equal THEN RETURN;
IF (c ← CompareInts[ft1.perim, ft2.perim]) # equal THEN RETURN;
c ← CompareInts[ft1.twiceLength, ft2.twiceLength];
};
CompareInts: PROC [i1, i2: INT] RETURNS [c: Basics.Comparison] =
{c ← SELECT i1 FROM
<i2 => less,
=i2 => equal,
>i2 => greater,
ENDCASE => ERROR};
ReadUse: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading] = {
from: IO.STREAM = s.stream;
typeName: ROPE ← GetName[s];
useId: ROPE ← GetName[s];
t: TransformAsTerms ← GetTransform[s];
cv: Vertex;
u: Use ← ParseUseDef[useId];
type: CellType ← EnsureType[ct.design, cr.dr, typeName, u.as, ct, u.childName];
cv ← NEW [VertexRep ← [
names: [unknown: LIST[u.childName]],
type: type,
parent: ct,
class: cell,
other: Assert[$t6, t, NIL]
]];
AddVertex[cv];
};
Use: TYPE = RECORD [childName: ROPE, as: ArraySpec];
ArraySpec: TYPE = RECORD [
variant: SELECT kind: * FROM
scalar => [],
array => [dims: ARRAY Dim OF RECORD [lo, hi, sep: INT]]
ENDCASE];
ParseUseDef: PROC [useId: ROPE] RETURNS [u: Use] = {
in: IO.STREAMIO.RIS[useId];
u.childName ← in.GetTokenRope[UseNameBreak].token;
IF in.EndOf[] THEN RETURN [[u.childName, [scalar[]]]]
ELSE {
as: ArraySpec.array ← [array[ALL[[0, 0, 0]]]];
Get: PROC [d: Dim] = {
IF in.GetChar[] # '[ THEN ERROR;
as.dims[d].lo ← in.GetInt[];
IF in.GetChar[] # ': THEN ERROR;
as.dims[d].hi ← in.GetInt[];
IF in.GetChar[] # ': THEN ERROR;
as.dims[d].sep ← in.GetInt[];
IF in.GetChar[] # '] THEN ERROR;
};
Get[X];
Get[Y];
IF NOT in.EndOf[] THEN ERROR;
in.Close[];
RETURN [[u.childName, as]];
};
};
UseNameBreak: PROC [char: CHAR] RETURNS [cc: IO.CharClass] --IO.BreakProc-- = {
cc ← SELECT char FROM
'[, '], ': => break,
ENDCASE => other;
};
EnsureType: PROC [design: Design, dr: DesignReading, typeName: ROPE, as: ArraySpec, parent: CellType, childName: ROPE] RETURNS [ct: CellType] = {
WITH as SELECT FROM
scalar => {
ct ← NARROW[Lookup[design.cellTypesByName, typeName]];
IF ct = NIL THEN ct ← ReadCellType[design, typeName, dr];
};
array => {
ec: ROPE ← typeName.Cat[FmtAS[as]];
eltType: CellType ← EnsureType[design, dr, typeName, [scalar[]], NIL, NIL];
d: Dim;
IF dims[X].lo = dims[X].hi THEN d ← Y ELSE
IF dims[Y].lo = dims[Y].hi THEN d ← X ELSE
{
d ← Y;
eltType ← EnsureType[design, dr, typeName, [array[[X: dims[X], Y: [0, 0, 0]]]], parent, childName];
};
ct ← NEW [CellTypeRep ← [
design: design,
names: [progged: LIST[IO.PutFR["%g(%g.%g)", IO.rope[ec], IO.rope[PickAName[parent.names]], IO.rope[childName]]]],
equivClass: ec,
publicKnown: TRUE,
privateKnown: TRUE,
ports: NEW [PortSeq[0]],
parts: RedBlackTree.Create[GetAliasKey, CompareAliases]
]];
AddCellType[ct];
FOR z: INT IN [dims[d].lo .. dims[d].hi] DO
cv: Vertex ← NEW [VertexRep ← [
names: [designed: LIST[NameElt[z]]],
type: eltType,
parent: ct,
class: cell
]];
AddVertex[cv];
ENDLOOP;
};
ENDCASE => ERROR;
};
NameElt: PROC [i: INT] RETURNS [eltName: ROPE] =
{eltName ← IO.PutFR["[%g]", IO.int[i]]};
FmtAS: PROC [as: ArraySpec] RETURNS [r: ROPE] = {
r ← WITH as SELECT FROM
scalar => "scalar",
array => IO.PutFLR["[%g:%g:%g][%g:%g:%g]", LIST[
IO.int[dims[X].lo],
IO.int[dims[X].hi],
IO.int[dims[X].sep],
IO.int[dims[Y].lo],
IO.int[dims[Y].hi],
IO.int[dims[Y].sep]]],
ENDCASE => ERROR;
};
FmtShape: PROC [shape: ARRAY Dim OF NAT] RETURNS [r: ROPE] = {
r ← IO.PutFR["[X: %g, Y: %g]", IO.int[shape[X]], IO.int[shape[Y]]];
};
GetTransform: PROC [s: Source] RETURNS [tat: TransformAsTerms] = {
from: IO.STREAM = s.stream;
dxdx: INT ← from.GetInt[];
dxdy: INT ← from.GetInt[];
dx: INT ← from.GetInt[];
dydx: INT ← from.GetInt[];
dydy: INT ← from.GetInt[];
dy: INT ← from.GetInt[];
tat ← MakeTAT[dxdx, dxdy, dx, dydx, dydy, dy];
};
ReadMerge: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading] = {
from: IO.STREAM = s.stream;
name1: ROPE ← GetName[s];
name2: ROPE ← GetName[s];
R: INT ← from.GetInt[];
C: INT ← from.GetInt[];
path1: Path ← ParsePath[s, ct, name1];
path2: Path ← ParsePath[s, ct, name2];
MergeWork[s, ct, cr, name1, name2, path1, path2, R, C];
};
OneDSubscript: TYPE = RECORD [first, last: INT];
ParsePath: PROC [s: Source, from: CellType, asRope: ROPE] RETURNS [p: Path] = {
in: IO.STREAMIO.RIS[asRope];
t: Path ← p ← NIL;
Append: PROC [ra: REF ANY] = {
this: Path ← LIST[ra];
IF t = NIL THEN p ← this ELSE t.rest ← this;
t ← this};
LookupVertex: PROC [name: ROPE] RETURNS [v: Vertex] = {
v ← NARROW[Lookup[from.parts, name]];
};
LookupRange: PROC [ods: OneDSubscript, d: Dim] RETURNS [va: VertexArray, eltType: CellType] = {
size: INT ← 1 + ods.last - ods.first;
va ← NEW [VertexArrayRep[size]];
va.shape ← ALL[1];
va.shape[d] ← size;
FOR i: INT IN [ods.first .. ods.last] DO
name: ROPE ← NameElt[i];
v: Vertex ← LookupVertex[name];
IF v.class # cell THEN ERROR;
va[i - ods.first] ← v;
IF i = ods.first THEN eltType ← v.type ELSE IF eltType # v.type THEN ERROR;
ENDLOOP;
};
GetODS: PROC RETURNS [ods: OneDSubscript] = {
ods.first ← ods.last ← in.GetInt[];
SELECT in.PeekChar[] FROM
': => {
IF in.GetChar[] # ': THEN ERROR;
ods.last ← in.GetInt[];
};
',, '] => NULL;
ENDCASE => ERROR;
};
WHILE NOT in.EndOf[] DO
toke: ROPE ← in.GetTokenRope[PathNameBreak].token;
SELECT TRUE FROM
toke.Equal["/"] => LOOP;
toke.Fetch[0] = '[ => {
xs, ys: OneDSubscript ← [0, 0];
twoD: BOOLFALSE;
ra: REF ANY;
ys ← GetODS[];
toke ← in.GetTokenRope[PathNameBreak].token;
SELECT TRUE FROM
toke.Equal["]"] => NULL;
toke.Equal[","] => {
twoD ← TRUE;
xs ← GetODS[];
toke ← in.GetTokenRope[PathNameBreak].token;
IF NOT toke.Equal["]"] THEN ERROR;
};
ENDCASE => ERROR;
[ra, from] ← LookupRange[ys, Y];
Append[ra];
IF twoD THEN {
[ra, from] ← LookupRange[xs, X];
Append[ra]};
};
toke.Fetch[0] = '] => ERROR;
toke.Fetch[0] = ': => ERROR;
toke.Fetch[0] = ', => ERROR;
ENDCASE => {
v: Vertex ← LookupVertex[toke];
Append[v];
from ← v.type;
};
ENDLOOP;
in.Close[];
};
PathNameBreak: PROC [char: CHAR] RETURNS [cc: IO.CharClass] --IO.BreakProc-- = {
cc ← SELECT char FROM
'[, '], ':, '/, ', => break,
ENDCASE => other;
};
MergeWork: PROC [s: Source, ct: CellType, cr: CellReading, name1, name2: ROPE, path1, path2: Path, R, C: INT] = {
na1, na2: VertexArray;
IF path1.first=path2.first AND ISTYPE[path1.first, Vertex] THEN {
v1: Vertex ← NARROW[path1.first];
v2: Vertex ← NARROW[path2.first];
IF v1.class = cell AND v1.type.firstInstance = v1 AND v1.type.lastInstance = v1 THEN {
MergeWork[s, v1.type, cr, name1, name2, path1.rest, path2.rest, R, C];
RETURN;
};
};
na1 ← PathGet[path1];
na2 ← PathGet[path2];
IF na1.shape = na2.shape THEN {
FOR i: INT IN [0 .. na1.shape[X]) DO
FOR j: INT IN [0 .. na1.shape[Y]) DO
nv1: Vertex ← VAFetch[na1, i, j];
nv2: Vertex ← VAFetch[na2, i, j];
nv: Vertex ← MergeNets[nv1, nv2].merged;
AdjustRC[nv, R, C, cr];
ENDLOOP;
ENDLOOP;
}
ELSE {
Warn[s, "Different shapes: %g is %g and %g is %g", IO.rope[name1], IO.rope[FmtShape[na1.shape]], IO.rope[name2], IO.rope[FmtShape[na2.shape]]];
};
};
VAFetch: PROC [va: VertexArray, x, y: NAT] RETURNS [v: Vertex] = {
v ← va[x*va.shape[Y]+y];
};
VAStore: PROC [va: VertexArray, x, y: NAT, v: Vertex] = {
va[x*va.shape[Y]+y] ← v;
};
PathGet: PROC [path: Path] RETURNS [va: VertexArray] = {
IF path.rest # NIL THEN {
childCellType: CellType;
childShape, shape: ARRAY Dim OF NAT;
gcva: VertexArray ← PathGet[path.rest];
WITH path.first SELECT FROM
v: Vertex => {childCellType ← v.type; childShape ← ALL[1]};
va: VertexArray => {childCellType ← va[0].type; childShape ← va.shape};
ENDCASE => ERROR;
shape ← [X: childShape[X]*gcva.shape[X], Y: childShape[Y]*gcva.shape[Y]];
va ← NEW [VertexArrayRep[shape[X]*shape[Y]]];
va.shape ← shape;
FOR cx: NAT IN [0 .. childShape[X]) DO FOR cy: NAT IN [0 .. childShape[Y]) DO
cv: Vertex ← WITH path.first SELECT FROM
v: Vertex => v,
va: VertexArray => VAFetch[va, cx, cy],
ENDCASE => ERROR;
FOR gx: NAT IN [0 .. gcva.shape[X]) DO FOR gy: NAT IN [0 .. gcva.shape[Y]) DO
x: NAT ← cx * gcva.shape[X] + gx;
y: NAT ← cy * gcva.shape[Y] + gy;
VAStore[va, x, y, VGet[cv, VAFetch[gcva, gx, gy]]];
ENDLOOP ENDLOOP;
ENDLOOP ENDLOOP;
}
ELSE WITH path.first SELECT FROM
x: VertexArray => va ← x;
v: Vertex => {va ← NEW [VertexArrayRep[1]];
va.shape ← ALL[1];
va[0] ← v;
};
ENDCASE => ERROR;
};
VGet: PROC [cell, net: Vertex] RETURNS [pn: Vertex] = {
ec: ExtraConnection ← NIL;
IF cell.extraConnections = NIL THEN cell.extraConnections ← RedBlackTree.Create[GetECChildNet, CompareECChildNet];
ec ← NARROW[cell.extraConnections.Lookup[net]];
IF ec = NIL THEN {
pn ← NEW [VertexRep ← [
names: [progged: LIST[PickAName[cell.names].Cat[".", PickAName[net.names]]]],
parent: cell.parent,
extraConnections: RedBlackTree.Create[GetIDKey, CompareECSubCellThenChildNet],
class: net]];
AddVertex[pn];
ec ← NEW [ExtraConnectionRep ← [pn, cell, net]];
cell.extraConnections.Insert[ec, ec.childNet];
pn.extraConnections.Insert[ec, ec];
}
ELSE pn ← ec.parentNet;
};
GetNets: PROC [s: Source, from: CellType, name: ROPE] RETURNS [va: VertexArray] = {
path: Path ← ParsePath[s, from, name];
va ← PathGet[path];
};
ReadAdjust: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading] = {
from: IO.STREAM = s.stream;
pathName: ROPE ← GetName[s];
R: INT ← from.GetInt[];
C: INT ← from.GetInt[];
na: VertexArray ← GetNets[s, ct, pathName];
FOR x: INT IN [0 .. na.shape[X]) DO
FOR y: INT IN [0 .. na.shape[Y]) DO
nv: Vertex ← VAFetch[na, x, y];
AdjustRC[nv, R, C, cr];
ENDLOOP;
ENDLOOP;
};
AdjustRC: PROC [nv: Vertex, R, C: INT, cr: CellReading]= {
dr: REALR * cr.rScale;
dc: REALC * cr.cScale;
ChangeReal[nv, $R, dr];
ChangeReal[nv, $C, dc];
};
ChangeReal: PROC [v: Vertex, fn: REF ANY, delta: REAL] = {
rr: REF REALNARROW[FnVal[fn, v.other]];
IF rr = NIL THEN v.other ← AssertFn1[fn, rr ← NEW [REAL ← 0], v.other];
rr^ ← rr^ + delta;
};
ReadCap: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading] = {
from: IO.STREAM = s.stream;
name1: ROPE ← GetName[s];
name2: ROPE ← GetName[s];
C: INT ← from.GetInt[];
na1: VertexArray ← GetNets[s, ct, name1];
na2: VertexArray ← GetNets[s, ct, name2];
IF na1.shape = na2.shape THEN {
FOR x: INT IN [0 .. na1.shape[X]) DO
FOR y: INT IN [0 .. na1.shape[Y]) DO
nv1: Vertex ← VAFetch[na1, x, y];
nv2: Vertex ← VAFetch[na2, x, y];
ct.otherPrivate ← Assert[
$InterNodeCap,
LIST[
PickAName[nv1.names],
PickAName[nv2.names],
NEW [REALC * cr.cScale]],
ct.otherPrivate];
ENDLOOP;
ENDLOOP;
}
ELSE {
Warn[s, "Different shapes: %g is %g and %g is %g", IO.rope[name1], IO.rope[FmtShape[na1.shape]], IO.rope[name2], IO.rope[FmtShape[na2.shape]]];
};
};
Register: PROC [keyword: ROPE, read: PROC [s: Source, ct: CellType, reader: Reader, cr: CellReading], data: REF ANYNIL] = {
r: Reader ← NEW [ReaderRep ← [keyword, read, data]];
readers.Insert[r, keyword]};
GetReaderKey: PROC [data: REF ANY] RETURNS [key: ROPE] --RedBlackTree.GetKey-- =
{r: Reader ← NARROW[data]; key ← r.keyword};
CompareReaders: PROC [k, data: REF ANY] RETURNS [c: Basics.Comparison] --RedBlackTree.Compare-- = {
k1: ROPENARROW[k];
k2: ROPE ← GetReaderKey[data];
c ← k1.Compare[k2]};
Start: PROC = {
Register["tech", ReadTech];
Register["timestamp", ReadTimestamp];
Register["version", ReadVersion];
Register["scale", ReadScale];
Register["node", ReadNode];
Register["equiv", ReadEquiv];
Register["fet", ReadFet];
Register["use", ReadUse];
Register["merge", ReadMerge];
Register["adjust", ReadAdjust];
Register["cap", ReadCap];
AssertingIO.writers ← AssertFn1[$CellReading, NEW [AssertingIO.WriteProc ← AssertingIO.DontWrite], AssertingIO.writers];
AssertingIO.writers ← AssertFn1[$DesignReading, NEW [AssertingIO.WriteProc ← AssertingIO.DontWrite], AssertingIO.writers];
};
Start[];
END.