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: BOOL _ FALSE, 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: BOOL _ FALSE] 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: LORA _ LIST[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_cr.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[REAL _ R*cr.rScale]], Assert[$C, LIST[NEW[REAL _ C*cr.cScale]], Assert[$locHint, LIST[NEW[INT_x], NEW[INT_y], $UnspecifiedLayer], attrs ]]] ]]; AddVertex[nv]; }; ReadAttrs: PROC [s: Source, zeroNIL: BOOL _ FALSE] 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: ROPE _ NIL; 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_ft.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 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.STREAM _ IO.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.STREAM _ IO.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: BOOL _ FALSE; 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: REAL _ R * cr.rScale; dc: REAL _ C * cr.cScale; ChangeReal[nv, $R, dr]; ChangeReal[nv, $C, dc]; }; ChangeReal: PROC [v: Vertex, fn: REF ANY, delta: REAL] = { rr: REF REAL _ NARROW[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 [REAL _ C * 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 ANY _ NIL] = { 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: ROPE _ NARROW[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. RLichenReadExt.Mesa Last Edited by: Spreitzer, July 11, 1985 9:30:00 pm PDT ΚA– "cedar" style˜Icode™J™7K˜šΟk ˜ Kšœ œD˜SKšœFœœ)˜u—K˜šΠbx œœ˜KšœJœœ(˜K˜Kšœœœ+˜7K˜Kšœœœ ˜šœ œœ˜Kšœ œ˜Kšœœ<˜FKšœœœ˜—K˜KšœI˜IK˜Kšœœœ˜+šœœœ˜!K˜—K˜Kšœ œœ˜'šœœœ˜K˜KšœΟcœ ˜KšœŸ œ ˜!KšœŸ œ ˜ Kšœœœ˜Kšœ œ˜—K˜Kš œœœœœŸœ˜—K˜š  œœ?˜NKšœœœ ˜Kšœœ˜Kšœœ˜K˜!K˜ šœ˜ Kšœ˜ Kšœ7˜;—K˜K˜—K˜š œœ?˜LKšœœœ ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœ"˜&K˜$K˜$K˜K˜Kšœ ˜ š œœ,˜8K˜*K˜Kšœœœ˜ K˜Kš œœœœœ˜^Kš œ œœ6œœ˜mK˜—K˜[šœœ˜Kšœœœœ'˜OK˜ K˜ Kšœ ˜ Kšœœ˜K˜—Kšœ œ˜Kšœ˜Kšœ˜K˜K˜Kšœ œœœ˜@—K˜š œœ œ˜>Kšœœœ ˜K˜K˜Kšœœ˜K˜—K˜š   œœœ2œœ*˜™K˜-Kšœœ<˜MK˜ Kšœœ˜%šœœœ˜š œœœ˜ Kšœ-œ!˜RKšœP˜PKšœ˜—K˜ šœœ˜K˜Kš œœœœœœœ˜„Kšœ œ˜Kšœœ˜K˜Kš œ%œœœœœœ˜tK˜—šœœ˜K˜'K˜'Kšœœ˜—Kšœ˜K˜K˜—K˜ Kšœ:˜:K˜—K˜š œœœ˜&Kšœœ˜Kšœœ ˜+Kšœœ"˜AKšœœ"˜AK˜—K˜š œœ"œœ˜Wšœœ˜ Kšœœ ˜Kšœœ ˜Kšœœ˜Kšœœ ˜Kšœœ ˜Kšœœ˜ K˜—K˜—K˜Kšœ œœ ˜šœ œœ˜Kšœ œ˜Kšœœ˜Kšœœ˜—K˜š  œœœœœœœŸœ˜PK˜ —K˜š  œœ œœœ˜KKšœœ˜Kšœœ˜Kšœ4œœ˜BKšœ/œœ˜=Kšœ1œœ˜?Kšœ2˜2K˜—K˜š  œœ œœ˜@šœœ˜K˜ K˜ K˜Kšœœ˜——K˜š œœ?˜LKšœœœ ˜Kšœ œ˜Kšœœ˜Kšœ&˜&K˜ Kšœ˜KšœO˜Ošœœ˜Kšœœ˜$K˜ K˜ K˜ Kšœœ˜K˜—K˜K˜—K˜Kšœœœ œ˜4K˜šœ œœ˜šœ œ ˜K˜ Kš œœœœœ˜7Kšœ˜ ——K˜š  œœ œœ ˜4Kš œœœœœ˜K˜2Kšœ œœ˜5šœ˜Kšœœ˜.š œœ ˜Kšœœœ˜ K˜Kšœœœ˜ K˜Kšœœœ˜ Kšœ˜Kšœœœ˜ K˜—Kšœœ˜Kšœœ˜Kšœœ œœ˜K˜ Kšœ˜K˜—K˜—K˜š   œœœœœ Ÿœ˜Ošœœ˜Kšœ˜Kšœ ˜—K˜—K˜š   œœ/œ.œœ˜‘šœœ˜˜ Kšœœ+˜6Kšœœœ)˜9K˜—˜ Kšœœ˜#KšœAœœ˜KK˜Kš œœ œœœ˜*Kš œœ œœœ˜*˜Kšœœ˜Kšœ3œœœ#˜c—K˜šœœ˜K˜Kš œœœœ œ œ˜qKšœ˜Kšœ œ˜Kšœœ˜Kšœœ˜Kšœ7˜7K˜—K˜šœœœ˜+šœ œ˜Kšœœ˜$K˜K˜ K˜ K˜—K˜Kšœ˜—K˜—Kšœœ˜—K˜—K˜š  œœœœ œ˜0Kšœ œœ ˜(—K˜š œœœœ˜1šœœœ˜K˜šœ œ œ˜0Kšœ œ˜Kšœ œ˜Kšœ œ˜Kšœ œ˜Kšœ œ˜Kšœ œ ˜—Kšœœ˜—K˜—K˜š œœ œœœœœ˜>Kš œœœ œœ œ˜CK˜—K˜š  œœ œ˜BKšœœœ ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜K˜.K˜—K˜š  œœ?˜NKšœœœ ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜K˜&K˜&Kšœ1œœ˜7K˜—K˜Kšœœœœ˜0K˜š  œœ%œœ˜OKš œœœœœ ˜Kšœœ˜š œœœœ˜Kšœ œ˜Kšœœœ œ˜,K˜ —š  œœœœ˜7Kšœœ˜%K˜—š  œœœ)˜_Kšœœ˜%Kšœœ˜ Kšœ œ˜Kšœ˜šœœœ˜(Kšœœ˜K˜Kšœœœ˜K˜Kš œœœœœœ˜KKšœ˜—K˜—š œœœ˜-K˜#šœ˜˜Kšœœœ˜ K˜K˜—Kšœ œ˜Kšœœ˜—K˜—šœœ ˜Kšœœ(˜2šœœ˜Kšœœ˜˜Kšœ˜Kšœœœ˜Kšœœœ˜ K˜Kšœ,˜,šœœ˜Kšœœ˜˜Kšœœ˜ K˜Kšœ,˜,Kšœœœœ˜"K˜—Kšœœ˜—Kšœœ˜ K˜ šœœ˜Kšœœ˜ K˜ —K˜—Kšœœ˜Kšœœ˜Kšœœ˜šœ˜ K˜K˜ K˜K˜——Kšœ˜—K˜ K˜—K˜š   œœœœœ Ÿœ˜Pšœœ˜Kšœ˜Kšœ ˜—K˜—K˜š   œœ:œœœœ˜qK˜šœœœœ˜AKšœ œ˜!Kšœ œ˜!šœœœœ˜VKšœ@œœ˜FKšœ˜K˜—K˜—Kšœ˜Kšœ˜šœœ˜š œœœœ˜$š œœœœ˜$Kšœ!˜!Kšœ!˜!Kšœ(˜(Kšœ œœ˜Kšœ˜—Kšœ˜—K˜—šœ˜Kš œ3œœœœ˜K˜—K˜—K˜š œœœœ˜BK˜K˜—K˜š œœœ˜9Kšœœ ˜K˜—K˜š œœœ˜8šœ œœ˜Kšœ˜Kšœœœœ˜$K˜'šœ œ˜Kšœ3œ˜;KšœG˜GKšœœ˜—Kš œ œ œ œœ œ œ˜IKšœœœœ˜-K˜šœœœœœœœœœ˜Mšœ œ œ˜(Kšœ˜Kšœ'˜'Kšœœ˜—šœœœœœœœœœ˜MKšœœœ˜!Kšœœœ˜!Kšœ4˜4Kšœœ˜—Kšœœ˜—K˜—šœœ œ˜ K˜šœœ˜+Kšœ œ˜K˜ K˜—Kšœœ˜—K˜—K˜š œœœ˜7Kšœœ˜KšœœœO˜rKšœœ$˜/šœœœ˜šœœ˜Kšœœ8˜MKšœ˜KšœN˜NK˜ —K˜Kšœœ(˜0Kšœ.˜.Kšœ#˜#K˜—Kšœ˜K˜—K˜š œœ#œœ˜SK˜&K˜K˜—K˜š  œœ?˜OKšœœœ ˜Kšœ œ˜Kšœœ˜Kšœœ˜Kšœ+˜+š œœœœ˜#š œœœœ˜#Kšœ˜Kšœ œœ˜Kšœ˜—Kšœ˜—K˜—K˜š  œœœœœ˜:Kšœœœ ˜Kšœœœ ˜K˜K˜K˜—K˜š   œœœœ œ˜:Kšœœœœ˜*Kš œœœœœ˜GK˜K˜—K˜š œœ?˜LKšœœœ ˜Kšœœ˜Kšœœ˜Kšœœ˜K˜)K˜)šœœ˜š œœœœ˜$š œœœœ˜$Kšœ!˜!Kšœ!˜!˜K˜šœ˜K˜K˜Kšœœœ˜—K˜—Kšœ˜—Kšœ˜—K˜—šœ˜Kš œ3œœœœ˜K˜—K˜—K˜š œœ œœCœœœ˜~Kšœ œ%˜4Kšœ˜—K˜š  œœœœœœŸœ˜PKšœ œ˜,—K˜š  œœ œœœŸœ˜cJšœœœ˜Jšœœ˜Kšœ˜—K˜š œœ˜K˜Kšœ%˜%Kšœ!˜!K˜K˜K˜Kšœ˜K˜K˜K˜Kšœ˜Kšœ.œG˜xKšœ0œG˜zKšœ˜—K˜K˜K˜Kšœ˜——…—[²{E