<> <> <> <> <> 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; <<-- Orientations>> <<>> 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; <<-- Utilities>> << >> 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; <<-- A check mark was in a tile just placed, record it in the module.>> 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; <<-- is an object already included in a design?>> Owner: PROC [ob: CD.ObPtr] RETURNS [REF ANY] = BEGIN RETURN[CDProperties.GetPropFromObject[ob, $Owner]]; END; <<-- is a module still valid?>> 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; <<-- get a pointer to a cell object, dereferencing through imports if needed>> 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; <<>> <<-- Accessing Marks and Tiles>> <<>> <<-- expands (stretches) the objects in a cell on a certain level (layer), does not copy the cell>> 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; <<-- stretch object >> 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; <<-- map a vector down into the object>> 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]; <<-- now use the vector to determine location to stretch at>> 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; <<-- Copies a cell object and it's applications (recursively). Installs new cell into the directory of 'design'.>> 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; <<-- 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).>> InstantiateCell: PROC [design: CD.Design, ob: CD.ObPtr, symbols: SymTab.Ref] RETURNS[CD.ObPtr] = BEGIN AddDefaultParameters: PROC [tab: SymTab.Ref] = BEGIN <<-- fill in default variables in symbol table>> ExprRead.StoreInt[tab, "SizeX", ob.size.x/ ExprRead.StoreInt[tab, "SizeY", ob.size.x/ 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]; <<-- first pass: stretch cell, second pass: stretch rectangles on certain layers.>> 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 { <<-- OLD CODE:>> <<-- copy the cell and start over>> <> 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; <<-- evaluate expression>> [amount, evalError] _ EvalIntegerExpr[expr: line.label, tab: symbols]; <<-- 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.>> 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 * 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 * 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; <<-- Convert a ChipNDale cell into a tile, copy only if needed. If copied, enter into design specified (if any).>> 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]; <<-- stretch the cell>> IF ~fast THEN obj _ InstantiateCell[design, obj, parameters]; tile.obj _ obj; <<-- find marks in the cell>> 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; <<-- 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. >> 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; <<-- retrieve a cell given it's name>> 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 { <<-- 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.>> [found, obj] _ CDDirectory.Fetch[context.tiles, cellName]; IF ~found THEN RETURN[NIL]; <<-- end of hack>> obj _ CDImports.GetReference[context.eventualOwner, cellName, context.tiles.name]; }; IF obj = NIL THEN RETURN[NIL]; RETURN[CellIntoTile[context.eventualOwner, obj, FALSE, context.parameters]] END; <<-- Accessing Designs>> <<>> <<-- load design from a file >> <> <> <> <> <> <> <> <> <> <<>> <<-- also returns an empty PlacedTile with which to align things via AlignTile >> 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; <<-- 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.>> <> <> <> <> <> <<[found, foundObj] _ CDDirectory.Fetch[design, cell.name];>> <> <> <> <<};>> <> <> <> <<};>> <> <> <> <<>> <<-- 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.>> 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]; <<-- convert children and add them in>> 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; <<-- relocate module so that ll corner is at (0, 0)>> 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]; <<-- make into an object>> 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; <<-- 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.>> 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 <<-- shift our default marks by the same amount that the contents shifted>> 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]; <<-- just for safety's sake, clear out some stuff>> module.valid _ FALSE; mod.topCell _ NIL; mod.current _ NIL; mod.cellTab _ NIL; mod.checkTable _ NIL; RETURN[obj]; END; <<-- turn a module into a design. TRASHES THE ORIGINAL MODULE.>> <> <> <> <> <> <<-- put it into a design>> <> <> <> <> <<>> <<-- turn a module into a tile, TRASHES THE ORIGINAL MODULE.>> 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; <<-- Tile Placement Procedures>> <<>> <<>> <<-- Place a cell next to another, using the "top", "bottom", "left", and "right" alignment marks.>> 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; <<-- 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).>> 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; <<-- place a cell into a design using alignment marks>> 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; <<>> <<-- Alignment Marks>> <<>> <<-- place a new alignment mark into a design on top of an existing subcell's mark>> AlignMark: PUBLIC PROC [oldTile: PlacedTile, oldMark: Mark, newMarkName: Rope.ROPE] = BEGIN PlaceMark[oldTile.owner, newMarkName, PlacedMarkLoc[oldTile, oldMark]]; END; <<>> <<>> <<-- Hierarchy>> <<>> <<-- Find a block, or create a new one if it is not there.>> 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; <<-- 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.>> SwitchBlock: PUBLIC PROC [module: Module, blockName: Rope.ROPE] = BEGIN mod: Mod _ CheckValid[module]; mod.current _ BlockFor[mod, blockName]; END; <<-- Returns the last rope passed to SwitchBlock for this module.>> GetCurrentBlock: PUBLIC PROC [module: Module] RETURNS [Rope.ROPE] = BEGIN mod: Mod _ CheckValid[module]; RETURN[mod.current.name]; END; <<-- 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.>> 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; <<-- Checking procedures>> <<>> VerTabProc: TYPE = PROC [pc: PlacedCheck] RETURNS [quit: BOOL _ FALSE]; <<-- list check marks in the VerficationTable. Returns TRUE if any callback proc returned TRUE.>> 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; <<-- 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.>> 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; <<>> <<-- Low-level stuff>> <<-- cell operations>> <<>> <<-- place a tile into a module at absolute coordinates>> 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]; <<-- add in inherited errors from erroneous tiles>> mod.inheritedErrors _ mod.inheritedErrors + tile.inheritedErrors; <<-- export marks>> 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; <<-- default alignment marks>> SetModDefaults[mod, pc]; <<-- record check mark positions for later verification >> 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; <<-- find out the size of a cell>> TileSize: PUBLIC PROC [tile: Tile] RETURNS [Position] = BEGIN RETURN[tile.obj.size]; END; <<-- mark operations>> <<>> <<-- Add a mark to a Module at absolute coordinates. Always goes in the top level of the module.>> PlaceCheckMark: PUBLIC PROC [into: Module, markPos: Position] = BEGIN mod: Mod _ CheckValid[into]; ShiftedCellIncludeApplication[mod.topCell, CheckMarks.MakeCheckAptr[markPos]]; END; <<-- Add a mark to a Module at absolute coordinates. Always goes in the top level of the module.>> 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; <<-- Add a stretch line to a Module at absolute coordinates. Always goes in the top level of the module.>> 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; <<-- General loophole: place arbitrary application into Module>> PlaceApplication: PUBLIC PROC [into: Module, aptr: CD.ApplicationPtr] = BEGIN mod: Mod _ CheckValid[into]; ShiftedCellIncludeApplication[mod.topCell, aptr]; END; END. <> <>