IFUCoreDriveImpl.mesa,
Copyright c 1986 by Xerox Corporation. All rights reserved.
Last Edited by Curry, June 26, 1986 12:25:51 pm PDT
DIRECTORY CD, CDDirectory, CDOrient, Core, CoreBlock, CoreCreate, CoreFrame, CoreInstCell, CoreIO, CoreLibrary, CoreName, CoreOps, CoreProperties, IFUCoreCells, IFUCoreDrive, IO, PW, PWCore, PWPins, REFBit, Rope;
IFUCoreDriveImpl: CEDAR PROGRAM
IMPORTS CDDirectory, CoreBlock, CoreCreate, CoreFrame, CoreInstCell, CoreIO, CoreLibrary, CoreName, CoreOps, CoreProperties, IFUCoreCells, IO, PW, PWCore, REFBit, Rope
EXPORTS IFUCoreDrive =
BEGIN
ROPE:   TYPE = Core.ROPE;
CellType:  TYPE = Core.CellType;
Wire:   TYPE = Core.Wire;
PLAType: TYPE = IFUCoreDrive.PLAType;
Drive:   TYPE = IFUCoreDrive.Drive;
Drives:  TYPE = IFUCoreDrive.Drives;
DriveRec:  TYPE = IFUCoreDrive.DriveRec;
DrNmType: TYPE = IFUCoreDrive.DrNmType;
RowType: TYPE = IFUCoreDrive.RowType;
Dir:   TYPE = IFUCoreDrive.Dir;
DrGate:  TYPE = IFUCoreDrive.DrGate;
Ph:   TYPE = IFUCoreDrive.Ph;
Polarity:  TYPE = IFUCoreDrive.Polarity;
DrTileRec:   TYPE = IFUCoreDrive.DrTileRec;
DrTileNonConn:  TYPE = IFUCoreDrive.DrTileNonConn;
DrTileConn:   TYPE = IFUCoreDrive.DrTileConn;
DrTileArray:   TYPE = IFUCoreDrive.DrTileArray;
DriveTileType:  TYPE = IFUCoreDrive.DriveTileType;
Signal: SIGNAL = CODE;
driveCellClass: PUBLIC Core.CellClass ←
CoreOps.SetClassPrintProc[
NEW[Core.CellClassRec ← [name: "IFUCoreDrive", recast: NIL]],
ClassPrintProc];
ClassPrintProc: CoreOps.PrintClassProc = {
drData: Drive ← NARROW[data];
IO.PutF[out, "\nDriver: %g", IO.rope[ DrRope[drData] ] ] };
drShiftIn: PUBLIC ATOM ← CoreIO.RegisterProperty[
CoreProperties.RegisterProperty[
$DShiftIn,
CoreProperties.Props[
[CoreProperties.propCompare, NEW[CoreProperties.PropCompareProc ← CompareRope]],
[CoreProperties.propCopy,  NEW[CoreProperties.PropCopyProc  ← CopyRope ]],
[CoreProperties.propPrint,  NEW[CoreProperties.PropPrintProc  ← PrintRopeIn ]] ]],
WriteRope,
ReadRope ];
drShiftOut: PUBLIC ATOM ← CoreIO.RegisterProperty[
CoreProperties.RegisterProperty[
$DShiftOut,
CoreProperties.Props[
[CoreProperties.propCompare, NEW[CoreProperties.PropCompareProc ← CompareRope]],
[CoreProperties.propCopy,  NEW[CoreProperties.PropCopyProc  ← CopyRope  ]],
[CoreProperties.propPrint,  NEW[CoreProperties.PropPrintProc  ← PrintRopeOut]]]],
WriteRope,
ReadRope ];
WriteRope: CoreIO.PropWriteProc =
{rope: ROPE ← NARROW[value]; CoreIO.WriteRope[h, rope]};
ReadRope: CoreIO.PropReadProc = {rope: ROPE ← CoreIO.ReadRope[h]; RETURN[ rope ]};
CopyRope: CoreProperties.PropCopyProc = {RETURN[value]};
CompareRope: CoreProperties.PropCompareProc = {
rope1: ROPENARROW[value1];
rope2: ROPENARROW[value2];
RETURN[Rope.Equal[rope1, rope2]]};
PrintRopeIn: CoreProperties.PropPrintProc =
{rope: ROPE ← NARROW[val]; to.PutF["DShiftIn: %g", IO.rope[rope]]};
PrintRopeOut: CoreProperties.PropPrintProc =
{rope: ROPE ← NARROW[val]; to.PutF["DShiftOut: %g", IO.rope[rope]]};
SetDShiftIO: PUBLIC PROC[cellType: CellType, sIn, sOut: ROPE] = {
CoreProperties.PutCellTypeProp[cellType, drShiftIn, sIn];
CoreProperties.PutCellTypeProp[cellType, drShiftOut, sOut]};
GetDShiftIO: PUBLIC PROC[cellType: CellType] RETURNS [sIn, sOut: ROPE] = {
sIn ← NARROW[CoreProperties.GetCellTypeProp[cellType, drShiftIn ]];
sOut ← NARROW[CoreProperties.GetCellTypeProp[cellType, drShiftOut ]]};
CellProc: PUBLIC PROC [
name: ROPE ← NIL,
data: Drive ← NIL ]
RETURNS [cellType: CellType] = {
cellType ← CoreOps.SetCellTypeName[
NEW [ Core.CellTypeRec ← [
class:  driveCellClass,
public: CoreOps.CreateWires[0],
data:  data] ],
name];
CoreFrame.SetFrameExpandProc[soft,   cellType, NEW[CoreFrame.ExpandProc ← Expand] ];
CoreFrame.SetFrameExpandProc[hard, cellType, NEW[CoreFrame.ExpandProc ← Expand] ]};
Expand: CoreFrame.ExpandProc = {
drive:    Drive   ← NARROW[frameCT.data];
frame:    REF CoreFrame.FrameRec ← NEW[CoreFrame.FrameRec ← [first: left]];
genericDriver: CellType      ← GetGenericDriver[drive];
driverName:  ROPE       ← DriveName[drive, out];
renameProc:  CoreInstCell.RenameProc = {new ← SpecificNames[old, drive]};
frame.cell   ← CoreInstCell.SpecificGeneric[genericDriver, renameProc];
frame.seq   ← NEW[CoreFrame.FrameSeq[0]];
frameCT.data  ← frame;
frameCT.class ← CoreFrame.frameCellClass;
CoreFrame.SetFrameExpandProc[soft, frameCT, NIL];
CoreFrame.SetFrameExpandProc[hard, frameCT, NIL]};
OldExpand: CoreFrame.ExpandProc = {
drive:    Drive   ← NARROW[frameCT.data];
frame:    REF CoreFrame.FrameRec ← NEW[CoreFrame.FrameRec ← [first: left]];
public:   CoreName.Context   ← CoreName.NewContext[];
genericDriver: CellType      ← GetGenericDriver[drive];
driverName:  ROPE       ← DriveName[drive, out];
pas:    LIST OF CoreCreate.PA;
eachWire:  CoreOps.EachWireProc = {
specificName: ROPE;
specific:   Wire;
IF wire.size#0 THEN RETURN;
specificName ← SpecificNames[CoreName.WireNm[wire].n, drive ];
IF specificName=NIL THEN Signal[];
specific  ← CoreName.CtxWire[public, specificName ];
pas   ← CONS[ [wire, specific], pas]};
[ ] ← CoreOps.VisitWire[genericDriver.public, eachWire];
frame.cell   ← CoreCreate.Cell[
public:  CoreName.WireFromCtx[public],
onlyInternal: NIL,
instances:  LIST[CoreCreate.InstanceList[genericDriver, pas]],
name:   driverName ];
public   ← CoreName.KillContext[public];
CoreBlock.PutCellSide[frame.cell, CoreFrame.SideSides[frame.first]];
CoreBlock.MergeSides[frame.cell];
PWCore.SetAbutX[frame.cell];
frame.seq   ← NEW[CoreFrame.FrameSeq[0]];
frameCT.data  ← frame;
frameCT.class ← CoreFrame.frameCellClass;
CoreFrame.SetFrameExpandProc[soft, frameCT, NIL];
CoreFrame.SetFrameExpandProc[hard, frameCT, NIL]};
GetGenericDriver: PROC[drive: Drive]
RETURNS[genericDriver: CellType] = {
obj: CD.Object;
basicDrName, drName: ROPE;
decoderOut:  BOOL
drive.plaType=decoder AND drive.drRowType=conn AND drive.drDir=out;
library:   CoreLibrary.Library   ← IFUCoreCells.library;
drTiles:   REF DrTileRec ← GetDriverTiles[];
IF drive.drRowType#conn THEN {
plaType: PLAType ←
SELECT drive.plaType FROM hot, precharged => drive.plaType, ENDCASE => static;
RETURN[drTiles.nconn[plaType][drive.drRowType]]};
basicDrName ← GenericDriverName[drive];
drName  ← IF decoderOut
THEN Rope.Cat["D", basicDrName]
ELSE basicDrName;
genericDriver ← CoreLibrary.Get[library, basicDrName];
IF genericDriver=NIL THEN {
Inst: PROC[type: DriveTileType] = {cells ← CONS[ drTiles.conn[drive.drDir][type], cells]};
cells: LIST OF CellType ← NIL;
IF drive.ref.ph=unk -- Debug driver, clears node on either phase
THEN Inst[inGndAB]
ELSE {
IF drive.ref.pol=drive.in.pol
THEN Inst[inPos]
ELSE Inst[inNeg];
IF drive.ref.ph=A
THEN Inst[latchA]
ELSE Inst[latchB]};
Inst[latch];
IF drive.drDir#in THEN SELECT drive.gate FROM
pos  => Inst[gateP];
neg  => Inst[gateN];
negAc => Inst[gateNA];
negBc  => Inst[gateNB];
ENDCASE => ERROR;
IF drive.dualOut
THEN {
IF (drive.ref.pol=drive.out.pol)=(drive.gate=pos)
THEN Inst[posDual]
ELSE Inst[negDual]}
ELSE
IF (drive.ref.pol=drive.out.pol)=(drive.gate=pos)
THEN Inst[posSing]
ELSE Inst[negSing];
genericDriver ← CoreBlock.AbutCellList
[basicDrName, (IF drive.drDir=out THEN right ELSE left), cells];
CoreLibrary.Set[library, basicDrName, genericDriver];
obj ← PWCore.Layout[genericDriver]}; -- Make sure PWCore is happy with construction
genericDriver ← CoreLibrary.Get[library, drName];
IF genericDriver=NIL THEN {
thinDriver: CellType ← CoreLibrary.Get[library, basicDrName];
genericDriver ← CoreCreate.Cell[
public:  CoreOps.CopyWire[thinDriver.public],
onlyInternal: NIL,
instances:  LIST[
CoreCreate.Instance[drTiles.nconn[decoder][blank],
[dShDataRp, dShDataInRp]],
CoreCreate.Instance[thinDriver]],
name:   drName ];
PWCore.SetAbutY[genericDriver];
CoreBlock.PutCellSide[genericDriver, CoreFrame.SideSides[bottom]];
CoreBlock.MergeSides[genericDriver];
CoreLibrary.Set[library, drName, genericDriver];
obj ← PWCore.Layout[genericDriver]} }; -- Make sure PWCore is happy with construction
inRp:    ROPE ← CoreName.RopeNm["in"];
ioRp:    ROPE ← CoreName.RopeNm["io"];
outRp:   ROPE ← CoreName.RopeNm["out"];
out0Rp:   ROPE ← CoreName.RopeNm["out0"];
out1Rp:   ROPE ← CoreName.RopeNm["out1"];
dShDataRp:  ROPE ← CoreName.RopeNm["DShData"];
dShDataInRp: ROPE ← CoreName.RopeNm["DShDataIn"];
dShDataOutRp: ROPE ← CoreName.RopeNm["DShDataOut"];
SpecificNames: PUBLIC PROC[generic: ROPE, drive: Drive]
RETURNS [specific: ROPE] = {
specific ← SELECT generic FROM
inRp  =>            DriveName[drive,in],
out0Rp =>            DriveName[drive,out],
out1Rp => IF ~drive.dualOut THEN NIL ELSE DriveName[drive,nout],
dShDataRp  => SELECT TRUE FROM
drive.inSh=NILAND drive.outSh=NIL => CoreName.ID[generic],
drive.inSh  =  drive.outSh  => drive.inSh,
drive.inSh#NILAND drive.outSh=NIL => drive.inSh,
drive.inSh=NILAND drive.outSh#NIL => drive.outSh,
ENDCASE          => ERROR,
dShDataInRp   => IF drive.inSh=NIL THEN CoreName.ID[generic] ELSE drive.inSh,
dShDataOutRp  => IF drive.outSh=NILTHEN CoreName.ID[generic] ELSE drive.outSh,
ENDCASE   => generic;
IF specific#NIL THEN specific ← CoreName.RopeNm[specific]};
tileBuffer: REF DrTileRec ← NIL;
GetDriverTiles: PUBLIC PROC RETURNS[tiles: REF DrTileRec] = {
Get: PROC[name: ROPE] RETURNS[cell: CellType] =
{cell ← CoreLibrary.Get[library, name]};
FlipY: PROC[ref: ROPE] RETURNS[cell: CellType] = {
name: ROPE  ← CoreName.RopeNm[ref.Cat["FlipY"]];
obj: CD.Object ← CDDirectory.Fetch[library.design, ref].object;
cell ← CoreLibrary.Get[library, name];
IF cell#NIL THEN RETURN[cell];
cell ← CoreLibrary.ObjCell[PW.FlipY[obj], name];
CoreLibrary.Set[library, name, cell]};
driveTop: CellType;
driveBot: CellType;
library: CoreLibrary.Library ← IFUCoreCells.library;
IF tileBuffer # NIL THEN RETURN[tileBuffer];
log.PutRope["\n Initialize drive tiles"];
tiles ← tileBuffer     ← NEW[DrTileRec];
tiles.conn[in]      ← NEW[DrTileArray];
tiles.conn[out]      ← NEW[DrTileArray];
tiles.nconn [precharged][header] ← Get[ "DrHead" ];
tiles.nconn [precharged][xheader] ← Get[ "DrXHead"];
tiles.nconn [precharged][extend] ← Get[ "DrExtend" ];
tiles.nconn [precharged][blank] ← Get[ "DrBlank" ];
tiles.nconn [precharged][dataUp] ← tiles.nconn [precharged][blank];
tiles.nconn [precharged][dataDn] ← tiles.nconn [precharged][blank];
tiles.nconn [precharged][footer] ← FlipY[ "DrHead"];
tiles.nconn [precharged][xfooter] ← FlipY[ "DrXHead"];
tiles.nconn [hot][header]   ← Get[ "HPlaDrHead" ];
tiles.nconn [hot][xheader]   ← Get[ "DrXHead"];
tiles.nconn [hot][extend]   ← Get[ "DrExtend" ];
tiles.nconn [hot][blank]   ← Get[ "DrBlank" ];
tiles.nconn [hot][dataUp]   ← tiles.nconn [hot][blank];
tiles.nconn [hot][dataDn]   ← tiles.nconn [hot][blank];
tiles.nconn [hot][footer]   ← FlipY[ "HPlaDrHead"];
tiles.nconn [hot][xfooter]   ← FlipY[ "DrXHead"];
tiles.nconn [static][header]   ← Get[ "SPlaDrHead" ];
tiles.nconn [static][xheader]  ← Get[ "DrXHead" ];
tiles.nconn [static][extend]   ← Get[ "DrExtend" ];
tiles.nconn [static][blank]   ← Get[ "SPlaDrBlank24" ];
tiles.nconn [static][dataUp]   ← tiles.nconn [static][blank];
tiles.nconn [static][dataDn]  ← tiles.nconn [static][blank];
tiles.nconn [static][footer]   ← FlipY[ "SPlaDrHead"];
tiles.nconn [static][xfooter]   ← FlipY[ "DrXHead"];
tiles.nconn [decoder][blank]  ← Get[ "DPlaDrBlank6" ]; --1 use
tiles.conn [in][inPos]    ← Get[ "DrInInPos" ];
tiles.conn [in][inNeg]    ← Get[ "DrInInNeg" ];
tiles.conn [in][latchA]    ← Get[ "DrInA" ];
tiles.conn [in][latchB]    ← Get[ "DrInB" ];
tiles.conn [in][latch]    ← Get[ "DrLatch" ];
tiles.conn [in][posSing]    ← Get[ "DrInPosSing" ];
tiles.conn [in][negSing]   ← Get[ "DrInNegSing" ];
tiles.conn [in][posDual]   ← Get[ "DrInPosDual" ];
tiles.conn [in][negDual]   ← Get[ "DrInNegDual" ];
tiles.conn [out][inPos]    ← Get[ "DrOutInPos" ];
tiles.conn [out][inNeg]    ← Get[ "DrOutInNeg" ];
tiles.conn [out][inGndAB]   ← Get[ "DrOutInGndAB" ];
tiles.conn [out][latchA]   ← Get[ "DrOutLatchA" ];
tiles.conn [out][latchB]    ← Get[ "DrOutLatchB" ];
tiles.conn [out][latch]    ← Get[ "DrLatch" ];
tiles.conn [out][gateP]    ← Get[ "DrOutPos" ];
tiles.conn [out][gateN]    ← Get[ "DrOutNeg" ];
tiles.conn [out][gateNA]   ← Get[ "DrOutNegAc" ];
tiles.conn [out][gateNB]   ← Get[ "DrOutNegBc" ];
tiles.conn [out][posSing]   ← Get[ "DrOutPosSing" ];
tiles.conn [out][negSing]   ← Get[ "DrOutNegSing" ];
tiles.conn [out][posDual]   ← Get[ "DrOutPosDual" ];
tiles.conn [out][negDual]   ← Get[ "DrOutNegDual" ];
driveTop ← CoreLibrary.Get[library, "DrTop"];
driveBot ← CoreFrame.RotateCellType[driveTop, CDOrient.mirrorY];
    CoreLibrary.Set[library, "DrBot", driveBot];
RETURN[tiles]};
DrRope: PROC[rec: Drive] RETURNS[rope: ROPE] = {
dirRope: ARRAY Dir OF ROPE  = [" in", "out"];
polRope: ARRAY Polarity OF ROPE = ["pos", "neg", "unk"];
phRope: ARRAY Ph OF ROPE   ← CoreName.PhRope;
gateRope: ARRAY DrGate OF ROPE = [" neg", "negAc", "negBc", " pos"];
dualSing: ARRAY BOOL OF ROPE  = ["sing", "dual"];
rowType: ARRAY RowType OF ROPE=
["Header", "Xheader", "Footer", "Xfooter", "Conn", "DataUp", "DataDn", "Blank", "Extend"];
SELECT rec.drRowType FROM
conn => {
rope ← IO.PutFR["%3g %12g %12g",
IO.rope[dirRope[rec.drDir]],
IO.rope[rec.name],
IO.rope[rec.nameInv] ];
rope ← rope.Cat[IO.PutFR[" %g.%g",
IO.int[rec.cy],
IO.int[rec.idx] ] ];
rope ← rope.Cat[IO.PutFR[" %g",
IO.rope[rec.inNm] ] ];
rope ← rope.Cat[IO.PutFR[" %g%g %g%g",
IO.rope[polRope [rec.in.pol]],
IO.rope[phRope [rec.in.ph]],
IO.rope[polRope [rec.ref.pol]],
IO.rope[phRope [rec.ref.ph]] ] ];
rope ← rope.Cat[IO.PutFR[" %g %g %g%g",
IO.rope[gateRope [rec.gate]],
IO.rope[dualSing [rec.dualOut]],
IO.rope[polRope [rec.out.pol]],
IO.rope[phRope [rec.out.ph]] ] ]};
ENDCASE => rope ← rowType[rec.drRowType]};
DriverFill: PUBLIC PROC RETURNS[frame: Frame] = {
frame  ← CDF.NewFrame[2, x, CDF.ID["DriverFill"]];
frame[0] ← CDF.Glue[];
frame[1] ← CDF.NewObjectFrame[DriverCell[static, extend]]};
DriverExt: PUBLIC PROC[up: BOOL ← FALSE] RETURNS[frame: Frame] = {
frame  ← CDF.NewFrame[2, x, CDF.ID["DriverFill"]];
frame[0] ← IF up THEN CDF.Glue[t:ext, b:conn] ELSE CDF.Glue[t:conn, b:ext];
frame[1] ← CDF.NewObjectFrame[DriverCell[static, extend]]};
BuildDrivers: PUBLIC PROC[frame: Frame, design: CD.Design] = {
IF frame.seqSize > 0
THEN FOR index: INT IN [0..frame.seqSize)
DO BuildDrivers[frame[index], design] ENDLOOP
ELSE {
drive: Drive ← NARROW[frame.data];
frame.data ← DriverCell[static, conn, drive, design];
frame.shell ← CDF.ShellFromObject[NARROW[frame.data]]} };
GenericDriverName: PUBLIC PROC[drive: Drive] RETURNS[name: ROPE] = {
IF drive.drDir = out THEN {
IF drive.out.ph=Ac THEN drive.gate ← negAc;
IF drive.out.ph=Bc THEN drive.gate ← negBc };
name ← "Drive";
name ← name.Cat[IF drive.drDir = in     THEN "In" ELSE "Out"];
name ← name.Cat[IF drive.ref.pol=drive.in.pol  THEN "Pos" ELSE "Neg"];
name ← name.Cat[SELECT drive.ref.ph
FROM A => "A", B => "B", unk => "GndAB", ENDCASE => ERROR];
name ← name.Cat[SELECT drive.gate FROM
neg  => "Neg",
negAc => "NAc",
negBc  => "NBc",
pos  => "",
ENDCASE => ERROR];
name ← name.Cat[
IF (drive.ref.pol=drive.out.pol)=(drive.gate=pos)  THEN "Pos" ELSE "Neg"];
name ← name.Cat[IF drive.dualOut      THEN "Dual" ELSE "Sing"]};
CapDrives: PUBLIC PROC[drives: Drives, sIn, altOut: ROPENIL]
RETURNS[newDrives: Drives, sOut: ROPE ← NIL] = {
sOut ← ConnectDrives[drives, sIn];
newDrives ← CONS[NEW[DriveRec ← [drRowType: xfooter, inSh: sIn, outSh: sIn]], drives];
FOR drives ← newDrives, drives.rest WHILE drives.rest#NIL DO ENDLOOP;
sOut ← IF altOut#NIL THEN altOut ELSE drives.first.outSh;
drives.first.outSh ← sOut;
drives.rest ← CONS[NEW[DriveRec ← [drRowType: xheader, inSh: sOut, outSh: sOut]], NIL]};
RefToDriverFrame: PUBLIC PROC[name: ROPE, refRec: REF, initial: DriveRec]
RETURNS[cell: CellType, outSh: ROPE]= {
top, bot: Drive;
drName: ROPEIF initial.drDir = in
THEN name.Cat["In"]
ELSE name.Cat["Out"];
[cell, outSh] ← RefToDriverFrameBasic[drName, refRec, initial];
top ← NEW[DriveRec ← [drRowType: xheader, inSh: outSh,   outSh: outSh]];
bot ← NEW[DriveRec ← [drRowType: xfooter,  inSh: initial.inSh, outSh: initial.inSh]];
cell   ← CoreFrame.NewFrameCells[
name: name,
rec: [first: top],
cells: LIST[
CellProc[name: DrRope[top], data: top],
cell,
CellProc[name: DrRope[bot], data: bot] ] ] };
RefToDriverFrameBasic: PUBLIC PROC [name: ROPE, refRec: REF, initial: DriveRec]
RETURNS[cell: CellType, outSh: ROPE]= {
drives: Drives ← RefToDrives[refRec, initial];
outSh    ← ConnectDrives[drives];
cell    ← DrivesToFrame[name, drives]};
RefToDrives: PUBLIC PROC [refRec: REF, initial: DriveRec]
RETURNS[drives: Drives]= {
dualOut: BOOLFALSE;
bitForm: REFBit.Format ← REFBit.Desc[refRec].bitForm;
FOR bit: INT DECREASING IN [0..bitForm.size) DO
inverted: BOOL;
drive: Drive  ← NEW[DriveRec ← initial];
[drive.name, drive.nameInv, dualOut, inverted, drive.cy, drive.idx] ←
CoreName.NormalFormatNames[bitForm[bit]];
drive.dualOut ← initial.dualOut OR dualOut;
IF inverted THEN drive.in.pol ← SELECT drive.in.pol
FROM pos=>neg, neg=>pos, ENDCASE=>ERROR;
drive.outSh  ← DriveName[drive, outSh];
drives ← CONS[drive, drives];
ENDLOOP};
NormalFormatNames
name  #NIL
nameInv =NIL <=> dual FALSE
NotFoo becomes Foo with inverted=TRUE
LatchPh: PUBLIC PROC[ph: Ph] RETURNS[latch: Ph] = {
latch ← SELECT ph FROM
A, AB, ABB, ABBB, Bc  => A,
B, BA, BAA, BAAA, Ac => B,
ENDCASE => unk};
Driver Configurations generated by SpecificDrive
                        polarities
             Input  > clk Ouput  in ref out
Core To Control or Core To Pad (input) 
Positive          inv   >    inv  pos inv pos
Negative          inv-inv  >    inv  inv inv pos
Control To Core or Pad To Core (output) 
Positive  UnClocked     inv   > pos  inv  pos inv pos
Negative  UnClocked     inv   > inv  inv  inv pos pos
Positive  Clocked      inv-inv  > invClk inv  pos pos pos
Negative  Clocked      inv   > invClk inv  pos inv pos
SpecificDrive: PUBLIC PROC[dir: Dir, in: ROPE, out: ROPE, inverted, dual: BOOL ← FALSE]
RETURNS[dr: IFUCoreDrive.Drive] = {
sigIn:  CoreName.SigRec ← CoreName.NameSig[in];
sigOut: CoreName.SigRec ← CoreName.NameSig[out];
clocked: BOOLSELECT sigOut.ph FROM Ac, Bc=>TRUE, ENDCASE=>FALSE;
dr   ← NEW[ IFUCoreDrive.DriveRec ← [
name:  sigOut.root,
inNm:  in,
drDir:  dir,
gate:  SELECT sigOut.ph FROM Ac=>negAc, Bc=>negBc, ENDCASE=>pos,
idx:  sigOut.idx,
cy:  sigOut.cy,
dualOut: dual,
in:   [ph:    sigIn.ph  ],
ref:  [ph: LatchPh[ sigOut.ph ] ],
out:  [ph:    sigOut.ph, pol: pos ] ]];
IF dr.ref.ph=unk THEN RETURN[dr];
SELECT dir FROM
in  => IF ~inverted
THEN        {dr.in.pol ← pos;  dr.ref.pol ← neg}
ELSE        {dr.in.pol ← neg; dr.ref.pol ← neg};
out => SELECT TRUE FROM
~inverted AND ~clocked => {dr.in.pol ← pos;  dr.ref.pol ← neg; dr.gate ← pos};
inverted AND ~clocked => {dr.in.pol ← neg; dr.ref.pol ← pos; dr.gate ← neg};
~inverted AND  clocked => {dr.in.pol ← pos;  dr.ref.pol ← pos};
inverted AND  clocked => {dr.in.pol ← pos;  dr.ref.pol ← neg};
ENDCASE => ERROR;
ENDCASE};
AdjustDriveOutPh: PUBLIC PROC[drives: Drives, names: ROPE] = {
ris: IO.STREAMIO.RIS[names];
DO
drive:  Drive;
signal: CoreName.SigRec;
item:  ROPE ← ris.GetTokenRope[! IO.EndOfStream => EXIT].token;
signal ← CoreName.NameSig[item];
drive ← FindSignalDrive[signal, drives];
drive.ref.ph ← unk;
drive.out.ph ← unk;
ENDLOOP;
ris ← IO.RIS[names];
DO
drive:  Drive;
signal: CoreName.SigRec;
item:  ROPE ← ris.GetTokenRope[! IO.EndOfStream => EXIT].token;
signal ← CoreName.NameSig[item];
drive ← FindSignalDrive[signal, drives];
IF signal.not THEN drive.dualOut ← TRUE;
drive.idx ← signal.idx;
drive.cy ← signal.cy;
IF drive.ref.ph#unk AND drive.ref.ph#LatchPh[signal.ph] THEN Signal[];
IF drive.out.ph#unk AND drive.out.ph#signal.ph    THEN Signal[];
drive.ref.ph ← LatchPh[signal.ph];
drive.out.ph ← signal.ph;
ENDLOOP};
FindSignalDrive: PROC[sig: CoreName.SigRec, drives: Drives]
RETURNS[drive: Drive] = {
FOR drives ← drives, drives.rest WHILE drives # NIL DO
IF drives.first.name = sig.root THEN {
IF drives.first.cy#-1 AND drives.first.cy#sig.cy  THEN LOOP;
IF drives.first.idx#-1 AND drives.first.idx#sig.idx THEN LOOP;
RETURN[drives.first]};
IF drives.first.nameInv = sig.root THEN {
IF drives.first.cy#-1 AND drives.first.cy#sig.cy  THEN LOOP;
IF drives.first.idx#-1 AND drives.first.idx#sig.idx THEN LOOP;
RETURN[drives.first]};
ENDLOOP;
drive ← NIL; Signal[]};
ConnectDrives: PUBLIC PROC [drives: Drives, inSh: ROPENIL] RETURNS[outSh: ROPE] = {
outShinSh;
FOR list: Drives ← drives, list.rest WHILE list#NIL DO
list.first.inSh  ← IF outSh#NIL      THEN outSh   ELSE list.first.inSh;
list.first.outSh ← IF list.first.drRowType#conn THEN list.first.inSh ELSE list.first.outSh;
outSh    ← list.first.outSh;
ENDLOOP};
DrivesToFrame: PUBLIC PROC [name: ROPE, drives: Drives]
RETURNS[cell: CellType]= {
cnt:   INT ← 0;
frame:  CoreFrame.Frame;
FOR list: Drives ← drives, list.rest WHILE list#NIL DO cnt ← cnt+1 ENDLOOP;
cell  ← CoreFrame.NewFrameCell[cnt, name, [first: bottom]];
frame  ← CoreFrame.FCT[cell];
FOR bit: INT IN [0..cnt) DO
frame.seq[bit] ← CellProc[DriveName[drives.first, out], drives.first];
drives ← drives.rest ENDLOOP};
DriveName: PUBLIC PROC[drive: Drive, type: DrNmType ← unk] RETURNS[ name: ROPE] = {
relSig: CoreName.RelativeSignal;
inv: BOOLSELECT type FROM nin, nref, nout, ninSh, noutSh=>TRUE, ENDCASE=>FALSE;
IF type=unk THEN type ← IF drive.drDir=in THEN in ELSE out;
SELECT type FROM
inSh  => RETURN[drive.inSh];
outSh  => RETURN[CoreName.RopeNm[Rope.Cat["drShOut", DriveName[drive, nref]]]];
ninSh  => Signal[]; -- {RETURN[Rope.Cat["Not", drive.inSh]]};
noutSh => Signal[]; -- {RETURN[Rope.Cat["Not", drive.outSh]]};
in   => {IF drive.inNm#NIL THEN RETURN[drive.inNm];  relSig ← drive.in};
nin  => {IF drive.inNm#NIL THEN Signal[];     relSig ← drive.in};
ref, nref => relSig ← drive.ref;
out, nout => relSig ← drive.out;
ENDCASE => ERROR;
IF drive.drRowType#conn
THEN name ← DrRope[drive]
ELSE {
[inv, name] ← CoreName.SelectName[(relSig.pol=neg)#inv, drive.name, drive.nameInv];
name ← CoreName.SigName[[inv, name, relSig.ph, drive.cy, drive.idx]]};
name ← CoreName.RopeNm[name]};
FindDrive: PUBLIC PROC[drives: Drives, name: ROPE] RETURNS[drive: Drive] = {
FOR drives ← drives, drives.rest WHILE drives # NIL DO
driveNm: ROPEDriveName[drives.first];
IF Rope.Equal[name, DriveName[drives.first]] THEN RETURN[drives.first] ENDLOOP;
RETURN[NIL]};
ReverseDrives: PUBLIC PROC[drives: Drives] RETURNS[new: Drives] = {
FOR drives ← drives, drives.rest WHILE drives#NIL DO
new ← CONS[drives.first, new] ENDLOOP};
AddDrive: PUBLIC PROC[drive: Drive, drives: Drives] RETURNS[new: Drives] = {
found: BOOLFALSE;
name:  ROPEIF drive.name # NIL THEN drive.name ELSE drive.nameInv;
FOR drives ← drives, drives.rest WHILE drives # NIL DO
new ← CONS[drives.first, new];
IF Rope.Equal[name, drives.first.name] OR Rope.Equal[name, drives.first.nameInv] THEN
{new ← CONS[drive, new]; found ← TRUE} ENDLOOP;
IF NOT found THEN new ← CONS[drive, new];
new ← ReverseDrives[new]};
ReplaceDrive: PUBLIC PROC[drive: Drive, drives: Drives] RETURNS[new: Drives] = {
found: BOOLFALSE;
name:  ROPEIF drive.name # NIL THEN drive.name ELSE drive.nameInv;
FOR drives ← drives, drives.rest WHILE drives # NIL DO
IF Rope.Equal[name, drives.first.name] OR Rope.Equal[name, drives.first.nameInv]
THEN {new ← CONS[drive,  new]; found ← TRUE}
ELSE {new ← CONS[drives.first, new]} ENDLOOP;
IF NOT found THEN Signal[];
new ← ReverseDrives[new]};
DelDrive: PUBLIC PROC[drive: Drive, drives: Drives] RETURNS [new: Drives] = {
found: BOOLFALSE;
name:  ROPEIF drive.name # NIL THEN drive.name ELSE drive.nameInv;
FOR drives ← drives, drives.rest WHILE drives # NIL DO
IF Rope.Equal[name, drives.first.name] OR Rope.Equal[name, drives.first.nameInv]
THEN found ← TRUE
ELSE new ← CONS[drives.first, new] ENDLOOP;
IF NOT found THEN Signal[];
new ← ReverseDrives[new]};
log: IO.STREAM ← CoreFrame.GetLog[];
TestProc: PROC[name: ROPE] = {
cellName: ROPE  ← "Testee";
refRec: REF  ← name;
initial: DriveRec ← [
name:   NIL,
nameInv:  NIL,
drDir:   in,
gate:   pos,
dualOut:  FALSE,
inSh:   "testShDataIn",
in:    [pol: pos, ph: A, cycle: 0],
ref:   [pol: pos, ph: A, cycle: 0],
out:   [pol: pos, ph: AB, cycle: 0],
pass:   FALSE,
plaType:  static,
drRowType: conn ];
cell: CellType ← RefToDriverFrame[cellName, refRec, initial].cell;
CoreFrame.Expand[cell];
[ ] ← CoreConnect.Connect[cell];
cell  ← CoreOps.Recast[cell];
CoreOps.PrintCellType[cell, log];
[ ] ← PW.Draw[PWCore.Layout[cell]] };
TestProc[ "Test.TestRec" ];
END.