IFUCoreCtlPreCharge:
CEDAR
PROGRAM
IMPORTS Basics, CCDUtils, CD, CDSymbolicObjects, CoreBlock, CoreFrame, CoreName, IFUCoreCells, IFUCoreDrive, IO, Lists, PLAOps, PW, PWCore, PWPins, REFBit, Rope
EXPORTS IFUCoreCtl =
BEGIN
ROPE: TYPE = Core.ROPE;
CellType: TYPE = Core.CellType;
Wire: TYPE = Core.Wire;
Frame: TYPE = CoreFrame.Frame;
PLADescription: TYPE = IFUCoreCtl.PLADescription;
Connection: TYPE = IFUCoreCtl.Connection;
PLAType: TYPE = IFUCoreDrive.PLAType;
Drive: TYPE = IFUCoreDrive.Drive;
Drives: TYPE = IFUCoreDrive.Drives;
DriveRec: TYPE = IFUCoreDrive.DriveRec;
RowType: TYPE = IFUCoreDrive.RowType;
Dir: TYPE = IFUCoreDrive.Dir;
DrGate: TYPE = IFUCoreDrive.DrGate;
Ph: TYPE = IFUCoreDrive.Ph;
Polarity: TYPE = IFUCoreDrive.Polarity;
Signal: SIGNAL = CODE;
MakeHotPLA,
MakePreChargedPLA:
PUBLIC
PROC[desc: PLADescription] = {
log.PutF["\n Make PreCharged/Hot PLA %g", IO.rope[desc.name]];
ZeroUnusedTTTOutputs [desc];
DefinePLARows [desc];
DressInDrs [desc];
MakeOutDrs [desc];
MakePla [desc]};
DressInDrs:
PROC [desc: PLADescription] = {
desc.inDrs ← CONS[ NEW[DriveRec ← [drRowType: xfooter]], desc.inDrs];
FOR list: Drives ← desc.inDrs, list.rest
WHILE list.rest#
NIL DO
REPEAT
FINISHED => list.rest ← CONS [NEW[DriveRec ← [drRowType: xheader]], NIL] ENDLOOP};
ZeroUnusedTTTOutputs:
PROC [desc: PLADescription ] = {
maskTerm: PLAOps.Term ← PLAOps.CopyTerm[desc.ttt.termList.begin];
log.PutRope["\n Zero unused TTT outputs"];
FOR i:
CARDINAL
IN [0..maskTerm.out.wdSize)
DO maskTerm.out[i] ← PLAOps.initOutQrtWz ENDLOOP;
FOR index:
INT
IN [0..desc.smlToBigOut.size)
DO
pos: INT ← desc.smlToBigOut[index];
PLAOps.SetOutQrt[one, maskTerm, REFBit.Desc[desc.ttt.out].bitForm[pos].firstBit] ENDLOOP;
FOR term: PLAOps.Term ← desc.ttt.termList.begin, term.next
WHILE term#
NIL
DO
FOR i:
CARDINAL
IN [0..maskTerm.out.wdSize)
DO
term.out[i].d ← Basics.BITAND[term.out[i].d, maskTerm.out[i].d] ENDLOOP ENDLOOP };
PreChargedParams:
TYPE =
RECORD[
minConnSpace: INT ← 2, -- SPACING rows between driver rows;
insPerExtra: INT ← 10, -- SPACING cols between extra columns;
outsPerExtra: INT ← 10,
nextTerm: PLAOps.Term ← NIL, -- specific parameter
nextConn: INT ← 0, -- specific parameter
rows: REF RowsRec ← NIL ]; -- specific parameter
RowsRec: TYPE = RECORD[SEQUENCE size: CARDINAL OF REF RowRec];
RowRec:
TYPE =
RECORD[
dr: REF DriveRec,
type: RowType,
and: ColSeqRef,
or: ColSeqRef ];
ColSeqRef: TYPE = REF ColSeqRec;
ColSeqRec: TYPE = RECORD[SEQUENCE size: CARDINAL OF NormalCellType];
DefinePLARows:
PROC [desc: PLADescription] = {
pp:
REF PreChargedParams ←
NEW[PreChargedParams ← [
nextTerm: desc.ttt.termList.begin,
nextConn: desc.connSeq.size-1,
insPerExtra: IF desc.plaType = hot THEN 10000 ELSE 10]]; --extra AND column undefined
firstRow: BOOL ← TRUE;
index: INT ← 0;
termUp: BOOL ← TRUE;
nofOuts: INT ← MAX[Lists.ListLength[desc.plaOutNames], desc.nofOrCols];
nofIns: INT ← Lists.ListLength[desc.plaInNames];
cRowsLeft: INT ← Lists.ListLength[desc.plaOutNames];
dRowsLeft: INT ← desc.ttt.termList.length;
hRowsLeft: INT;
dRowsLeft ← MAX[dRowsLeft, cRowsLeft*(pp.minConnSpace)];
hRowsLeft ← MAX[1, (dRowsLeft+ desc.termsPerHeader/2)/desc.termsPerHeader];
log.PutRope["\n Assign precharged/hot pla row types"];
desc.data ← pp;
desc.nofAndCols ← nofIns/2 + (nofIns/2 -1) / pp.insPerExtra;
desc.nofOrCols ← nofOuts + (nofOuts -1) / pp.outsPerExtra;
pp.rows ← NEW[RowsRec[cRowsLeft+dRowsLeft+2*hRowsLeft]];
index ← pp.rows.size-1; -- start at the top
WHILE hRowsLeft#0
DO
-- actually one more header is appended afterwards
RperH: INT ← (cRowsLeft+dRowsLeft+hRowsLeft + hRowsLeft/2)/hRowsLeft;
IF firstRow
THEN firstRow←FALSE
ELSE {pp.rows[index] ← NextRow[desc, xfooter]; index←index-1};
pp.rows[index] ← NextRow[desc, header];
index←index-1; RperH←RperH-1; hRowsLeft←hRowsLeft-1;
WHILE RperH > 0
DO
CperD, DperC: INT;
CperD ← MAX[1, (cRowsLeft + dRowsLeft/2)/dRowsLeft];
DperC ← MAX[1, (dRowsLeft + cRowsLeft/2)/cRowsLeft];
IF DperC < pp.minConnSpace
OR
(CperD>1) AND (pp.minConnSpace>0) THEN ERROR;
RperH ← RperH - CperD - DperC;
WHILE CperD > 0
DO
pp.rows[index] ← NextRow[desc, conn];
index←index-1; cRowsLeft𡤌RowsLeft-1; CperD𡤌perD-1;
ENDLOOP;
termUp ← TRUE;
WHILE DperC > 0
DO
pp.rows[index] ← NextRow[desc, IF termUp THEN dataUp ELSE dataDn];
index←index-1; dRowsLeft𡤍RowsLeft-1; DperC𡤍perC-1;
termUp ← NOT termUp;
ENDLOOP;
ENDLOOP;
ENDLOOP;
IF index#0 THEN ERROR;
pp.rows[index] ← NextRow[desc, footer]};
NextRow:
PROC [desc: PLADescription, type: RowType]
RETURNS[row:
REF RowRec] = {
pp: REF PreChargedParams ← NARROW[desc.data];
andIndex, orIndex, index: INT ← 0;
data: PLAOps.Term;
conn: Connection;
row ← NEW[RowRec ← [type: type]];
row.and ← NEW[ColSeqRec[desc.nofAndCols]];
IF desc.nofOrCols#0 THEN row.or ← NEW[ColSeqRec[desc.nofOrCols]];
SELECT type
FROM
header => { };
conn => {conn ← NextConnection[desc]; row.dr ← conn.dr};
dataUp, dataDn => {
data ← NextDataTerm[desc];
row.dr ← NIL;
IF data=NIL THEN type ← row.type ← blank};
ENDCASE;
FOR index
IN[0..desc.nofAndCols)
DO
IF (index+1)
MOD (pp.insPerExtra+1) = 0
THEN row.and[index] ← extra
ELSE {
SELECT type
FROM
dataUp, dataDn =>
SELECT PLAOps.GetInQrt
[data, REFBit.Desc[desc.ttt.data].bitForm[andIndex].firstBit]
FROM
zero => row.and[index] ← left;
one => row.and[index] ← right;
ENDCASE => row.and[index] ← nc;
conn =>
IF conn.isOutput
OR conn.index#andIndex
THEN row.and[index] ← nc
ELSE
IF conn.isLeftSide
THEN row.and[index] ← left
ELSE row.and[index] ← right;
ENDCASE => row.and[index] ← nc;
andIndex𡤊ndIndex+1 } ENDLOOP;
IF desc.nofOrCols#0
THEN
FOR index
IN[0..desc.nofOrCols)
DO
IF (index+1)
MOD (pp.outsPerExtra+1) = 0
THEN row.or[index] ← extra
ELSE {
row.or[index] ← nc;
IF orIndex < desc.smlToBigOut.size
THEN {
IF (type=dataUp
OR type=dataDn)
AND PLAOps.GetOutQrt
[data, REFBit.Desc[desc.ttt.out].bitForm[desc.smlToBigOut[orIndex]].firstBit]=one
THEN row.or[index] ← left;
IF type=conn
AND conn.isOutput
AND conn.index=desc.smlToBigOut[orIndex]
THEN row.or[index] ← left };
orIndex←orIndex+1 } ENDLOOP};
NextDataTerm:
PROC [desc: PLADescription]
RETURNS[term: PLAOps.Term] = {
pp: REF PreChargedParams ← NARROW[desc.data];
term ← pp.nextTerm;
IF term#NIL THEN pp.nextTerm ← pp.nextTerm.next};
NextConnection:
PROC [desc: PLADescription]
RETURNS[conn: Connection] = {
pp: REF PreChargedParams ← NARROW[desc.data];
conn ← desc.connSeq[pp.nextConn];
pp.nextConn ← pp.nextConn-1};
MakeOutDrs:
PROC[desc: PLADescription] = {
pp: REF PreChargedParams ← NARROW[desc.data];
last: INT ← pp.rows.size+pp.minConnSpace;
FOR driverIndex:
INT DECREASING IN [0..pp.rows.size)
DO
type: RowType ← pp.rows[driverIndex].type;
SELECT type
FROM
header, xfooter, footer => {
IF (last-driverIndex) <= pp.minConnSpace THEN ERROR;
last ← driverIndex+pp.minConnSpace;
desc.outDrs ←
CONS[NEW[DriveRec ← [plaType: desc.plaType, drRowType: type]], desc.outDrs]};
blank, dataUp, dataDn => {
IF (last-driverIndex) <= pp.minConnSpace THEN LOOP;
desc.outDrs ←
CONS[NEW[DriveRec ← [plaType: desc.plaType, drRowType: type]], desc.outDrs]};
conn => {
IF (last-driverIndex) <= pp.minConnSpace THEN ERROR;
last ← driverIndex;
desc.outDrs ← CONS[pp.rows[driverIndex].dr, desc.outDrs]}
ENDCASE => ERROR;
ENDLOOP};
MakePla:
PROC[desc: PLADescription] = {
name: ROPE ← CoreName.RopeNm[desc.name.Cat["Body"]];
IF (desc.outBodyCT ← CoreFrame.ReadFrameCache[name])=
NIL
THEN {
cellType: Core.CellType;
tiles: REF TileVarieties ← GetPLATiles[desc.plaType];
pp: REF PreChargedParams ← NARROW[desc.data];
refPhase: Ph ← unk;
rowList: PW.ListOb ← NIL;
log.PutRope["\n Assemble precharged/hot pla row cells"];
FOR rowIndex:
INT
IN [0..pp.rows.size)
DO
objects: PW.ListOb ← NIL;
row: REF RowRec ← pp.rows[rowIndex];
IF pp.rows[rowIndex].dr#NIL THEN refPhase ← pp.rows[rowIndex].dr.ref.ph;
objects ← CONS[tiles.glue[row.type][leftSide], objects];
FOR index:
INT
IN [0..row.and.size)
DO
objects ← CONS[tiles.and[row.type][row.and[index]], objects] ENDLOOP;
IF desc.nofOrCols#0
THEN {
objects ← CONS[tiles.glue[row.type][between], objects];
FOR index:
INT
IN [0..row.or.size)
DO
objects ← CONS[tiles.or[row.type][row.or[index]], objects] ENDLOOP;
objects ← CONS[tiles.glue[row.type][rightSide], objects] };
rowList ← CONS[PW.SharedAbutListX[PW.Reverse[objects]], rowList]
rowList ← CONS[PW.AbutListX[PW.Reverse[objects]], rowList]
ENDLOOP;
desc.body ← PW.SharedAbutListY[PW.Reverse[rowList]];
desc.body ← PW.AbutListY[PW.Reverse[rowList]];
ApplyNames[desc];
cellType ← PWCore.FromLayoutWithoutPublic[desc.body];
CoreBlock.MarkSides[cellType, desc.capSides];
[ ] ← CoreName.CellNm[cellType, name];
desc.outBodyCT ← CoreFrame.NewFrameCell[0, name, [first: left, cell: cellType] ];
CoreFrame.WriteFrameCache[desc.outBodyCT]};
desc.body ← CCDUtils.Layout[desc.outBodyCT]};
in0: ROPE ← CoreName.RopeNm["in0"];
in1: ROPE ← CoreName.RopeNm["in1"];
out: ROPE ← CoreName.RopeNm["out"];
fire: ROPE ← CoreName.RopeNm["Fire"];
fireControlV: ROPE ← CoreName.RopeNm["FireControlV"];
notPreChg: ROPE ← CoreName.RopeNm["NotPreChg"];
VDD: ROPE ← CoreName.RopeNm["VDD"];
GND: ROPE ← CoreName.RopeNm["GND"];
ApplyNames:
PROC[desc: PLADescription] = {
TileSize:
PROC[obj:
CD.Object]
RETURNS[size:
CD.Position] =
{IF obj=NIL THEN RETURN[[0, 0]]; RETURN[CD.InterestSize[obj]]};
pp: REF PreChargedParams ← NARROW[desc.data];
tiles: REF TileVarieties ← GetPLATiles[desc.plaType];
leftSize: INT ← TileSize[tiles.glue [blank] [leftSide]].x;
andWidth: INT ← TileSize[tiles.and [blank] [nc]].x;
extraWidth: INT ← TileSize[tiles.and [blank] [extra]].x;
headHt: INT ← TileSize[tiles.glue [header] [rightSide]].y;
xfootHt: INT ← TileSize[tiles.glue [xfooter] [rightSide]].y;
rowHt: INT ← TileSize[tiles.glue [blank] [rightSide]].y;
renameProc: PWPins.
ChangePinProc ~ {
old: ROPE ← CoreName.RopeNm[CDSymbolicObjects.GetName[oldPin]];
side: CoreBlock.Sides;
loc: INT;
newPin ← oldPin;
[side, loc] ← CoreBlock.GetInstSideLoc[desc.body, newPin];
SELECT old
FROM
GND => RETURN;
VDD => RETURN;
out => {
name: ROPE;
yPos: INT;
FOR oIndex:
INT
IN [0..pp.rows.size)
DO
SELECT pp.rows[oIndex].type
FROM
header, footer => {yPos ← yPos + headHt; LOOP};
xfooter => {yPos ← yPos + xfootHt; LOOP};
dataUp, dataDn => {yPos ← yPos + rowHt; LOOP};
blank => {yPos ← yPos + rowHt; LOOP};
conn => {IF loc < yPos THEN Signal[]};
ENDCASE => Signal[];
yPos ← yPos + rowHt;
IF loc > yPos THEN LOOP;
name ← IFUCoreDrive.DriveName[pp.rows[oIndex].dr, nin];
CDSymbolicObjects.SetName[newPin, name]; RETURN ENDLOOP;
Signal[]};
in0,
in1 => {
name: ROPE;
list: LIST OF ROPE ← desc.plaInNames;
xpos: INT;
xpos ← (loc - leftSize)/(pp.insPerExtra*andWidth+extraWidth);
xpos ← (loc - leftSize - extraWidth*xpos)/(andWidth/2);
WHILE xpos>1
DO
IF list=NIL THEN RETURN;
list ← list.rest.rest; xpos ← xpos-2 ENDLOOP;
name ← IF xpos=0 THEN list.first ELSE list.rest.first;
IF (xpos=0)#(old=in0) THEN Signal[];
CDSymbolicObjects.SetName[newPin, name];
RETURN};
fire => CDSymbolicObjects.SetName[newPin, "PhB"];
fireControlV => CDSymbolicObjects.SetName[newPin, "FireControlV"]; -- to conn pad
notPreChg => CDSymbolicObjects.SetName[newPin, "NotPreChg"]; -- to conn pad
ENDCASE => RETURN};
desc.body ← PWPins.ChangePins[desc.body, renameProc]};
tileBuffer: REF TileVarieties;
hotTileBuffer: REF TileVarieties;
TileVarieties: TYPE = RECORD[glue: REF GlueTiles, and, or: REF NormalTiles];
GlueTiles: TYPE = ARRAY RowType OF ARRAY GlueCellType OF CD.Object;
GlueCellType: TYPE = {leftSide, between, rightSide};
NormalTiles: TYPE = ARRAY RowType OF ARRAY NormalCellType OF CD.Object;
NormalCellType: TYPE = {left, right, nc, extra};
GetPLATiles:
PROC[type: PLAType]
RETURNS[tiles:
REF TileVarieties] = {
tiles ←
SELECT type
FROM
hot => GetHotPLATiles[],
ENDCASE => GetPreChargedPLATiles[]};
GetPreChargedPLATiles:
PROC
RETURNS[tiles:
REF TileVarieties] = {
Get:
PROC[name:
ROPE]
RETURNS[
CD.Object] =
{RETURN[PW.Get[design: library.design, name: name ]]};
library: CoreLibrary.Library ← IFUCoreCells.library;
IF tileBuffer # NIL THEN RETURN[tileBuffer];
log.PutRope["\n Initialize precharged PLA tiles"];
tiles ← tileBuffer ← NEW[TileVarieties];
tiles.glue ← NEW[GlueTiles];
tiles.and ← NEW[NormalTiles];
tiles.or ← NEW[NormalTiles];
tiles.glue [xfooter][leftSide] ← Get[ "XLeftSide" ];
tiles.glue [xfooter][between] ← Get[ "XBetween" ];
tiles.glue [xfooter][rightSide] ← Get[ "XOrEx" ];
tiles.and [xfooter][nc] ← Get[ "XAnd" ];
tiles.and [xfooter][extra] ← Get[ "XAndEx" ];
tiles.or [xfooter][nc] ← Get[ "XOr" ];
tiles.or [xfooter][extra] ← Get[ "XOrEx" ];
tiles.glue [header][leftSide] ← Get[ "HLeftSide" ];
tiles.glue [header][between] ← Get[ "HBetween" ];
tiles.glue [header][rightSide] ← Get[ "HRightSide" ];
tiles.and [header][nc] ← Get[ "HAnd" ];
tiles.and [header][extra] ← Get[ "HAndEx" ];
tiles.or [header][nc] ← Get[ "HOr" ];
tiles.or [header][extra] ← Get[ "HOrEx" ];
tiles.glue [footer][leftSide] ← PW.FlipY[ tiles.glue [header][leftSide] ];
tiles.glue [footer][between] ← PW.FlipY[ tiles.glue [header][between] ];
tiles.glue [footer][rightSide] ← PW.FlipY[ tiles.glue [header][rightSide] ];
tiles.and [footer][nc] ← PW.FlipY[ tiles.and [header][nc] ];
tiles.and [footer][extra] ← PW.FlipY[ tiles.and [header][extra] ];
tiles.or [footer][nc] ← PW.FlipY[ tiles.or [header][nc] ];
tiles.or [footer][extra] ← PW.FlipY[ tiles.or [header][extra] ];
tiles.glue [blank][leftSide] ← Get[ "BLeftSide" ];
tiles.glue [blank][between] ← Get[ "BBetween" ];
tiles.glue [blank][rightSide] ← Get[ "BOrEx" ];
tiles.and [blank][nc] ← Get[ "BAnd" ];
tiles.and [blank][extra] ← Get[ "BAndEx" ];
tiles.or [blank][nc] ← Get[ "BOr" ];
tiles.or [blank][extra] ← Get[ "BOrEx" ];
tiles.glue [conn][leftSide] ← Get[ "BLeftSide" ];
tiles.glue [conn][between] ← Get[ "BBetween" ];
tiles.glue [conn][rightSide] ← Get[ "CRightSide" ];
tiles.and [conn][left] ← Get[ "CAndLt" ];
tiles.and [conn][right] ← Get[ "CAndRt" ];
tiles.and [conn][nc] ← Get[ "BAnd" ];
tiles.and [conn][extra] ← Get[ "BAndEx" ];
tiles.or [conn][left] ← Get[ "COr" ];
tiles.or [conn][nc] ← Get[ "COrNC" ];
tiles.or [conn][extra] ← Get[ "COrEx" ];
tiles.glue [dataUp][leftSide] ← Get[ "DLeftSide" ];
tiles.glue [dataUp][between] ← Get[ "DBetween" ];
tiles.glue [dataUp][rightSide] ← Get[ "DRightSide" ];
tiles.and [dataUp][left] ← Get[ "DAndLt" ];
tiles.and [dataUp][right] ← Get[ "DAndRt" ];
tiles.and [dataUp][nc] ← Get[ "DAnd" ];
tiles.and [dataUp][extra] ← Get[ "DAndEx" ];
tiles.or [dataUp][left] ← Get[ "DOr" ];
tiles.or [dataUp][nc] ← Get[ "DOrNC" ];
tiles.or [dataUp][extra] ← Get[ "DOrEx" ];
tiles.glue [dataDn][leftSide] ← tiles.glue [dataUp][leftSide];
tiles.glue [dataDn][between] ← PW.FlipY[ tiles.glue [dataUp][between] ];
tiles.glue [dataDn][rightSide] ← PW.FlipY[ tiles.glue [dataUp][rightSide] ];
tiles.and [dataDn][left] ← tiles.and [dataUp][left];
tiles.and [dataDn][right] ← tiles.and [dataUp][right];
tiles.and [dataDn][nc] ← tiles.and [dataUp][nc];
tiles.and [dataDn][extra] ← tiles.and [dataUp][extra];
tiles.or [dataDn][left] ← PW.FlipY[ tiles.or [dataUp][left] ];
tiles.or [dataDn][nc] ← PW.FlipY[ tiles.or [dataUp][nc] ];
tiles.or [dataDn][extra] ← PW.FlipY[ tiles.or [dataUp][extra] ];
RETURN[tiles]};
GetHotPLATiles:
PROC
RETURNS[tiles:
REF TileVarieties] = {
Get:
PROC[name:
ROPE]
RETURNS[
CD.Object] =
{RETURN[PW.Get[design: library.design, name: name ]]};
library: CoreLibrary.Library ← IFUCoreCells.library;
IF hotTileBuffer # NIL THEN RETURN[hotTileBuffer];
log.PutRope["\n Initialize hot PLA tiles"];
tiles ← hotTileBuffer ← NEW[TileVarieties];
tiles.glue ← NEW[GlueTiles];
tiles.and ← NEW[NormalTiles];
tiles.or ← NEW[NormalTiles];
tiles.glue [header][leftSide] ← Get[ "HPlaHLeftSide" ];
tiles.glue [header][between] ← Get[ "HPlaHBetween" ];
tiles.glue [header][rightSide] ← Get[ "HPlaHRightSide" ];
tiles.and [header][nc] ← Get[ "HPlaHAnd" ];
tiles.or [header][nc] ← Get[ "HPlaHOr" ];
tiles.or [header][extra] ← Get[ "HPlaHOrEx" ];
tiles.glue [footer][leftSide] ← PW.FlipY[ tiles.glue [header][leftSide] ];
tiles.glue [footer][between] ← PW.FlipY[ tiles.glue [header][between] ];
tiles.glue [footer][rightSide] ← PW.FlipY[ tiles.glue [header][rightSide] ];
tiles.and [footer][nc] ← PW.FlipY[ tiles.and [header][nc] ];
tiles.or [footer][nc] ← PW.FlipY[ tiles.or [header][nc] ];
tiles.or [footer][extra] ← PW.FlipY[ tiles.or [header][extra] ];
tiles.glue [blank][leftSide] ← Get[ "HPlaBLeftSide" ];
tiles.glue [blank][between] ← Get[ "HPlaBBetween" ];
tiles.glue [blank][rightSide] ← Get[ "HPlaBRightSide" ];
tiles.and [blank][nc] ← Get[ "HPlaBAnd" ];
tiles.or [blank][nc] ← Get[ "BOr" ];
tiles.or [blank][extra] ← Get[ "HPlaBOrEx" ];
tiles.glue [conn][leftSide] ← Get[ "HPlaBLeftSide" ];
tiles.glue [conn][between] ← Get[ "HPlaBBetween" ];
tiles.glue [conn][rightSide] ← Get[ "HPlaCRightSide" ];
tiles.and [conn][left] ← Get[ "CAndLt" ];
tiles.and [conn][right] ← Get[ "CAndRt" ];
tiles.and [conn][nc] ← Get[ "BAnd" ];
tiles.or [conn][left] ← Get[ "COr" ];
tiles.or [conn][nc] ← Get[ "COrNC" ];
tiles.or [conn][extra] ← Get[ "HPlaCOrEx" ];
tiles.glue [dataUp][leftSide] ← Get[ "HPlaDLeftSide" ];
tiles.glue [dataUp][between] ← Get[ "HPlaDBetween" ];
tiles.glue [dataUp][rightSide] ← Get[ "HPlaDRightSide" ];
tiles.and [dataUp][left] ← Get[ "DAndLt" ];
tiles.and [dataUp][right] ← Get[ "DAndRt" ];
tiles.and [dataUp][nc] ← Get[ "DAnd" ];
tiles.or [dataUp][left] ← Get[ "DOr" ];
tiles.or [dataUp][nc] ← Get[ "DOrNC" ];
tiles.or [dataUp][extra] ← Get[ "HPlaDOrEx" ];
tiles.glue [dataDn][leftSide] ← tiles.glue [dataUp][leftSide];
tiles.glue [dataDn][between] ← PW.FlipY[ tiles.glue [dataUp][between] ];
tiles.glue [dataDn][rightSide] ← PW.FlipY[ tiles.glue [dataUp][rightSide] ];
tiles.and [dataDn][left] ← tiles.and [dataUp][left];
tiles.and [dataDn][right] ← tiles.and [dataUp][right];
tiles.and [dataDn][nc] ← tiles.and [dataUp][nc];
tiles.and [dataDn][extra] ← tiles.and [dataUp][extra];
tiles.or [dataDn][left] ← PW.FlipY[ tiles.or [dataUp][left] ];
tiles.or [dataDn][nc] ← PW.FlipY[ tiles.or [dataUp][nc] ];
tiles.or [dataDn][extra] ← PW.FlipY[ tiles.or [dataUp][extra] ];
RETURN[tiles]};
log: IO.STREAM ← CoreFrame.GetLog[];
END.