<> <> <> <> <> <> <> <> <> DIRECTORY AMTypes USING [TV, TVEqual, TVType, UnderClass], AMBridge USING [SomeRefFromTV, TVForFrame, TVForReferent, TVToRef], AMModel USING [Context], AMModelBridge USING [ContextForFrame], CD, CDBasics, CDCells, CDDirectory, CDImports, CDLayers, CDProperties, CDRects, CDSatellites, CDSequencer, CDSymbolicObjects, CDTexts, Convert, Core, CoreClasses, CoreOps, CoreProperties, CoreGeometry, IO, Interpreter USING [Evaluate], PrincOpsUtils, PW, RefTab, Rope, RopeList, Sinix, Sisyph, SymTab, TerminalIO; SisyphImpl: CEDAR PROGRAM IMPORTS AMBridge, AMModelBridge, AMTypes, CDBasics, CDCells, CDDirectory, CDImports, CDLayers, CDProperties, CDRects, CDSatellites, CDSequencer, CDTexts, Convert, CoreClasses, CoreOps, CoreProperties, CoreGeometry, Interpreter, IO, PrincOpsUtils, PW, RefTab, Rope, RopeList, Sinix, SymTab, TerminalIO EXPORTS Sisyph SHARES CDCells, CDImports, CDRects, CDTexts, Sinix = BEGIN OPEN Sisyph; <> expressionsProp: PUBLIC ATOM _ PW.RegisterProp[$SisyphExpressions, TRUE]; designRope: PRIVATE ROPE _ "design"; <> globalNamesRope: PRIVATE ROPE _ "globalNames"; <> corePropsRope: PUBLIC ROPE _ "coreProps"; coreInstPropsRope: PUBLIC ROPE _ "coreInstProps"; cdObjRope: PRIVATE ROPE _ "cdObj"; <> localVariablesRopes: ROPES = LIST ["&", "&&", corePropsRope, coreInstPropsRope, cdObjRope, "cI", "wI", "wire"]; parmNamesProp: PUBLIC ATOM _ PW.RegisterProp[$SisyphParmNames, TRUE]; defaultGlobalNames: PUBLIC ROPES _ LIST ["Vdd", "Gnd", "RosemaryLogicTime"]; mode: PUBLIC Sinix.Mode _ NEW [Sinix.ModeRec _ [ extractProcProp: PW.RegisterProp[$SisyphExtractProc, TRUE], decoration: CoreGeometry.CreateDecoration["Sisyph"], instanceEqualProc: InstanceEqual, objectEqualProc: ObjectEqual, instanceLayer: Sinix.DefaultInstanceLayer, userData: DefaultUserData, fusionByName: schematics, touchProc: Touch, nameProc: Name ]]; <> ResultFor: PROC [cx: Context, obj: CD.Object, properties: CD.PropList] RETURNS [result: REF _ NIL] = { codeFor: ROPE _ NARROW [CDProperties.GetListProp[properties, $CodeFor]]; iconFor: ROPE _ NARROW [CDProperties.GetListProp[properties, $IconFor]]; IF codeFor=NIL THEN codeFor _ NARROW [CDProperties.GetObjectProp[obj, $CodeFor]]; IF iconFor=NIL THEN iconFor _ NARROW [CDProperties.GetObjectProp[obj, $IconFor]]; SELECT TRUE FROM codeFor#NIL AND iconFor#NIL => ERROR; -- that's one two many! codeFor#NIL => { result _ EvalToRef[cx, codeFor]; IF result#NIL THEN WITH result SELECT FROM ct: CellType => {}; w: Wire => {}; w: Wires => {}; ENDCASE => ERROR; }; iconFor#NIL => result _ ES[iconFor, cx]; ENDCASE => ERROR; -- one of them at least should be present! }; ExtractCellIcon: PUBLIC Sinix.ExtractProc = { cx: Context _ EvaluateParameters[userData, obj, properties]; iconCT: CellType _ NARROW [Sinix.ExtractCell[obj, mode, NIL, cx].result]; iconName: ROPE _ Name[obj, cx]; cellType: CellType; name: ROPE; result _ ResultFor[cx, obj, properties]; IF result=NIL THEN RETURN; cellType _ NARROW [result]; name _ CoreOps.GetCellTypeName[cellType]; IF name=NIL THEN name _ CDNameToCTName[iconName, ".icon"]; cellType _ Sinix.CreateIcon[cellType: cellType, name: name]; result _ cellType; CoreGeometry.PutObject[mode.decoration, cellType, obj]; <> IF NOT CheckAndDecorate[iconName, obj, iconCT.public, cellType.public, GetGlobalNames[cx]] THEN { TerminalIO.PutF["*** Error: icon public and schematic public for cell icon %g do NOT conform\n", IO.rope[iconName]]; TerminalIO.PutF["Icon public is:"]; CoreOps.PrintWire[wire: iconCT.public, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\nSchematic public is:"]; CoreOps.PrintWire[wire: cellType.public, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\n"]; ERROR }; cellType.properties _ PutCoreProps[cellType.properties, GetCoreProps[cx]]; props _ GetCoreInstProps[cx]; }; ExtractNamedWireIcon: PUBLIC Sinix.ExtractProc = { cx: Context _ EvaluateParameters[userData, obj, properties]; iconCT: CellType _ NARROW [Sinix.ExtractCell[obj, mode, NIL, cx].result]; iconName: ROPE = Name[obj, cx]; resultWire: WireSeq; result _ ResultFor[cx, obj, properties]; IF result=NIL THEN {result _ resultWire _ iconCT.public; RETURN} ELSE WITH result SELECT FROM wires: Wires => { result _ resultWire _ CoreOps.CreateWire[wires]; resultWire.properties _ PutCoreProps[resultWire.properties, GetCoreProps[cx]]; }; ww: Wire => {result _ ww; resultWire _ CoreOps.CreateWire[LIST [ww]]}; cellType: CellType => result _ resultWire _ CoreOps.CopyWire[cellType.public]; ENDCASE => ERROR; <> SELECT TRUE FROM iconCT.public.size=1 AND resultWire.size=1 => { <> result _ resultWire _ resultWire[0]; CoreGeometry.PutIndirectLazyPins[mode.decoration, resultWire, iconCT.public[0]]; }; CheckAndDecorate[iconName, obj, iconCT.public, resultWire] => {}; ENDCASE => { TerminalIO.PutF["*** Error: icon wire and result wire for wire icon %g don't conform\n", IO.rope[iconName]]; TerminalIO.PutF["Icon wire is:"]; CoreOps.PrintWire[wire: iconCT.public, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\nResult wire is:"]; CoreOps.PrintWire[wire: resultWire, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\n"]; ERROR }; props _ GetCoreInstProps[cx]; }; ExtractUnNamedWireIcon: PUBLIC Sinix.ExtractProc = { FlushName: CoreOps.EachWireProc = {[] _ CoreOps.SetShortWireName[wire, NIL]}; wire: Wire; [result, props] _ ExtractNamedWireIcon[obj, mode, properties, userData]; wire _ NARROW [result]; [] _ CoreOps.VisitWire[wire, FlushName]; }; ExtractWire: Sinix.ExtractProc = { wire: Wire; cx: Context; resultVar, resultExpr: ROPE; IF obj.class#CDRects.bareRectClass THEN ERROR; IF obj.layer#CD.commentLayer THEN ERROR; <> <> <> [cx, resultVar, resultExpr] _ OldEvaluateParameters[userData, obj, properties, IsResultVar]; IF resultVar=NIL THEN wire _ CoreOps.CreateWire[] ELSE { EvalExpr[cx, resultVar, resultExpr, FALSE]; wire _ NARROW [GetRef[cx, "wire"]]; TerminalIO.PutF["*** Old Syntax: 'wire _%g'. Sisyph might not be able to cope with that in near future!\n", IO.rope[resultExpr]]; }; CoreGeometry.PutPins[mode.decoration, wire, LIST [[obj]]]; wire.properties _ PutCoreProps[wire.properties, GetCoreInstProps[cx]]; result _ wire; }; <<>> ExtractImport: Sinix.ExtractProc = { cx: Context = NARROW [userData]; design: CD.Design _ GetDesign[cx]; import: CDImports.ImportSpecific = NARROW [obj.specific]; CDSequencer.CheckAborted[design]; IF import.boundOb=NIL OR import.boundDesign=NIL THEN { IF NOT CDImports.LoadAndBindDesign[into: design, importeeName: import.designName, allowConflicts: interactive, useCache: TRUE] THEN {TerminalIO.PutF["*** Error: Cannot load import %g[%g] which is unbound.\n", IO.rope[import.objectName], IO.rope[import.designName]]; ERROR}; IF import.boundOb=NIL OR import.boundDesign=NIL THEN {TerminalIO.PutF["*** Error: Cannot bind import %g[%g].\n", IO.rope[import.objectName], IO.rope[import.designName]]; ERROR}; }; RETURN Sinix.Extract[obj: import.boundOb, mode: mode, properties: properties, userData: Create[import.boundDesign, cx]]; }; ES, ExtractSchematicByName: PUBLIC PROC [name: ROPE, cx: Context] RETURNS [CellType] = { design: CD.Design = GetDesign[cx]; obj: CD.Object = CDDirectory.Fetch[design, name].object; IF obj=NIL THEN {TerminalIO.PutF["*** Error: ES cannot find object '%g' in design '%g'.\n", IO.rope[name], IO.rope[design.name]]; ERROR}; RETURN [NARROW [Sinix.Extract[obj: obj, mode: mode, properties: NIL, userData: cx].result]]; }; <> Create: PUBLIC PROC [design: CD.Design, previousCx: Context _ NIL] RETURNS [cx: Context] = { EvalDesignExprs: PROC [exprs: ROPES] = { WHILE exprs#NIL DO expr: ROPE _ exprs.first; tokenKind1, tokenKind2: IO.TokenKind; token1, token2, rest: ROPE; [tokenKind1, token1, rest] _ ParseRope[expr]; [tokenKind2, token2, rest] _ ParseRope[rest]; SELECT TRUE FROM tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '_] => EvalExpr[cx, token1, rest]; tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '~] => EvalExpr[cx, token1, rest, FALSE]; ENDCASE => { TerminalIO.PutF["*** Old syntax in design satellite or expression: Side effect in '%g'.\n", IO.rope[expr]]; Eval[cx, expr]; }; exprs _ exprs.rest; ENDLOOP; }; cx _ IF previousCx=NIL THEN SymTab.Create[11] ELSE Copy[previousCx]; Store[cx, designRope, NEW [CD.Design _ design]]; Insert[cx, globalNamesRope, NEW [ROPES _ defaultGlobalNames]]; EvalDesignExprs[NARROW [CDProperties.GetDesignProp[design, expressionsProp]]]; EvalDesignExprs[CDSatellites.GetSatelliteRopes[design]]; }; <> <> <> <<[] _ SymTab.Store[cx, key, AMTypes.Copy[val]]; >> <<};>> <> <<[] _ SymTab.Pairs[oldCx, CopyItem];>> <> <> <> <<};>> <<>> Copy: PUBLIC PROC [oldCx: Context] RETURNS [cx: Context] = { <> <<[] _ SymTab.Store[cx, key, AMTypes.Copy[val]]; >> <<};>> <> <<[] _ SymTab.Pairs[oldCx, CopyItem];>> cx _ SymTab.Copy[oldCx]; -- JMF: copy the table, no more necessary to copy TV's Store[cx, corePropsRope, NEW [Properties _ NIL]]; -- and erase some standard variables Store[cx, coreInstPropsRope, NEW [Properties _ NIL]]; Store[cx, cdObjRope, NEW [CD.Object _ NIL]]; }; Store: PUBLIC PROC [cx: Context, var: ROPE, value: REF _ NIL] = { [] _ SymTab.Store[cx, var, TVFromRef[value]]; }; Insert: PUBLIC PROC [cx: Context, var: ROPE, value: REF _ NIL] = { [] _ SymTab.Insert[cx, var, TVFromRef[value]]; }; FetchInt: PUBLIC PROC [cx: Context, var: ROPE] RETURNS [found: BOOL _ FALSE, value: INT] = { val: SymTab.Val _ SymTab.Fetch[cx, var].val; IF val=NIL THEN RETURN; WITH RefFromTV[val] SELECT FROM refInt: REF INT => RETURN [TRUE, refInt^]; refNat: REF NAT => RETURN [TRUE, INT[refNat^]]; ENDCASE => ERROR; -- Wrong type }; FetchAtom: PUBLIC PROC [cx: Context, var: ROPE] RETURNS [found: BOOL _ FALSE, value: ATOM] = { val: SymTab.Val _ SymTab.Fetch[cx, var].val; IF val=NIL THEN RETURN; RETURN [TRUE, NARROW [RefFromTV[val]]]; }; FetchRope: PUBLIC PROC [cx: Context, var: ROPE] RETURNS [found: BOOL _ FALSE, value: ROPE] = { val: SymTab.Val _ SymTab.Fetch[cx, var].val; IF val=NIL THEN RETURN; WITH RefFromTV[val] SELECT FROM rope: ROPE => RETURN [TRUE, rope]; text: REF TEXT => RETURN [TRUE, Rope.FromRefText[text]]; ENDCASE => ERROR; -- Wrong type }; EvalToTV: PROC [cx: Context, expr: ROPE] RETURNS [result: AMTypes.TV, errorRope: ROPE, noResult: BOOL] = TRUSTED { [result, errorRope, noResult] _ Interpreter.Evaluate[ rope: expr, context: AMModelBridge.ContextForFrame[ AMBridge.TVForFrame[PrincOpsUtils.GetReturnFrame[]] ], symbolsList: LIST [cx] ]; }; EvalToRef: PUBLIC PROC [cx: Context, expr: ROPE] RETURNS [result: REF] = TRUSTED { tv: AMTypes.TV; errorRope: ROPE; noResult: BOOL; [tv, errorRope, noResult] _ EvalToTV[cx, expr]; SELECT TRUE FROM errorRope#NIL => SIGNAL InterpreterError[cx, NIL, expr, errorRope]; noResult => SIGNAL InterpreterError[cx, NIL, expr, "No Result"]; ENDCASE => result _ RefFromTV[tv]; }; EvalExpr : PUBLIC PROC [cx: Context, var, expr: ROPE, checkDefined: BOOL _ TRUE] = { result: AMTypes.TV; errorRope: ROPE; noResult: BOOL; [result, errorRope, noResult] _ EvalToTV[cx, expr]; SELECT TRUE FROM errorRope#NIL => SIGNAL InterpreterError[cx, var, expr, errorRope]; noResult => SIGNAL InterpreterError[cx, var, expr, "No Result"]; Rope.Fetch[var]='& OR NOT checkDefined => [] _ SymTab.Store[cx, var, result]; ENDCASE => IF SymTab.Store[cx, var, result] THEN SIGNAL InterpreterError[cx, var, expr, "Variable has not been previously declared (with a Sisyph.Store)"]; }; AddProp: PUBLIC PROC [cx: Context, key: ATOM, expr: ROPE, inst: BOOL] = { AddPropInternal[cx, key, EvalToRef[cx, expr], inst]; }; <<>> AddPropInternal: PROC [cx: Context, key: ATOM, value: REF, inst: BOOL] = { previousProps: Properties _ (IF inst THEN GetCoreInstProps ELSE GetCoreProps)[cx]; Store[cx, IF inst THEN coreInstPropsRope ELSE corePropsRope, NEW [Properties _ CoreProperties.PutProp[previousProps, key, value]]]; }; Eval: PRIVATE PROC [cx: Context, expr: ROPE] = { <> <> <> <> <> <<], >> <> <<]};>> result: AMTypes.TV; errorRope: ROPE; noResult: BOOL; -- JMF TRUSTED {[result, errorRope, noResult] _ Interpreter.Evaluate[ rope: expr, context: AMModelBridge.ContextForFrame[ AMBridge.TVForFrame[PrincOpsUtils.GetReturnFrame[]] ], symbolsList: LIST [cx] ]}; IF errorRope=NIL THEN RETURN; SIGNAL InterpreterError[cx, NIL, expr, errorRope]; }; <> <> <> <> <> <> <> <> <> <> <> <<[found, bVal] _ SymTab.Fetch[b, key];>> <> <<};>> <> <<};>> <> <<};>> <<>> ContextEqual: PROC [cx1, cx2: Context, parmNames: ROPES] RETURNS [BOOL] = { -- JMF <> < no parameters at all>> IsSubset: PROC [a, b: Context] RETURNS [BOOL] = { <> CheckAbsentInb: SymTab.EachPairAction = { found: BOOL; bVal: SymTab.Val; IF val=NIL THEN RETURN [FALSE]; -- value is in fact not in a ... <> IF RopeList.Memb[localVariablesRopes, key] THEN RETURN [FALSE]; <> [found, bVal] _ SymTab.Fetch[b, key]; quit _ NOT found OR bVal=NIL OR NOT TVEqual[bVal, val]; }; RETURN [NOT SymTab.Pairs[a, CheckAbsentInb]]; }; SELECT TRUE FROM cx1=cx2 => RETURN [TRUE]; -- for sure... parmNames=NIL => RETURN [IsSubset[cx1, cx2] AND IsSubset[cx2, cx1]]; -- most general case parmNames.rest=NIL AND Rope.Equal[parmNames.first, "0"] => RETURN [TRUE]; -- no parameters ENDCASE => { -- limited parameter list, compare only those found1: BOOL; val1: SymTab.Val; found2: BOOL; val2: SymTab.Val; FOR keys: ROPES _ parmNames, keys.rest UNTIL keys=NIL DO [found1, val1] _ SymTab.Fetch[cx1, keys.first]; [found2, val2] _ SymTab.Fetch[cx2, keys.first]; found1 _ found1 AND val1#NIL; -- TV's are not supposed to be NIL ... found2 _ found2 AND val2#NIL; IF found1#found2 THEN RETURN[FALSE]; -- present in only one table IF found1 AND NOT TVEqual[val1, val2] THEN RETURN[FALSE]; --values differ ENDLOOP; RETURN [TRUE]; -- all parameters matched }; }; InstanceEqual: PROC [obj: CD.Object, p1: CD.PropList, ud1: REF, p2: CD.PropList, ud2: REF] RETURNS [BOOL] = { instArgs1: ROPES _ NARROW [CDProperties.GetListProp[p1, expressionsProp]]; satArgs1: ROPES _ NARROW [CDProperties.GetListProp[p1, Sinix.satellitesProp]]; extract1: ATOM _ NARROW [CDProperties.GetListProp[p1, mode.extractProcProp]]; instArgs2: ROPES _ NARROW [CDProperties.GetListProp[p2, expressionsProp]]; satArgs2: ROPES _ NARROW [CDProperties.GetListProp[p2, Sinix.satellitesProp]]; extract2: ATOM _ NARROW [CDProperties.GetListProp[p2, mode.extractProcProp]]; parmNames: ROPES _ NARROW [CDProperties.GetObjectProp[obj, parmNamesProp]]; IF extract1#extract2 THEN RETURN [FALSE]; IF NOT EqualRopes[instArgs1, instArgs2] OR NOT EqualRopes[satArgs1, satArgs2] THEN RETURN [FALSE]; IF ForceExtractRope[instArgs2] OR ForceExtractRope[satArgs2] THEN RETURN [FALSE]; <> IF parmNames#NIL AND Rope.Equal[parmNames.first, "0"] THEN RETURN [TRUE]; RETURN [ContextEqual[NARROW [ud1], NARROW [ud2], NIL]]; }; ObjectEqual: PROC [obj: CD.Object, ud1: REF, ud2: REF] RETURNS [BOOL] = { parmNames: ROPES _ NARROW [CDProperties.GetObjectProp[obj, parmNamesProp]]; IF parmNames#NIL AND Rope.Equal[parmNames.first, "0"] THEN RETURN [TRUE]; RETURN [ContextEqual[NARROW [ud1], NARROW [ud2], parmNames]]; }; <> ForceExtractRope: PROC [ropes: ROPES] RETURNS [BOOL] = { FOR r: ROPES _ ropes, r.rest WHILE r#NIL DO IF Rope.Equal["t~", Rope.Substr[r.first,0,2]] THEN RETURN [TRUE]; ENDLOOP; RETURN [FALSE]; }; EqualRopes: PUBLIC PROC [ropes1, ropes2: ROPES] RETURNS [BOOL] = { FOR r1: ROPES _ ropes1, r1.rest WHILE r1#NIL DO IF NOT RopeList.Memb[ropes2, r1.first] THEN RETURN [FALSE]; ENDLOOP; FOR r2: ROPES _ ropes2, r2.rest WHILE r2#NIL DO IF NOT RopeList.Memb[ropes1, r2.first] THEN RETURN [FALSE]; ENDLOOP; RETURN [TRUE]; }; Cons: PUBLIC PROC [r: ROPE, lor: ROPES] RETURNS [ROPES] = { RETURN [CONS [r, lor]]; }; List: PUBLIC PROC [r1, r2, r3, r4, r5, r6: ROPE _ NIL] RETURNS [lor: ROPES _ NIL] = { IF r6#NIL THEN lor _ CONS [r6, lor]; IF r5#NIL THEN lor _ CONS [r5, lor]; IF r4#NIL THEN lor _ CONS [r4, lor]; IF r3#NIL THEN lor _ CONS [r3, lor]; IF r2#NIL THEN lor _ CONS [r2, lor]; IF r1#NIL THEN lor _ CONS [r1, lor]; }; <> CheckAndDecorate: PROC [iconName: ROPE, icon: CD.Object, drawnPublic, resultPublic: WireSeq, globalNames: ROPES _ NIL] RETURNS [ok: BOOL _ TRUE] = { resultToDrawn: RefTab.Ref _ RefTab.Create[]; -- associates resultPublic to drawnPublic <> FOR i: NAT IN [0 .. drawnPublic.size) DO EachResultWire: CoreOps.EachWireProc = { resultName: ROPE _ CoreOps.GetShortWireName[wire]; IF NOT Rope.Equal[resultName, drawnName] THEN RETURN; IF wire=resultWire THEN RETURN; IF resultWire#NIL THEN {TerminalIO.PutF["*** Cell %g: Drawn Icon has a wire %g whose name appears more than once in the schematic\n", IO.rope[iconName], IO.rope[drawnName]]; quit _ TRUE; ok _ FALSE; RETURN}; resultWire _ wire; }; drawnWire: Wire _ drawnPublic[i]; drawnName: ROPE _ CoreOps.GetShortWireName[drawnWire]; resultWire: Wire _ NIL; IF drawnName=NIL THEN {TerminalIO.PutF["*** Cell %g: Drawn Icon has an unnamed wire\n", IO.rope[iconName]]; ok _ FALSE; LOOP}; IF CoreOps.VisitWire[resultPublic, EachResultWire] THEN LOOP; IF resultWire=NIL THEN {TerminalIO.PutF["*** Cell %g: Drawn Icon has wire %g that doesn't correspond to any wire in the schematic\n", IO.rope[iconName], IO.rope[drawnName]]; ok _ FALSE; LOOP}; <> CoreGeometry.PutIndirectLazyPins[mode.decoration, resultWire, drawnWire]; [] _ RefTab.Store[resultToDrawn, resultWire, drawnWire]; ENDLOOP; <> FOR i: NAT IN [0 .. resultPublic.size) DO resultWire: Wire _ resultPublic[i]; resultName: ROPE _ CoreOps.GetShortWireName[resultWire]; drawnWire: Wire _ NARROW [RefTab.Fetch[resultToDrawn, resultWire].val]; IF resultName=NIL THEN LOOP; IF drawnWire#NIL THEN LOOP; IF RopeList.Memb[globalNames, resultName] THEN LOOP; TerminalIO.PutF["*** Warning in Cell %g: schematic has wire %g that corresponds to no wire in the drawn Icon\n", IO.rope[iconName], IO.rope[resultName]]; ENDLOOP; }; <> <> <> <> <> <> <<};>> <> <> <> <<};>> <> <> <> <> <> <> <> <<};>> <> <> <> <<};>> <> <> <> <> <> <<};>> <> <> <<};>> <> <> <> <<[] _ CoreOps.VisitBindingSeq[rct[i].actual, rct[i].type.public, FindGlobals];>> <> <<[] _ CoreOps.VisitWireSeq[rct.internal, FindWire];>> <> <> <> <> <> <> <> <> <> <> <> <<};>> <<>> ProcessGlobalName: PROC [record: CellType, name: ROPE] = { -- JMF <> <> <<- globals _ list of wires in internal/public to be identified with global `name'>> <> <<- if there is a single such wire, it has the right name and is public, then we're done>> <<- define the 1st elem of globals to be the new single wire representing `name'>> <<- cleanup public, internal and 1st level actuals>> <<- public and internal may change size (extra copies of the global are removed, global is forced to be public)>> <<- 1st level actuals cannot change sizes>> <<- merge properties of all other representative of global into it>> globals: Wires; ReplaceSeq: PROC [old: WireSeq] ~ { FOR i: NAT IN [0 .. old.size) DO old[i] _ Replace[old[i]] ENDLOOP; }; Replace: PROC [old: Wire] RETURNS [new: Wire] = { new _ old; -- presumably ... IF old.size#0 THEN FOR i: NAT IN [0 .. old.size) DO new[i] _ Replace[old[i]] ENDLOOP ELSE IF CoreOps.Member[globals, old] THEN new _ global; }; ReplaceAndCleanSeq: PROC [old: WireSeq] RETURNS [new: WireSeq] = { news: Wires _ LIST [global]; FOR i: NAT IN [0 .. old.size) DO new _ Replace[old[i]]; IF NOT CoreOps.Member[news, new] THEN news _ CONS [new, news]; ENDLOOP; new _ CoreOps.CreateWire[news]; }; InsertGlobal: PROC [wire: Wire] = { IF wire.size#0 THEN SIGNAL GlobalNonAtomic[record, name, wire]; IF NOT CoreOps.Member[globals, wire] THEN globals _ CONS [wire, globals]; }; FindGlobals: CoreOps.EachWirePairProc = { publicName: ROPE = CoreOps.GetShortWireName[publicWire]; IF Rope.Equal[publicName, name] THEN { -- a sub global candidate actualName: ROPE = CoreOps.GetShortWireName[actualWire]; IF actualName=NIL OR Rope.Equal[actualName, name] THEN InsertGlobal[actualWire]; }; }; FindWire: CoreOps.EachWireProc = { IF Rope.Equal[CoreOps.GetShortWireName[wire], name] THEN InsertGlobal[wire]; }; rct: CoreClasses.RecordCellType = NARROW [record.data]; global: Wire; FOR i: NAT IN [0..rct.size) DO [] _ CoreOps.VisitBindingSeq[rct[i].actual, rct[i].type.public, FindGlobals]; ENDLOOP; [] _ CoreOps.VisitWireSeq[rct.internal, FindWire]; IF globals=NIL THEN RETURN; IF globals.rest=NIL AND Rope.Equal[CoreOps.GetShortWireName[globals.first], name] AND CoreOps.RecursiveMember[record.public, globals.first] THEN RETURN; -- all right already, nothing to do! global _ CoreOps.SetShortWireName[globals.first, name]; globals _ globals.rest; record.public _ ReplaceAndCleanSeq[record.public]; rct.internal _ ReplaceAndCleanSeq[rct.internal]; FOR i: NAT IN [0..rct.size) DO ReplaceSeq[rct[i].actual] ENDLOOP; WHILE globals#NIL DO Sinix.FuseProperties[mode, globals.first, global, CoreOps.GetCellTypeName[record]]; globals _ globals.rest; ENDLOOP; }; Name: PROC [obj: CD.Object, userData: REF] RETURNS [ROPE] = { cx: Context _ NARROW [userData]; RETURN [CDDirectory.Name[obj, GetDesign[cx]]]; }; Touch: CoreGeometry.TouchProc = { IF instance1.obj.class#CDRects.bareRectClass OR instance2.obj.class#CDRects.bareRectClass THEN ERROR; -- the only thing we know is Rectangles! IF ~SilTouchRect[CoreGeometry.InlineBBox[instance1], CoreGeometry.InlineBBox[instance2]] THEN RETURN; <> RETURN [CDLayers.AbstractToPaint[instance1.obj.layer]=CDLayers.AbstractToPaint[instance2.obj.layer]]; }; SilTouchRect: PROC [r1, r2: CD.Rect] RETURNS [BOOL] = INLINE { Intersect: PROC [i1min, i1max, i2min, i2max: CD.Number] RETURNS [BOOL] = INLINE { RETURN [(i1max >= i2min) AND (i2max >= i1min)]; }; Adjoin: PROC [i1min, i1max, i2min, i2max: CD.Number] RETURNS [BOOL] = INLINE { RETURN [(i2min >= i1min AND i2min <= i1max AND i2max >= i1max) OR (i1min >= i2min AND i1min <= i2max AND i1max >= i2max)]; }; RETURN [(Intersect[r1.x1, r1.x2, r2.x1, r2.x2] AND Adjoin[r1.y1, r1.y2, r2.y1, r2.y2]) OR (Intersect[r1.y1, r1.y2, r2.y1, r2.y2] AND Adjoin[r1.x1, r1.x2, r2.x1, r2.x2]) OR CDBasics.Inside[r1, r2] OR CDBasics.Inside[r2, r1]] }; GetRef: PROC [cx: Context, var: ROPE] RETURNS [ref: REF] = { val: SymTab.Val _ SymTab.Fetch[cx, var].val; IF val=NIL THEN ERROR; ref _ RefFromTV[val]; }; GetCDObj: PUBLIC PROC [cx: Context] RETURNS [CD.Object] = { RETURN [NARROW [GetRef[cx, cdObjRope]]] }; GetCoreProps: PUBLIC PROC [cx: Context] RETURNS [Properties] = { RETURN [NARROW [GetRef[cx, corePropsRope]]] }; GetCoreInstProps: PUBLIC PROC [cx: Context] RETURNS [Properties] = { RETURN [NARROW [GetRef[cx, coreInstPropsRope]]] }; GetDesign: PUBLIC PROC [cx: Context] RETURNS [CD.Design] = { RETURN [NARROW [GetRef[cx, designRope]]] }; GetGlobalNames: PUBLIC PROC [cx: Context] RETURNS [ROPES] = { RETURN [NARROW [GetRef[cx, globalNamesRope]]] }; RefFromTV: PROC [tv: REF] RETURNS [REF] = { IF tv=NIL THEN RETURN [NIL]; IF ~ISTYPE [tv, AMTypes.TV] THEN ERROR; TRUSTED {RETURN [SELECT AMTypes.UnderClass[AMTypes.TVType[tv]] FROM nil, atom, rope, list, ref => AMBridge.TVToRef[tv], ENDCASE => AMBridge.SomeRefFromTV[tv]]}; }; TVFromRef: PROC [ref: REF] RETURNS [AMTypes.TV] = TRUSTED { RETURN [AMBridge.TVForReferent[ref]]; }; TVEqual: PROC [tv1, tv2: REF] RETURNS [BOOL] = { -- JMF <> IF AMTypes.TVEqual[tv1, tv2] THEN RETURN [TRUE]; WITH RefFromTV[tv1] SELECT FROM -- manage standard types not covered by AMTypes rr1: ROPES => WITH RefFromTV[tv2] SELECT FROM rr2: ROPES => RETURN [EqualRopes[rr1, rr2]]; ENDCASE => RETURN [FALSE]; r1: ROPE => WITH RefFromTV[tv2] SELECT FROM -- JMF r2: ROPE => RETURN [Rope.Equal[r1, r2]]; -- JMF ENDCASE => RETURN [FALSE]; -- JMF <> ENDCASE => RETURN [FALSE]; }; PutCoreProps: PROC [onto, from: Properties] RETURNS [new: Properties] = { PutProp: PROC [prop: ATOM, val: REF ANY] = { new _ CoreProperties.PutProp[new, prop, val]; }; new _ onto; CoreProperties.Enumerate[from, PutProp]; }; StripCellTypeName: PROC [cellType: CellType, dropPart: ROPE] = { [] _ CoreOps.SetCellTypeName[cellType, CDNameToCTName[CoreOps.GetCellTypeName[cellType], dropPart]]; }; CDNameToCTName: PROC [cdName, dropPart: ROPE] RETURNS [ctName: ROPE] = { ctName _ Rope.Substr[cdName, 0, Rope.Index[cdName, 0, dropPart]]; }; DefaultUserData: PROC [design: CD.Design] RETURNS [REF] ~ { RETURN [Create[design]]; }; <> ParseRope: PUBLIC PROC [rope: ROPE] RETURNS [tokenKind: IO.TokenKind, token, rest: ROPE] = { ENABLE { IO.Error => GOTO Error; IO.EndOfStream => GOTO EOF; }; stream: IO.STREAM _ IO.RIS[rope]; charsSkipped1: INT _ IO.SkipWhitespace[stream]; ampersand: BOOL _ IO.PeekChar[stream]='&; charsSkipped2: INT; IF ampersand THEN {[] _ IO.GetChar[stream]; charsSkipped1 _ charsSkipped1 + 1}; [tokenKind, token, charsSkipped2] _ IO.GetCedarTokenRope[stream]; rest _ Rope.Substr[rope, charsSkipped1+charsSkipped2+Rope.Length[token]]; IF ampersand THEN { IF tokenKind=tokenID THEN token _ Rope.Cat["&", token] ELSE GOTO Error; TerminalIO.PutF["*** Variable name starting with &: %g.\n", IO.rope[token]]; }; EXITS Error => RETURN [tokenERROR, NIL, NIL]; EOF => RETURN [tokenEOF, NIL, NIL]; }; IsParsedID: PUBLIC PROC [tokenKind: IO.TokenKind, token, id: ROPE] RETURNS [BOOL] = { RETURN [tokenKind=tokenID AND Rope.Equal[token, id]]; }; IsParsedChar: PUBLIC PROC [tokenKind: IO.TokenKind, token: ROPE, char: CHAR] RETURNS [BOOL] = { RETURN [tokenKind=tokenSINGLE AND Rope.Fetch[token]=char]; }; EvaluateParameters: PUBLIC PROC [userData: REF, obj: CD.Object, properties: CD.PropList] RETURNS [cx: Context] = { EvalExprs: PROC [exprs: ROPES, inst: BOOL] = { WHILE exprs#NIL DO expr: ROPE _ exprs.first; tokenKind1, tokenKind2: IO.TokenKind; token1, token2, rest: ROPE; [tokenKind1, token1, rest] _ ParseRope[expr]; [tokenKind2, token2, rest] _ ParseRope[rest]; SELECT TRUE FROM tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '_] => EvalExpr[cx, token1, rest]; tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, ':] => AddProp[cx, Convert.AtomFromRope[token1], rest, inst]; tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '~] => EvalExpr[cx, token1, rest, FALSE]; Rope.Find[expr, "_"]>=0 OR Rope.Find[expr, ":"]>=0=> { TerminalIO.PutF["*** Old syntax in %g: Side effect in '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[expr]]; Eval[cx, expr]; }; ENDCASE => { previousName: ROPE _ NARROW [CoreProperties.GetProp[(IF inst THEN GetCoreInstProps ELSE GetCoreProps)[cx], CoreOps.nameProp]]; IF previousName#NIL AND NOT Rope.Equal[previousName, expr] THEN { TerminalIO.PutF["*** Error in object '%g': Conflicting names '%g' and '%g' [probably two satellites].\n", IO.rope[Name[obj, cx]], IO.rope[previousName], IO.rope[expr]]; ERROR; }; IF Rope.Find[expr, " "]>=0 THEN TerminalIO.PutF["*** Warning in %g: name contains space '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[expr]]; AddPropInternal[cx, CoreOps.nameProp, expr, inst]; }; exprs _ exprs.rest; ENDLOOP; }; cx _ Copy[NARROW [userData]]; Store[cx, cdObjRope, NEW [CD.Object _ obj]]; CDSequencer.CheckAborted[GetDesign[cx]]; EvalExprs[NARROW [CDProperties.GetObjectProp[obj, expressionsProp]], FALSE]; EvalExprs[NARROW [CDProperties.GetObjectProp[obj, Sinix.satellitesProp]], FALSE]; EvalExprs[NARROW [CDProperties.GetListProp[properties, expressionsProp]], TRUE]; EvalExprs[NARROW [CDProperties.GetListProp[properties, Sinix.satellitesProp]], TRUE]; }; ProcessGlobalNames: PUBLIC PROC [record: CellType, cx: Context] = { FOR names: ROPES _ GetGlobalNames[cx], names.rest WHILE names#NIL DO ProcessGlobalName[record, names.first]; ENDLOOP; }; <> <> <> ExtractSchematic: PRIVATE Sinix.ExtractProc = { cx: Context; resultVar, resultExpr: ROPE; [cx, resultVar, resultExpr] _ OldEvaluateParameters[userData, obj, properties, IsResultVar]; SELECT TRUE FROM Rope.Equal[resultVar, "cI"] => { cellType: CellType; EvalExpr[cx, resultVar, resultExpr, FALSE]; cellType _ ExtractCellIconInternal[obj, cx]; TerminalIO.PutF["*** Old syntax for cell icon in %g: '%g _%g'. Convert!\n", IO.rope[Name[obj, userData]], IO.rope[resultVar], IO.rope[resultExpr]]; cellType.properties _ PutCoreProps[cellType.properties, GetCoreProps[cx]]; result _ cellType; props _ GetCoreInstProps[cx]; }; Rope.Equal[resultVar, "wI"] => { wire: Wire; EvalExpr[cx, resultVar, resultExpr, FALSE]; wire _ ExtractNamedWireIconInternal[obj, cx]; TerminalIO.PutF["*** Old syntax for named wire icon in %g: '%g _%g'. Convert!\n", IO.rope[Name[obj, userData]], IO.rope[resultVar], IO.rope[resultExpr]]; wire.properties _ PutCoreProps[wire.properties, GetCoreProps[cx]]; result _ wire; props _ GetCoreInstProps[cx]; }; Rope.Equal[resultVar, "wire"] => ERROR; ENDCASE => { cellType: CellType; <> result _ Sinix.ExtractCell[obj, mode, properties, cx].result; cellType _ NARROW [result]; ProcessGlobalNames[cellType, cx]; cellType.properties _ PutCoreProps[cellType.properties, GetCoreProps[cx]]; StripCellTypeName[cellType, ".sch"]; props _ GetCoreInstProps[cx]; }; }; <> ExtractCellIconInternal: PROC [icon: CD.Object, cx: Context] RETURNS [cellType: CellType] = { iconName: ROPE = Name[icon, cx]; iconCT: CellType _ NARROW [Sinix.ExtractCell[icon, mode, NIL, cx].result]; <> cellType _ NARROW [GetRef[cx, "cI"]]; IF cellType=NIL THEN { cellType _ CoreOps.CreateCellType[class: CoreClasses.unspecifiedCellClass, public: iconCT.public, name: CDNameToCTName[iconName, ".icon"]]; } ELSE { name: ROPE _ CoreOps.GetCellTypeName[cellType]; IF name=NIL THEN name _ CDNameToCTName[iconName, ".icon"]; cellType _ Sinix.CreateIcon[cellType: cellType, name: name]; }; CoreGeometry.PutObject[mode.decoration, cellType, icon]; <> IF NOT CheckAndDecorate[iconName, icon, iconCT.public, cellType.public, GetGlobalNames[cx]] THEN { TerminalIO.PutF["*** Error: icon public and schematic public for cell icon %g do NOT conform\n", IO.rope[iconName]]; TerminalIO.PutF["Icon public is:"]; CoreOps.PrintWire[wire: iconCT.public, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\nSchematic public is:"]; CoreOps.PrintWire[wire: cellType.public, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\n"]; ERROR } }; <> ExtractNamedWireIconInternal: PROC [icon: CD.Object, cx: Context] RETURNS [result: Wire] = { iconName: ROPE = Name[icon, cx]; iconCT: CellType _ NARROW [Sinix.ExtractCell[icon, mode, NIL, cx].result]; result _ NARROW [GetRef[cx, "wI"]]; IF result=NIL THEN ERROR; <<>> <> IF iconCT.public.size=1 THEN { <> CoreGeometry.PutPins[mode.decoration, result, CoreGeometry.GetPins[mode.decoration, iconCT.public[0]]]; RETURN; }; IF ~CheckAndDecorate[iconName, icon, iconCT.public, CoreOps.CreateWire[LIST [result]]] THEN { TerminalIO.PutF["*** Error: icon wire and result wire for wire icon %g don't conform\n", IO.rope[iconName]]; TerminalIO.PutF["Icon wire is:"]; CoreOps.PrintWire[wire: iconCT.public, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\nResult wire is:"]; CoreOps.PrintWire[wire: result, out: TerminalIO.TOS[], level: LAST [NAT]]; TerminalIO.PutF["\n"]; ERROR } }; IsResultVarProc: TYPE = PROC [var: ROPE] RETURNS [BOOL]; <> << >> IsResultVar: IsResultVarProc = { RETURN [Rope.Equal[var, "cI"] OR Rope.Equal[var, "wI"] OR Rope.Equal[var, "wire"]]; }; OldEvaluateParameters: PROC [userData: REF, obj: CD.Object, properties: CD.PropList, isResultVar: IsResultVarProc _ NIL] RETURNS [cx: Context, resultVar, resultExpr: ROPE _ NIL] = { EvalExprs: PROC [exprs: ROPES, inst: BOOL] = { tempResultVar, tempResultExpr: ROPE _ NIL; WHILE exprs#NIL DO expr: ROPE _ exprs.first; tokenKind1, tokenKind2: IO.TokenKind; token1, token2, rest: ROPE; [tokenKind1, token1, rest] _ ParseRope[expr]; [tokenKind2, token2, rest] _ ParseRope[rest]; SELECT TRUE FROM tokenKind1=tokenID AND isResultVar#NIL AND isResultVar[token1] => { IF tempResultVar#NIL THEN {TerminalIO.PutF["*** Error: multiple result expressions encountered: '%g' and '%g'.\n", IO.rope[expr], IO.rope[tempResultVar]]; ERROR}; <> IF NOT IsParsedChar[tokenKind2, token2, '_] AND NOT IsParsedChar[tokenKind2, token2, ':] THEN {TerminalIO.PutF["*** Error: result expression has wrong syntax: '%g'.\n", IO.rope[expr]]; ERROR}; tempResultVar _ token1; tempResultExpr _ rest; }; inst AND IsParsedID[tokenKind1, token1, "name"] AND IsParsedChar[tokenKind2, token2, '_] => { tokenKind: IO.TokenKind; token, rr: ROPE; [tokenKind, token, rr] _ ParseRope[rest]; IF tokenKind=tokenROPE THEN TerminalIO.PutF["*** Old syntax in %g: Use an expression or a satellite %g instead of '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[token], IO.rope[expr]] ELSE TerminalIO.PutF["*** Old syntax in %g: Use 'CoreName: %g' instead of '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[rest], IO.rope[expr]]; AddProp[cx, CoreOps.nameProp, rest, inst]; }; tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '_] => EvalExpr[cx, token1, rest]; tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, ':] => AddProp[cx, Convert.AtomFromRope[token1], rest, inst]; tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '~] => EvalExpr[cx, token1, rest, FALSE]; Rope.Find[expr, "_"]>=0 OR Rope.Find[expr, ":"]>=0=> { TerminalIO.PutF["*** Old syntax in %g: Side effect in '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[expr]]; Eval[cx, expr]; }; ENDCASE => { previousName: ROPE _ NARROW [CoreProperties.GetProp[(IF inst THEN GetCoreInstProps ELSE GetCoreProps)[cx], CoreOps.nameProp]]; IF previousName#NIL AND NOT Rope.Equal[previousName, expr] THEN { TerminalIO.PutF["*** Error in object '%g': Conflicting names '%g' and '%g' [probably two satellites].\n", IO.rope[Name[obj, cx]], IO.rope[previousName], IO.rope[expr]]; ERROR; }; IF Rope.Find[expr, " "]>=0 THEN TerminalIO.PutF["*** Warning in %g: name contains space '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[expr]]; AddPropInternal[cx, CoreOps.nameProp, expr, inst]; }; exprs _ exprs.rest; ENDLOOP; IF tempResultVar#NIL THEN {resultVar _ tempResultVar; resultExpr _ tempResultExpr}; }; cx _ Copy[NARROW [userData]]; Store[cx, cdObjRope, NEW [CD.Object _ obj]]; CDSequencer.CheckAborted[GetDesign[cx]]; EvalExprs[NARROW [CDProperties.GetObjectProp[obj, expressionsProp]], FALSE]; EvalExprs[NARROW [CDProperties.GetObjectProp[obj, Sinix.satellitesProp]], FALSE]; EvalExprs[NARROW [CDProperties.GetListProp[properties, expressionsProp]], TRUE]; EvalExprs[NARROW [CDProperties.GetListProp[properties, Sinix.satellitesProp]], TRUE]; }; <> GlobalNonAtomic: PUBLIC SIGNAL [record: CellType, name: ROPE, wire: Wire] = CODE; InterpreterError: PUBLIC SIGNAL [cx: Context, var, expr, errorRope: ROPE] = CODE; <> Sinix.RegisterExtractProc[$SisyphExtractSchematic, ExtractSchematic]; Sinix.RegisterExtractProc[$SisyphExtractCellIcon, ExtractCellIcon]; Sinix.RegisterExtractProc[$SisyphExtractNamedWireIcon, ExtractNamedWireIcon]; Sinix.RegisterExtractProc[$SisyphExtractUnNamedWireIcon, ExtractUnNamedWireIcon]; Sinix.RegisterExtractProc[$SisyphExtractWire, ExtractWire]; Sinix.RegisterExtractProc[$SisyphExtractImport, ExtractImport]; CDProperties.PutProp[CDCells.pCellClass, mode.extractProcProp, $SisyphExtractSchematic]; CDProperties.PutProp[CDRects.bareRectClass, mode.extractProcProp, $SisyphExtractWire]; CDProperties.PutProp[CDTexts.rigidTextClass, mode.extractProcProp, $ExtractNull]; CDProperties.PutProp[CDTexts.flipTextClass, mode.extractProcProp, $ExtractNull]; CDProperties.PutProp[CDImports.importsClass, mode.extractProcProp, $SisyphExtractImport]; END. <<>>