DIRECTORY Parquet, ParquetInternal, AlignmentMarks USING [Mark, FindList, MakeMarkAptr], CheckMarks USING [FindList, MakeCheckAptr], StretchLines, Stretch USING [Direction, DoStretch], TerminalIO USING [WriteRope, WriteInt], ExprRead, TileSetExpressions USING [GetParams], CD, CDApplications USING [NewApplicationI, BoundingRectI], CDRects USING [CreateBareRect], CDDirectory USING [Fetch, Include, Another], CDBasics USING [AddPoints, SubPoints, MinPoint, MaxPoint, AddSize], CDOrient USING [IncludesOddRot90, MapPoint, DeMapRect, InverseOrient, ComposeOrient, OrientedSize], CDCells USING [CreateEmptyCell, RemoveApplication], CDProperties USING [PutPropOnApplication, GetPropFromObject, CopyProps], CDImports USING [GetReference, ReferencePtr], CDImportsExtras USING [OneLevelIncludedCopy], Rope USING [ROPE, Concat], PrincOpsUtils USING [BITAND], AMBridge USING [SomeRefFromTV], AMTypes USING [TypedVariable, TV], Interpreter USING [Evaluate], SymTab USING [Ref, Create, Fetch, Store, Pairs, EachPairAction]; ParquetImplA: CEDAR PROGRAM IMPORTS Parquet, ParquetInternal, AlignmentMarks, CheckMarks, Stretch, ExprRead, TileSetExpressions, TerminalIO, CDDirectory, CDImportsExtras, CDBasics, Rope, CDApplications, CDRects, CDOrient, CDCells, CDProperties, CDImports, SymTab, StretchLines, Interpreter, AMBridge EXPORTS Parquet, ParquetInternal SHARES CDDirectory = BEGIN OPEN Parquet, ParquetInternal; HighPosO: PROC [aptr: CD.ApplicationPtr] RETURNS [CD.DesignPosition] = INLINE {RETURN [CDBasics.AddSize[aptr.location, CDOrient.OrientedSize[aptr.ob.size, aptr.orientation]]]}; Error: PUBLIC ERROR [ec: ErrorCode] = CODE; errorSize: INT = 20; MirrorY: PUBLIC Orientation _ ComposeOrient[ComposeOrient[Rotate270, MirrorX], Rotate90]; InverseOrient: PUBLIC PROC [orient: Orientation] RETURNS [inverse: Orientation] ~ BEGIN RETURN[CDOrient.InverseOrient[orient]]; END; ComposeOrient: PUBLIC PROC [first, second: Orientation] RETURNS [Orientation] ~ BEGIN RETURN[CDOrient.ComposeOrient[first, second]]; END; ShiftedCellIncludeApplication: PROC [shifted: ShiftedCell, aptr: CD.ApplicationPtr] = BEGIN shifted.llCorner _ CDBasics.MinPoint[shifted.llCorner, aptr.location]; shifted.urCorner _ CDBasics.MaxPoint[shifted.urCorner, HighPosO[aptr]]; shifted.contents _ CONS[aptr, shifted.contents]; END; AddCheck: PROC [mod: Mod, pos: CD.Position] = BEGIN hash: INT; IF mod.checkTable = NIL THEN mod.checkTable _ NEW[VerficationTableRec]; hash _ ABS[(pos.y * 10021 + pos.x) MOD verificationTableSize]; FOR pm: PlacedCheckList _ mod.checkTable[hash], pm.rest WHILE pm # NIL DO IF pos.x = pm.first.pos.x AND pos.y = pm.first.pos.y THEN { pm.first.duplicate _ TRUE; RETURN; }; ENDLOOP; mod.checkTable[hash] _ CONS[[FALSE, pos], mod.checkTable[hash]]; END; Owner: PROC [ob: CD.ObPtr] RETURNS [REF ANY] = BEGIN RETURN[CDProperties.GetPropFromObject[ob, $Owner]]; END; CheckValid: PUBLIC PROC[module: Module] RETURNS [Mod] = BEGIN IF module = NIL OR ~module.valid OR ~ISTYPE[module.data, Mod] THEN ERROR Error[InvalidModule]; RETURN[NARROW[module.data]]; END; DerefCell: PROC [obj: CD.ObPtr] RETURNS [CD.ObPtr] = BEGIN IF obj = NIL THEN RETURN[NIL]; SELECT obj.p.objectType FROM $Cell => RETURN [obj]; $Import => { rp: CDImports.ReferencePtr ~ NARROW[obj.specificRef]; IF rp.boundApp = NIL THEN { ERROR; -- import should be bound, if not something is wrong } ELSE RETURN [rp.boundApp.ob]; }; ENDCASE => ERROR; END; DoExpand: PROC [ob: CD.ObPtr, design: CD.Design, level: CD.Level, place, min, max: INT, dir: StretchLines.LineDirections, amount: INT] RETURNS [Rope.ROPE] = BEGIN cell: CD.CellPtr _ NARROW[ob.specificRef]; FOR a: CD.ApplicationList _ cell.contents, a.rest WHILE a # NIL DO ap: CD.ApplicationPtr _ a.first; urPos: CD.DesignPosition _ HighPosO[a.first]; llPos: CD.DesignPosition _ a.first.location; IF ap.ob.level # level THEN LOOP; IF ((dir = $up OR dir = $down) AND llPos.y <= place AND urPos.y >= place AND llPos.x <= max AND urPos.x >= min) OR ((dir = $left OR dir = $right) AND llPos.x <= place AND urPos.x >= place AND llPos.y <= max AND urPos.y >= min) THEN { msg: Rope.ROPE; newOb: CD.ObPtr; lower, upper: INT; newDir: Stretch.Direction; newPlace: INT; rect, mapRect: CD.Rect; IF dir = $up OR dir = $right THEN { -- left is left side of stretch mark lower _ place - 1; upper _ place + 1; } ELSE { lower _ place + 1; upper _ place - 1; -- stretch mark is upside down }; IF dir = $left OR dir = $right THEN rect _ [x1: lower, x2: upper, y1: 0, y2: 0] ELSE rect _ [x1: 0, x2: 0, y1: lower, y2: upper]; mapRect _ CDOrient.DeMapRect[rect, ap.ob.size, ap.orientation, ap.location]; IF mapRect.x1 = mapRect.x2 THEN { newPlace _ (mapRect.y1 + mapRect.y2) / 2; IF mapRect.y1 < mapRect.y2 THEN newDir _ $up ELSE newDir _ $down; } ELSE { newPlace _ (mapRect.x1 + mapRect.x2) / 2; IF mapRect.x1 < mapRect.x2 THEN newDir _ $right ELSE newDir _ $left; }; [newOb, msg] _ Stretch.DoStretch[ap.ob, design, newPlace, newDir, amount]; IF newOb = NIL THEN RETURN[msg]; ap.ob _ newOb; SELECT dir FROM $down => ap.location.y _ ap.location.y - amount; $left => ap.location.x _ ap.location.x - amount; ENDCASE; }; ENDLOOP; RETURN[NIL]; END; CopyCellTree: PROC [oldOb: CD.ObPtr, design: CD.Design] RETURNS [CD.ObPtr] = BEGIN oldCrec: CD.CellPtr ~ NARROW[oldOb.specificRef]; newOb: CD.ObPtr _ NEW[CD.ObjectDefinition _ oldOb^]; newCrec: CD.CellPtr _ NEW[CD.CellRecord _ oldCrec^]; newOb.specificRef _ newCrec; newOb.properties _ CDProperties.CopyProps[oldOb.properties]; newCrec.contents _ NIL; FOR a: CD.ApplicationList _ oldCrec.contents, a.rest UNTIL a = NIL DO ap: CD.ApplicationPtr _ NEW[CD.Application _ a.first^]; ap.properties _ CDProperties.CopyProps[a.first.properties]; IF ap.ob.p.objectType = $Cell THEN ap.ob _ CopyCellTree[ap.ob, design]; newCrec.contents _ CONS[ap, newCrec.contents]; ENDLOOP; IF design # NIL AND ~CDDirectory.Include[design, newOb] THEN ERROR; RETURN[newOb]; END; InstantiateCell: PROC [design: CD.Design, ob: CD.ObPtr, symbols: SymTab.Ref] RETURNS[CD.ObPtr] = BEGIN AddDefaultParameters: PROC [tab: SymTab.Ref] = BEGIN ExprRead.StoreInt[tab, "SizeX", ob.size.x/l]; ExprRead.StoreInt[tab, "SizeY", ob.size.x/l]; END; EvalIntegerExpr: PROC [expr: Rope.ROPE, tab: SymTab.Ref] RETURNS [INT, Rope.ROPE] = BEGIN none: BOOL; msg: Rope.ROPE _ NIL; value: INT _ 0; tv: AMTypes.TypedVariable; [tv, msg, none] _ Interpreter.Evaluate[rope: expr, symTab: tab]; IF none AND msg = NIL THEN msg _ "Expression does not return a value."; IF msg = NIL THEN { ref: REF ANY; TRUSTED {ref _ AMBridge.SomeRefFromTV[tv];}; WITH ref SELECT FROM i: REF INT => value _ i^; ENDCASE => msg _ "Expression did not return an integer."; }; RETURN[value, msg]; END; stretchedOb, derefOb: CD.ObPtr; alist: CD.ApplicationList; copied: BOOL _ FALSE; passType: StretchLines.LineTypes; cellName: Rope.ROPE; IF ob.p.objectType # $Cell AND ob.p.objectType # $Import THEN ERROR; stretchedOb _ ob; cellName _ NARROW[DerefCell[ob].specificRef, CD.CellPtr].name; IF symbols = NIL THEN symbols _ SymTab.Create[]; AddDefaultParameters[symbols]; FOR pass: INT IN [0..1] DO IF pass = 0 THEN passType _ pointed ELSE passType _ blunt; derefOb _ DerefCell[stretchedOb]; alist _ NARROW[derefOb.specificRef, CD.CellPtr].contents; WHILE alist # NIL DO derefOb _ DerefCell[stretchedOb]; FOR alist _ NARROW[derefOb.specificRef, CD.CellPtr].contents, alist.rest UNTIL (alist = NIL OR (alist.first.ob.p.objectType = StretchLines.objAtom AND StretchLines.AptrToLine[alist.first].type = passType)) DO NULL; ENDLOOP; IF alist # NIL -- alist.first.ob.p.objectType = StretchLines.objAtom -- THEN { min, place, amount: INT; evalError: Rope.ROPE; line: REF StretchLines.LineData; IF ~copied THEN { SELECT stretchedOb.p.objectType FROM $Cell => stretchedOb _ CDDirectory.Another[stretchedOb, design, design]; $Import => stretchedOb _ CDImportsExtras.OneLevelIncludedCopy[stretchedOb, design]; ENDCASE => ERROR; IF stretchedOb.p.objectType # $Cell THEN ERROR; copied _ TRUE; LOOP; }; line _ StretchLines.AptrToLine[alist.first]; IF line.type # passType THEN ERROR; SELECT line.direction FROM up => { min _ line.point.x; place _ line.point.y; }; down => { min _ line.point.x; place _ line.point.y; }; left => { min _ line.point.y; place _ line.point.x; }; right => { min _ line.point.y; place _ line.point.x; }; ENDCASE => ERROR; [amount, evalError] _ EvalIntegerExpr[expr: line.label, tab: symbols]; IF CDCells.RemoveApplication[design, stretchedOb, alist.first].removed = NIL THEN ERROR; IF evalError # NIL THEN { TerminalIO.WriteRope["Could not evaluate stretch amount '"]; TerminalIO.WriteRope[line.label]; TerminalIO.WriteRope["' for cell '"]; TerminalIO.WriteRope[cellName]; TerminalIO.WriteRope["', stretch line ignored.\n"]; TerminalIO.WriteRope["Error was '"]; TerminalIO.WriteRope[evalError]; TerminalIO.WriteRope["'.\n"]; } ELSE { IF line.type = pointed THEN { new: CD.ObPtr; msg: Rope.ROPE; [new, msg] _ Stretch.DoStretch[stretchedOb, design, place, line.direction, amount * l]; IF new = NIL THEN { TerminalIO.WriteRope["Could not stretch cell '"]; TerminalIO.WriteRope[cellName]; TerminalIO.WriteRope["' by amount '"]; TerminalIO.WriteRope[line.label]; TerminalIO.WriteRope["', error was '"]; TerminalIO.WriteRope[msg]; TerminalIO.WriteRope["'\n"]; } ELSE stretchedOb _ new; } ELSE { msg: Rope.ROPE; TerminalIO.WriteRope["Expand amount"]; TerminalIO.WriteInt[amount]; TerminalIO.WriteRope[" in cell '"]; TerminalIO.WriteRope[cellName]; TerminalIO.WriteRope["'.\n"]; msg _ DoExpand[stretchedOb, design, line.level, place, min, min + line.length, line.direction, amount * l]; IF msg # NIL THEN { TerminalIO.WriteRope["Could not expand part of cell '"]; TerminalIO.WriteRope[cellName]; TerminalIO.WriteRope["' by amount '"]; TerminalIO.WriteRope[line.label]; TerminalIO.WriteRope["', error was '"]; TerminalIO.WriteRope[msg]; TerminalIO.WriteRope["'\n"]; } }; } }; ENDLOOP; ENDLOOP; RETURN[stretchedOb]; END; CellIntoTile: PROC [design: CD.Design, obj: CD.ObPtr, fast: BOOL _ FALSE, parameters: SymTab.Ref _ NIL, moduleWithDefaultMarks: Mod _ NIL] RETURNS [Tile] = BEGIN tile: Tile _ NEW[TileRec]; IF ~fast THEN obj _ InstantiateCell[design, obj, parameters]; tile.obj _ obj; IF ~fast THEN { deref: CD.ObPtr _ DerefCell[obj]; FOR ml: LIST OF AlignmentMarks.Mark _ AlignmentMarks.FindList[deref], ml.rest WHILE ml#NIL DO mark: Mark _ NEW[MarkRec]; mark.name _ ml.first.name; mark.pos _ ml.first.pos; StoreMark[tile, mark]; ENDLOOP; FOR cl: LIST OF CD.Position _ CheckMarks.FindList[deref], cl.rest WHILE cl#NIL DO tile.checkList _ CONS[cl.first, tile.checkList]; ENDLOOP; }; DefaultMarks[tile, moduleWithDefaultMarks]; RETURN[tile] END; CombineParameters: PUBLIC PROC [context: Context, generatorParameters: SymTab.Ref] = BEGIN IF context = NIL THEN ERROR Error[BadArgs]; context.parameters _ ExprRead.CombineTabs[context.parameters, generatorParameters]; IF context.tiles # NIL THEN context.parameters _ ExprRead.CombineTabs[TileSetExpressions.GetParams[context.tiles], context.parameters] END; InstantiateTile: PUBLIC PROC [context: Context, cellName: Rope.ROPE] RETURNS [Tile] = BEGIN obj: CD.ObPtr; found: BOOL; IF context.tiles = NIL THEN ERROR Error[NoSuchTileSet]; IF context.eventualOwner = context.tiles THEN { [found, obj] _ CDDirectory.Fetch[context.eventualOwner, cellName]; IF ~found THEN RETURN[NIL]; } ELSE { [found, obj] _ CDDirectory.Fetch[context.tiles, cellName]; IF ~found THEN RETURN[NIL]; obj _ CDImports.GetReference[context.eventualOwner, cellName, context.tiles.name]; }; IF obj = NIL THEN RETURN[NIL]; RETURN[CellIntoTile[context.eventualOwner, obj, FALSE, context.parameters]] END; NewModule: PUBLIC PROC [context: Context] RETURNS [Module, PlacedTile] = BEGIN pc: PlacedTile _ NEW[PlacedTileRec]; module: Module _ NEW[ModuleRec]; mod: Mod _ NEW[ModRec]; mod.current _ mod.topCell _ NEW[ShiftedCellRec]; mod.eventualOwner _ context.eventualOwner; module.data _ mod; module.valid _ TRUE; pc.pos _ [0, 0]; pc.tile _ NEW[TileRec]; pc.tile.obj _ NEW[CD.ObjectDefinition _ [p: NIL, size: [0, 0]]]; DefaultMarks[pc.tile]; pc.owner _ module; RETURN[module, pc]; END; ShiftedCellIntoCell: PROC [design: CD.Design, shifted: ShiftedCell, name: Rope.ROPE _ "UnnamedParquetCell", applicationsPerScreenDot: INT _ -1] RETURNS [CD.ObPtr, CD.Position] = BEGIN obj: CD.ObPtr _ CDCells.CreateEmptyCell[]; cell: CD.CellPtr; oldLL: CD.Position; numAps: INT _ 0; cell _ NARROW[obj.specificRef]; FOR sc: LIST OF ShiftedCell _ shifted.children, sc.rest WHILE sc # NIL DO ap: CD.ApplicationPtr _ NEW[CD.Application]; [ap.ob, ap.location] _ ShiftedCellIntoCell[design, sc.first, sc.first.name, applicationsPerScreenDot]; ap.orientation _ CD.original; ap.properties _ NIL; ShiftedCellIncludeApplication[shifted, ap]; IF applicationsPerScreenDot > 0 THEN TerminalIO.WriteRope["c"]; ENDLOOP; oldLL _ shifted.llCorner; FOR w: CD.ApplicationList _ shifted.contents, w.rest WHILE w#NIL DO w.first.location _ CDBasics.SubPoints[w.first.location, shifted.llCorner]; w.first.selected _ FALSE; numAps _ numAps + 1; IF applicationsPerScreenDot > 0 AND numAps MOD applicationsPerScreenDot = 0 THEN TerminalIO.WriteRope["."]; ENDLOOP; shifted.urCorner _ CDBasics.SubPoints[shifted.urCorner, shifted.llCorner]; shifted.llCorner _ [0, 0]; obj.size _ shifted.urCorner; cell.contents _ shifted.contents; cell.name _ name; cell.ir _ CDApplications.BoundingRectI[cell.contents]; IF design # NIL AND ~CDDirectory.Include[design, obj, name] THEN ERROR; RETURN[obj, oldLL]; END; ModuleIntoCell: PUBLIC PROC [module: Module, name: Rope.ROPE _ NIL, applicationsPerScreenDot: INT _ -1] RETURNS [CD.ObPtr] = BEGIN mod: Mod _ CheckValid[module]; oldLL: CD.Position; obj: CD.ObPtr; FixOrphans: SymTab.EachPairAction -- [key: Key, val: Val] RETURNS [quit: BOOL] -- = BEGIN sCell: ShiftedCell _ NARROW[val]; IF sCell.parent = NIL THEN { sCell.parent _ mod.topCell; mod.topCell.children _ CONS[sCell, mod.topCell.children]; }; RETURN[FALSE]; END; IF mod.cellTab # NIL THEN [] _ SymTab.Pairs[mod.cellTab, FixOrphans]; [obj, oldLL] _ ShiftedCellIntoCell[mod.eventualOwner, mod.topCell, name, applicationsPerScreenDot]; -- trashes mod.topCell IF mod.ul # NIL THEN mod.ul^ _ CDBasics.SubPoints[mod.ul^, oldLL]; IF mod.ur # NIL THEN mod.ur^ _ CDBasics.SubPoints[mod.ur^, oldLL]; IF mod.ll # NIL THEN mod.ll^ _ CDBasics.SubPoints[mod.ll^, oldLL]; IF mod.lr # NIL THEN mod.lr^ _ CDBasics.SubPoints[mod.lr^, oldLL]; IF mod.top # NIL THEN mod.top^ _ CDBasics.SubPoints[mod.top^, oldLL]; IF mod.bottom # NIL THEN mod.bottom^ _ CDBasics.SubPoints[mod.bottom^, oldLL]; IF mod.left # NIL THEN mod.left^ _ CDBasics.SubPoints[mod.left^, oldLL]; IF mod.right # NIL THEN mod.right^ _ CDBasics.SubPoints[mod.right^, oldLL]; module.valid _ FALSE; mod.topCell _ NIL; mod.current _ NIL; mod.cellTab _ NIL; mod.checkTable _ NIL; RETURN[obj]; END; ModuleIntoTile: PUBLIC PROC [module: Module, name: Rope.ROPE, context: Context, fast: BOOL, bbox: BOOL _ FALSE] RETURNS [numErrors: INT, tile: Tile] = BEGIN mod: Mod _ CheckValid[module]; obj: CD.ObPtr; IF ~fast THEN numErrors _ CheckModule[module] ELSE numErrors _ 0; IF bbox THEN mod.top _ mod.bottom _ mod.left _ mod.right _ mod.ul _ mod.ur _ mod.ll _ mod.lr _ NIL; obj _ ModuleIntoCell[module, name]; tile _ CellIntoTile[mod.eventualOwner, obj, fast, context.parameters, mod]; tile.inheritedErrors _ numErrors; RETURN[numErrors, tile]; END; AdjacentTile: PUBLIC PROC [oldTile: PlacedTile, newTile: Tile, dir: Direction, orient: Orientation] RETURNS [PlacedTile] = BEGIN l1, r1, t1, b1, l2, r2, t2, b2: Mark; mark1, mark2: Mark; [l1, r1, t1, b1, , , , ] _ OrientStdMark[oldTile.tile, oldTile.orient]; [l2, r2, t2, b2, , , , ] _ OrientStdMark[newTile, orient]; SELECT dir FROM above => BEGIN mark1 _ t1; mark2 _ b2 END; below => BEGIN mark1 _ b1; mark2 _ t2 END; leftOf => BEGIN mark1 _ l1; mark2 _ r2 END; rightOf => BEGIN mark1 _ r1; mark2 _ l2 END; ENDCASE; RETURN[AlignTile[oldTile, mark1, newTile, mark2, orient]]; END; AdjacentTileCorners: PUBLIC PROC [oldTile: PlacedTile, newTile: Tile, dir: Direction, orient: Orientation] RETURNS [PlacedTile] = BEGIN ul1, lr1, ll1, ul2, lr2, ll2: Mark; mark1, mark2: Mark; [ul: ul1, lr: lr1, ll: ll1] _ OrientStdMark[oldTile.tile, oldTile.orient]; [ul: ul2, lr: lr2, ll: ll2] _ OrientStdMark[newTile, orient]; SELECT dir FROM above => BEGIN mark1 _ ul1; mark2 _ ll2 END; below => BEGIN mark1 _ ll1; mark2 _ ul2 END; leftOf => BEGIN mark1 _ ll1; mark2 _ lr2 END; rightOf => BEGIN mark1 _ lr1; mark2 _ ll2 END; ENDCASE; RETURN[AlignTile[oldTile, mark1, newTile, mark2, orient]]; END; PlacedTileLoc: PUBLIC PROC [tile: PlacedTile] RETURNS [xmin, ymin, xmax, ymax: INT] = BEGIN mappedSize: CD.Position; mappedSize _ CDOrient.OrientedSize[tile.tile.obj.size, tile.orient]; RETURN[tile.pos.x, tile.pos.y, tile.pos.x + mappedSize.x, tile.pos.y + mappedSize.y]; END; AlignTile: PUBLIC PROC [oldTile: PlacedTile, oldMark: Mark, newTile: Tile, newMark: Mark, orient: Orientation _ CD.original] RETURNS [PlacedTile] = BEGIN pos: Position; pos _ CDBasics.SubPoints[PlacedMarkLoc[oldTile, oldMark], MapPoint[newMark.pos, newTile.obj.size, orient]]; RETURN[PlaceTile[into: oldTile.owner, tile: newTile, lowerLeftCorner: pos, orient: orient]]; END; AlignMark: PUBLIC PROC [oldTile: PlacedTile, oldMark: Mark, newMarkName: Rope.ROPE] = BEGIN PlaceMark[oldTile.owner, newMarkName, PlacedMarkLoc[oldTile, oldMark]]; END; BlockFor: PROC [mod: Mod, blockName: Rope.ROPE] RETURNS [ShiftedCell] = BEGIN found: BOOL _ FALSE; ref: REF ANY; cell: ShiftedCell; IF blockName = NIL THEN { IF mod.topCell = NIL THEN ERROR; RETURN[mod.topCell]; }; IF mod.cellTab = NIL THEN mod.cellTab _ SymTab.Create[13]; [found, ref] _ SymTab.Fetch[mod.cellTab, blockName]; IF found THEN { cell _ NARROW[ref]; RETURN[cell]; } ELSE { cell _ NEW[ShiftedCellRec]; cell.name _ blockName; IF ~SymTab.Store[mod.cellTab, blockName, cell] THEN ERROR; RETURN[cell]; }; END; SwitchBlock: PUBLIC PROC [module: Module, blockName: Rope.ROPE] = BEGIN mod: Mod _ CheckValid[module]; mod.current _ BlockFor[mod, blockName]; END; GetCurrentBlock: PUBLIC PROC [module: Module] RETURNS [Rope.ROPE] = BEGIN mod: Mod _ CheckValid[module]; RETURN[mod.current.name]; END; NestBlock: PUBLIC PROC [module: Module, child, parent: Rope.ROPE] RETURNS [done: BOOL] = BEGIN mod: Mod _ CheckValid[module]; par, chi: ShiftedCell; chi _ BlockFor[mod, child]; par _ BlockFor[mod, parent]; IF chi.parent # NIL THEN RETURN[FALSE]; -- already nested FOR b: ShiftedCell _ par, par.parent WHILE b # NIL DO IF b = chi THEN RETURN[FALSE]; -- would create loop in hierarchy ENDLOOP; chi.parent _ par; par.children _ CONS[chi, par.children]; RETURN[TRUE]; END; VerTabProc: TYPE = PROC [pc: PlacedCheck] RETURNS [quit: BOOL _ FALSE]; EnumVerTab: PROC [verTab: VerficationTable, proc: VerTabProc] RETURNS [BOOL] ~ BEGIN IF verTab = NIL THEN RETURN[FALSE]; FOR i: INT IN [0..verificationTableSize) DO FOR c: PlacedCheckList _ verTab[i], c.rest WHILE c # NIL DO IF proc[c.first] THEN RETURN[TRUE]; ENDLOOP; ENDLOOP; RETURN[FALSE]; END; CheckModule: PUBLIC PROC [module: Module] RETURNS [INT] = BEGIN mod: Mod _ CheckValid[module]; errors: INT _ 0; PaintErrorRect: PROCEDURE [mod: Mod, pos: Position] = BEGIN appl: CD.ApplicationPtr _ CDApplications.NewApplicationI[ ob: CDRects.CreateBareRect[[errorSize, errorSize], CD.highLightError], location: [pos.x - errorSize / 2, pos.y - errorSize / 2], orientation: IdentityOrient]; CDProperties.PutPropOnApplication[onto: appl, prop: $SignalName, val: Rope.Concat["Parquet Check-", "Mark MisAlignment"]]; -- don't pass a constant rope because they are really of type Text and ChipNDale can't copy those properly ShiftedCellIncludeApplication[mod.topCell, appl]; END; CheckMatched: VerTabProc -- PROC [pc: PlacedCheck] RETURNS [quit: BOOL _ FALSE] -- = BEGIN IF ~pc.duplicate THEN BEGIN errors _ errors + 1; PaintErrorRect[mod, pc.pos]; END; END; [] _ EnumVerTab[mod.checkTable, CheckMatched]; RETURN[errors + mod.inheritedErrors]; END; PlaceTile: PUBLIC PROC [into: Module, tile: Tile, lowerLeftCorner: Position, orient: Orientation _ CD.original] RETURNS [PlacedTile] = BEGIN mod: Mod _ CheckValid[into]; pc: PlacedTile _ NEW[PlacedTileRec]; ap: CD.ApplicationPtr _ NEW[CD.Application]; pc.owner _ into; pc.tile _ tile; pc.orient _ orient; pc.pos _ lowerLeftCorner; ap.ob _ tile.obj; ap.location _ lowerLeftCorner; ap.orientation _ orient; ShiftedCellIncludeApplication[mod.current, ap]; mod.inheritedErrors _ mod.inheritedErrors + tile.inheritedErrors; FOR m: MarkList _ tile.exportMarks, m.rest WHILE m # NIL DO pos: CD.Position; pos _ CDBasics.AddPoints[lowerLeftCorner, CDOrient.MapPoint[ pointInCell: m.first.pos, cellSize: tile.obj.size, cellInstOrient: orient] ]; PlaceMark[into, m.first.name, pos]; ENDLOOP; SetModDefaults[mod, pc]; FOR c: CheckList _ tile.checkList, c.rest WHILE c # NIL DO pos: CD.Position; pos _ CDBasics.AddPoints[lowerLeftCorner, CDOrient.MapPoint[ pointInCell: c.first, cellSize: tile.obj.size, cellInstOrient: orient] ]; AddCheck[mod, pos]; ENDLOOP; RETURN[pc]; END; TileSize: PUBLIC PROC [tile: Tile] RETURNS [Position] = BEGIN RETURN[tile.obj.size]; END; PlaceCheckMark: PUBLIC PROC [into: Module, markPos: Position] = BEGIN mod: Mod _ CheckValid[into]; ShiftedCellIncludeApplication[mod.topCell, CheckMarks.MakeCheckAptr[markPos]]; END; PlaceMark: PUBLIC PROC [into: Module, markName: Rope.ROPE, markPos: Position] = BEGIN mod: Mod _ CheckValid[into]; ShiftedCellIncludeApplication[mod.topCell, AlignmentMarks.MakeMarkAptr[[name: markName, pos: markPos]] ]; END; PlaceStretch: PUBLIC PROC [into: Module, data: StretchData] = BEGIN mod: Mod _ CheckValid[into]; aptr: CD.ApplicationPtr _ StretchLines.MakeLineAptr[data, TRUE]; IF aptr = NIL THEN ERROR Error[BadArgs]; ShiftedCellIncludeApplication[mod.topCell, aptr]; END; PlaceApplication: PUBLIC PROC [into: Module, aptr: CD.ApplicationPtr] = BEGIN mod: Mod _ CheckValid[into]; ShiftedCellIncludeApplication[mod.topCell, aptr]; END; END. บFile: ParquetImplA.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. Created by: Mayo, July 16, 1984 4:44:25 pm PDT Last Edited by: Mayo, November 5, 1984 7:07:45 pm PST Last Edited by: Jacobi, February 8, 1985 1:27:44 pm PST -- Orientations -- Utilities -- A check mark was in a tile just placed, record it in the module. -- is an object already included in a design? -- is a module still valid? -- get a pointer to a cell object, dereferencing through imports if needed -- Accessing Marks and Tiles -- expands (stretches) the objects in a cell on a certain level (layer), does not copy the cell -- stretch object -- map a vector down into the object -- now use the vector to determine location to stretch at -- Copies a cell object and it's applications (recursively). Installs new cell into the directory of 'design'. -- Creates a new cell by scanning through a cell, stretching along each stretch line found and processing any other sorts of parameterization found. -- Creates a new cell only if there was parameterization of the cell. New cell (if any) is entered into the directory of the design passed (if any). -- fill in default variables in symbol table -- first pass: stretch cell, second pass: stretch rectangles on certain layers. stretch along this stretch line -- OLD CODE: -- copy the cell and start over stretchedOb _ CopyCellTree[derefOb, design]; -- evaluate expression -- remove the stretch mark from the cell so that we don't see it again or try to stretch it. Also, we don't want it to appear in resulting cell. TerminalIO.WriteRope["Stretch amount"]; TerminalIO.WriteInt[amount]; TerminalIO.WriteRope[" for cell '"]; TerminalIO.WriteRope[crec.name]; TerminalIO.WriteRope["'.\n"]; -- Convert a ChipNDale cell into a tile, copy only if needed. If copied, enter into design specified (if any). -- stretch the cell -- find marks in the cell -- Combine the user parameters (from the context variable) with any additional parameters supplied by the generator, with the latter overriding. Then take the parameters from the tile set and put them in the table if they are not already there. -- retrieve a cell given it's name -- start of hack, until Christian fixes CDImports.GetReference so that it returns NIL if the importee does not exist. AFTER THAT VERSION IS RELEASED THIS CODE SHOULD BE CHANGED. ...... Bob Mayo, 9/84. -- end of hack -- Accessing Designs -- load design from a file ReadTileSet: PUBLIC PROC [fileName: Rope.ROPE, userParams: SymTab.Ref _ NIL] RETURNS [TileSet, Technology, SymTab.Ref] = BEGIN params: SymTab.Ref _ NIL; tiles: TileSet _ NIL; tiles _ CDIO.ReadDesign[from: fileName]; IF tiles # NIL THEN params _ TileSetExpressions.GetParams[tiles]; params _ ExprRead.CombineTabs[params, userParams]; IF tiles = NIL THEN RETURN[NIL, NIL, params]; RETURN[tiles, tiles.technology, params]; END; -- also returns an empty PlacedTile with which to align things via AlignTile -- Enter a cell and all of its subcells (recursively) into the directory of a design. -- Returns TRUE if it worked, FALSE if it failed. If it fails, only some of the cells may have been entered. EnterCellTreeIntoDirectory: PUBLIC PROC [design: CD.Design, obj: CD.ObPtr] RETURNS [BOOL] = BEGIN cell: CD.CellPtr; found: BOOL; foundObj: CD.ObPtr; cell _ NARROW[obj.specificRef]; [found, foundObj] _ CDDirectory.Fetch[design, cell.name]; IF ~found OR foundObj # obj THEN { IF Owner[obj] # NIL THEN RETURN[FALSE]; IF ~CDDirectory.Include[design, obj] THEN RETURN[FALSE]; }; FOR w: CD.ApplicationList _ cell.contents, w.rest WHILE w#NIL DO IF w.first.ob.p.objectType = $Cell THEN { IF ~EnterCellTreeIntoDirectory[design, w.first.ob] THEN RETURN[FALSE]; }; ENDLOOP; RETURN[TRUE]; END; -- Recursively turn a ShiftedCell into a legal ChipNDale cell object. TRASHES THE ORIGINAL SHIFTED CELL. The position returned is where the new cell should be placed in order for the shifting to have no effect. If design # NIL THEN new cells are entered into that design's directory. -- convert children and add them in -- relocate module so that ll corner is at (0, 0) -- make into an object -- Turn a module into a Cell object, does not make a copy of anything in the module. TRASHES THE ORIGINAL MODULE, except for the default marks, which are relocated. -- If module.eventualOwner # NIL THEN the cells in the module are entered into that design's directory. -- shift our default marks by the same amount that the contents shifted -- just for safety's sake, clear out some stuff -- turn a module into a design. TRASHES THE ORIGINAL MODULE. ModuleIntoDesign: PUBLIC PROC [module: Module, name: Rope.ROPE _ NIL, applicationsPerScreenDot: INT _ -1] RETURNS [CD.Design] = BEGIN mod: Mod _ CheckValid[module]; obj: CD.ObPtr; newDesign: CD.Design _ CDOps.CreateDesign[mod.technology]; obj _ ModuleIntoCell[module, name, applicationsPerScreenDot]; -- put it into a design IF ~EnterCellTreeIntoDirectory[newDesign, obj] THEN ERROR; CDOps.AddAnObject[newDesign, obj, [0, 0]]; RETURN[newDesign]; END; -- turn a module into a tile, TRASHES THE ORIGINAL MODULE. -- Tile Placement Procedures -- Place a cell next to another, using the "top", "bottom", "left", and "right" alignment marks. -- Place a cell next to another, using the "ll" and "lr" alignment marks (for rightOf and leftOf), or the "ll" and "ul" alignment marks (for above and below). -- place a cell into a design using alignment marks -- Alignment Marks -- place a new alignment mark into a design on top of an existing subcell's mark -- Hierarchy -- Find a block, or create a new one if it is not there. -- Switch to a new block in the hierarchy. Subsequent cells will appear in this block. When the generator is done, each block will be put into a chipndale cell. blockName does not have to be declared: if that block doesn't exist a new one is created. The topmost block can be switched to by passing a NIL blockName. -- Returns the last rope passed to SwitchBlock for this module. -- Nest one block inside of another. If the block is already nested or if the nesting creates a circularity then the call is ignored and FALSE is returned. The topmost block is refered to by NIL. Unnested blocks will be put in the topmost block. -- Checking procedures -- list check marks in the VerficationTable. Returns TRUE if any callback proc returned TRUE. -- Checks alignment marks to make sure that the ones placed by the tiler match up properly, as indicated by the syntax of the mark name. -- Return result is the number of errors found. -- Low-level stuff -- cell operations -- place a tile into a module at absolute coordinates -- add in inherited errors from erroneous tiles -- export marks -- default alignment marks -- record check mark positions for later verification -- find out the size of a cell -- mark operations -- Add a mark to a Module at absolute coordinates. Always goes in the top level of the module. -- Add a mark to a Module at absolute coordinates. Always goes in the top level of the module. -- Add a stretch line to a Module at absolute coordinates. Always goes in the top level of the module. -- General loophole: place arbitrary application into Module Edited on February 8, 1985 1:28:14 pm PST, by Jacobi Bug correction: cell.ir _ CDApplications.BoundingRectI[cell.contents]; included in ShiftedCellIntoCell ส˜– "Cedar" stylešœ™Jšœ ฯmœ7™BJ™.J™5J™7J˜—J˜šฯk ˜ Jšœ˜J˜Jšœžœ ˜4Jšœ žœ˜+Jšœ ˜ Jšœžœ˜%Jšœ žœ˜'Jšœ ˜ Jšœžœ ˜%Jšžœ˜Jšœžœ"˜6Jšœžœ˜Jšœ žœ˜,Jšœ žœ5˜CJšœ žœU˜cJšœžœ&˜3Jšœ žœ6˜HJšœ žœ˜-Jšœžœ˜-Jšœžœžœ ˜Jšœžœžœ˜Jšœ žœ˜Jšœžœžœ˜"Jšœ žœ ˜šœžœ4˜@J˜——J˜šฯb œžœžœ˜Jšžœ‰žœžœ˜ว—Jšžœžœ˜$J˜š ฯnœžœžœžœžœ˜Fšžœžœ"˜0J˜9J˜——JšŸœžœžœžœ˜+J˜JšŸ œžœ˜J˜J™™JšŸœžœJ˜YJ˜š   œžœžœžœž˜WJšžœ!˜'Jšžœ˜J˜—š ะbn œžœžœžœž˜UJšžœ(˜.Jšžœ˜J˜——™ J™š œžœžœž˜[JšœF˜FJšœG˜GJšœžœ˜0Jšžœ˜—J˜J™Cš œžœžœ ž˜3Jšœžœ˜ Jšžœžœžœžœ˜GJšœžœžœ˜>•StartOfExpansion[]šžœ5žœžœž˜Išžœžœžœ˜;Jšœžœ˜Jšžœ˜J˜—Jšžœ˜—Jšœžœžœ˜@Jšžœ˜J˜—J™-š  œžœžœžœžœžœž˜4Jšžœ-˜3Jšžœ˜J˜—Jšœ™š   œžœžœžœ ž˜=š žœ žœžœžœžœžœ˜CJšžœ˜—Jšžœžœ˜Jšžœ˜—J˜J™Jš   œžœžœžœžœ ž˜:Jš žœžœžœžœžœ˜šžœž˜Jšœ žœ˜˜ Jšœžœ˜5šžœžœžœ˜Jšžœฯc4˜;J˜—šž˜Jšžœ˜—J˜—Jšžœžœ˜—Jšžœ˜——J™J™™J™_š œžœžœžœžœžœ,žœžœžœž˜ขJšœžœ žœ˜*š žœžœ)žœžœž˜BJšœžœ˜ Jšœžœ$˜-Jšœžœ#˜,Jšžœžœžœ˜!Jšœ™šžœ žœžœžœžœžœžœžœžœžœžœžœžœ˜้Jšœ žœ˜Jšœžœ˜Jšœžœ˜J˜Jšœ žœ˜Jšœžœ˜Jšœ$™$šžœ žœžœข$˜JJšœ&˜&J˜—šžœ˜Jšœ(ข˜FJ˜—šžœ žœžœ˜$Jšœ+˜+—šž˜Jšœ,˜,—JšœL˜LJšœ9™9šžœžœ˜!Jšœ)˜)Jšžœžœžœ˜AJ˜—šžœ˜Jšœ)˜)Jšžœžœžœ˜DJ˜—JšœJ˜JJšžœ žœžœžœ˜ J–[]˜šžœž˜Jšœ0˜0Jšœ0˜0Jšžœ˜—J˜—Jšžœ˜—Jšžœžœ˜ Jšžœ˜J˜—J™oš   œžœ žœžœ žœžœ ž˜RJšœ žœ žœ˜0Jšœžœ žœžœ˜4Jšœ žœ žœžœ˜4Jšœ˜Jšœ<˜Jšžœ žœžœ˜0Jšœ˜J™Pšžœžœžœž˜Jšžœ žœžœ˜:Jšœ!˜!Jšœžœžœ˜9šžœ žœž˜Jšœ!˜!šžœ žœžœžœ žœžœ5žœ8žœ˜ัJšžœ˜Jšžœ˜—šžœ žœข8œžœ˜QJšœ™Jšœžœ˜Jšœžœ˜Jšœžœ˜ šžœ žœ˜™ J™Jšœ,™,—šžœž˜$JšœH˜HJšœS˜SJšžœžœ˜—Jšžœ"žœžœ˜/Jšœ žœ˜Jšžœ˜J˜—Jšœ,˜,Jšžœžœžœ˜#šžœž˜˜J˜J˜J˜—˜ J˜J˜J˜—˜ J˜J˜J˜—˜ J˜J˜J˜—Jšžœžœ˜—Jšœ™JšœF˜FJšœ‘™‘JšžœGžœžœžœ˜Xšžœ žœžœ˜J˜