-- A barrel shifter; two inputs (left and st2A), one output (fuOut)
-- sh=0 => out←left; sh=wordSize => out←st2A; shift by zero is on top;
-- The layout is explicit because the shifter is a special type of array not expressible by a Sequence cell (diagonal port is the same on the top and left side).
-- shOut[0..32), sh[0..33), pass, (left, st2A, r2B, cBus, fuOut)[0..32), Vdd, Gnd
CreateBarrelShifter:
PROC []
RETURNS [cellType: CellType] = {
shLine: CellType ← CreateBarrelShifterRow[];
instances: CellInstances ← LIST[Instance[CreateShTop[]]]; -- connect to left
sh: Wire ← Seq["sh", wordSize+1];
shOut: Wire ← Bus["shOut"];
left: Wire ← Bus["left"];
st2A: Wire ← Bus["st2A"];
r2B: Wire ← Bus["r2B"];
cBus: Wire ← Bus["cBus"];
fuOut: Wire ← Bus["fuOut"];
public: Wire ← Wires[shOut, sh, "pass", "Vdd", "Gnd",
left, st2A, r2B, cBus, fuOut];
FOR row:
NAT
IN [0..wordSize+1)
DO
bindings: LIST OF PA ← LIST[["sh", sh[row]], ["shOut", shOut]];
FOR column:
NAT
IN [0..wordSize)
DO
sum: NAT ← row+column;
to: WR ← IF sum<wordSize THEN left[sum] ELSE st2A[sum-wordSize];
bindings ← CONS[[Index["in", column], to], bindings];
ENDLOOP;
IF row<wordSize THEN bindings ← CONS[["pass", st2A[row]], bindings];
instances ← CONS[InstanceList[shLine, bindings], instances];
ENDLOOP;
instances ← CONS[Instance[CreateShBot[]], instances]; -- connect to st2A
cellType ← Cell[
name: "BarrelShifter",
public: public,
instances: instances];
PWCore.SetAbutY[cellType]; -- it is really an array, but we can't use SequenceCell
};
CreateShTop:
PROC
RETURNS [cellType: CellType] ~ {
cellType ← SequenceCell[name: "ShTop",
baseCell: Extract["shLeftConnect.sch" ], count: wordSize,
sequencePorts: Wires["left", "st2A", "r2B", "cBus", "fuOut"]];
PWCore.SetArrayX[cellType];
};
CreateShBot:
PROC
RETURNS [cellType: CellType] ~ {
cellType ← SequenceCell[name: "ShBot",
baseCell: Extract["shRightConnect.sch" ], count: wordSize,
sequencePorts: Wires["shOut", "st2A", "r2B", "cBus", "fuOut"]];
PWCore.SetArrayX[cellType];
};
-- in[0..32), shOut[0..32), sh, pass
CreateBarrelShifterRow:
PROC []
RETURNS [cellType: CellType] = {
shCell: CellType ← Extract["ShifterCell.sch"];
instances: CellInstances ← NIL;
FOR i:
NAT
DECREASING
IN [0..wordSize)
DO
inst: CellInstance ← Instance[shCell,
["sh", "sh"], ["in", Index["in", i]], ["shOut", Index["shOut", i]],
["st2A", Index["st2A", i]], ["r2B", Index["r2B", i]],
["cBus", Index["cBus", i]], ["fuOut", Index["fuOut", i]],
["pass", IF i=wordSize-1 THEN "pass" ELSE Index["in", i+1] ]];
instances ← CONS[inst, instances];
ENDLOOP;
cellType ← Cell[name: "BarrelShifterRow",
public: Wires[Bus["in"], "sh", Bus["shOut"], "pass", "Vdd", "Gnd",
Bus["st2A"], Bus["r2B"], Bus["cBus"], Bus["fuOut"]],
instances: instances];
PWCore.SetAbutX[cellType]; -- it is really an array, but who cares?
};
-- A bit of mask generation theory: let k and i be two n+1-bit numbers, and F[n, k, i]=k>i. By recurring on the high-order bit, we find that
F[n, k, i]=k[n].~i[n]+(k[n]=i[n]).F[n-1, k, i], and for 1-bit numbers F[0, k, i]=k[0].~i[0]
In every slice, i is a constant and k an input. Let's decompose according to the value of i[n]:
i[n]=0: F[0, k, i]=k[0] (use k[0])
F[n, k, i]=k[n] + F[n-1, k, i]=Nand [~k[n], ~F[n-1, k, i]] (NOR to Gnd)
i[n]=1: F[0, k, i]=0 (no transistor)
F[n, k, i]=k[n] . F[n-1, k, i]=Nor [~k[n], ~F[n-1, k, i]] (NAND branch)
-- Note: a NAND branch starting with no tr. still has no tr., i.e. if i=xx0111 then the three bottom transistors are missing!
-- mask[0..6), shift[0..6), (m1, m2, st2A, r2B, cBus, fuOut)[0..32), Vdd, Gnd,
CreateMask:
PROC
RETURNS [cellType: CellType] = {
instances: CellInstances ← NIL;
FOR i: [0..wordSize)
DECREASING
IN [0..wordSize)
DO
instances ←
CONS[
Instance[CreateMasksCell[i],
["m1", Index["m1", i]], ["m2", Index["m2", i]], ["st2A", Index["st2A", i]],
["r2B", Index["r2B", i]], ["cBus", Index["cBus", i]], ["fuOut", Index["fuOut", i]]],
instances];
ENDLOOP;
cellType ← Cell[
name: "Mask",
public: Wires["Vdd", "Gnd", Seq["mask", sizeK], Seq["shift", sizeK],
Bus["m1"], Bus["m2"], Bus["st2A"], Bus["r2B"], Bus["cBus"], Bus["fuOut"]],
instances: instances];
PWCore.SetAbutX[cellType];
};
-- "Vdd", "Gnd", "shift[0..6)", "mask[0..6)", "m1", "m2", "st2A", "r2B", "cBus", "fuOut"
CreateMasksCell:
PROC [pos: [0..wordSize)]
RETURNS [cellType: CellType] = {
m1: CellType ← CreateMaskCell["mask", "m1", 31-pos];
m2: CellType ← CreateMaskCell["shift", "m2", 31-pos];
cellType ← Cell[
name: "Masks",
public: Wires["Vdd", "Gnd", Seq["mask", sizeK], Seq["shift", sizeK], "m1", "m2", "st2A", "r2B", "cBus", "fuOut" ],
instances: LIST[Instance[m2], Instance[m1]]];
PWCore.SetAbutY[cellType];
};
Trits: TYPE = {P, S, F, X};
Pat: TYPE = ARRAY [0..6) OF Trits;
Pattern:
PROC [k:
NAT]
RETURNS [lowToHi: Pat] ~ {
isOne: BOOL ← BitHacks.XthBitOfN[0, k];
lowToHi[0] ← IF isOne THEN X ELSE F;
FOR bit:
NAT
IN [1..6)
DO
isOne ← BitHacks.XthBitOfN[bit, k];
lowToHi[bit] ←
SELECT
TRUE
FROM
isOne AND lowToHi[bit-1]=X => X,
isOne => S,
~isOne AND lowToHi[bit-1]=X => F,
~isOne => P,
ENDCASE => ERROR;
ENDLOOP;
};
-- Using a generator of static gates, program maskOut=F(a, pos)
-- "Vdd", "Gnd", "selName[0..6)", "maskOut"
-- (selName, outName) can be (mask, m1) or (shift, m2);
CreateMaskCell:
PROC [selName, outName:
ROPE, pos: [0..32)]
RETURNS [cellType: CellType] = {
pas: LIST OF CoreCreate.PA ← LIST[["Vdd", "Vdd"], ["m1", "m1"], ["m2", "m2"], ["Gnd", "Gnd"], ["st2A", "st2A"], ["r2B", "r2B"], ["cBus", "cBus"], ["fuOut", "fuOut"]];
POb: CD.Object ← PWCore.Layout[Extract["maskP.sch"]];
SOb: CD.Object ← PWCore.Layout[Extract["maskS.sch"]];
FOb: CD.Object ← PWCore.Layout[Extract["maskF.sch"]];
XOb: CD.Object ← PWCore.Layout[Extract["maskX.sch"]];
botOb: CD.Object ← PWCore.Layout[Extract["maskBot.sch"]];
public: Wire ← Wires["Vdd", "Gnd", Seq[selName, sizeK], "m1", "m2", "st2A", "r2B", "cBus", "fuOut"];
abutInstances:
LIST
OF PWCore.AbutInstance ←
LIST [
[PWCore.Layout[Extract[Rope.Cat[outName, "top.sch"]]], pas]];
lowToHi: Pat ← Pattern[pos];
FOR bit:
NAT
DECREASING
IN [0..6)
DO
ob:
CD.Object ←
SELECT lowToHi[bit]
FROM
X => XOb,
F => FOb,
S => SOb,
P => POb,
ENDCASE => ERROR;
abutInstances ←
CONS [[ob,
CONS[["sel", Index[selName, 5-bit]], pas]],
-- check!!!
abutInstances];
ENDLOOP;
abutInstances ← CONS [[botOb, pas], abutInstances];
cellType ← PWCore.AbutCell[
name: "Mask",
public: public,
abutInstances: abutInstances,
inX: FALSE];
};
CreateMaskCell: PROC [selName, outName: ROPE, pos: [0..32)] RETURNS [cellType: CellType] = {
internalList: LIST OF WR ← NIL;
norBranch: CellType ← Extract["maskGenNor.sch"];
nandBranch: CellType ← Extract["maskGenNand.sch"];
public: Wire ← Wires["Vdd", "Gnd", Seq[selName, sizeK], "m1", "m2", "st2A", "r2B", "cBus", "fuOut"];
instances: CellInstances ← NIL;
new: WR;
currentN: WR ← outName;
currentP: WR ← outName;
instances ← LIST[Instance[Extract[Rope.Cat[outName, "top.sch"]]]];
FOR i: NAT DECREASING IN [0..sizeK) DO
IF BitHacks.XthBitOfN[i, pos] THEN {
IF i>0 THEN {new ← Wires[]; internalList ← CONS[new, internalList]}
ELSE new ← "Vdd";
instances ← CONS[
Instance[norBranch,
["sel", Index[selName, i]], ["n", currentN], ["pHi", currentP], ["pLow", new]],
instances];
}
ELSE {
IF i>0 THEN {new ← Wires[]; internalList ← CONS[new, internalList]}
ELSE new ← "Gnd";
instances ← CONS[
Instance[nandBranch,
["sel", Index[selName, i]], ["p", currentP], ["nHi", currentN], ["nLow", new]],
instances];
};
ENDLOOP;
instances ← CONS[IF BitHacks.XthBitOfN[0, pos]
THEN Instance[Extract["maskGenNorBot.sch"]]
ELSE Instance[Extract["maskGenNandBot.sch"]], instances];
cellType ← Cell[
name: "Mask",
public: public,
onlyInternal: WireList[internalList],
instances: instances];
PWCore.SetAbutY[cellType];
};