File: ParquetImplA.mesa
Copyright © 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
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/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];
-- 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 {
stretch along this stretch line
min, place, amount: INT;
evalError: Rope.ROPE;
line: REF StretchLines.LineData;
IF ~copied
THEN {
-- OLD CODE:
-- copy the cell and start over
stretchedOb ← CopyCellTree[derefOb, design];
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;
TerminalIO.WriteRope["Stretch amount"];
TerminalIO.WriteInt[amount];
TerminalIO.WriteRope[" for cell '"];
TerminalIO.WriteRope[crec.name];
TerminalIO.WriteRope["'.\n"];
[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 {
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;
-- 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
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
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.
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.
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.
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.
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]
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.
Edited on February 8, 1985 1:28:14 pm PST, by Jacobi
Bug correction: cell.ir ← CDApplications.BoundingRectI[cell.contents]; included in ShiftedCellIntoCell