XilinxIOImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Barth, July 20, 1989 5:49:40 pm PDT
Last Edited by: Gasbarro July 18, 1989 6:23:49 pm PDT
DIRECTORY Core, CoreFlat, CoreOps, CoreProperties, FS, RefTab, SymTab, IO, Rope, XilinxIO;
XilinxIOImpl: CEDAR PROGRAM
IMPORTS CoreFlat, CoreOps, CoreProperties, FS, RefTab, SymTab, IO, Rope
EXPORTS XilinxIO
= BEGIN OPEN XilinxIO;
Types and Globals
ROPE: TYPE = Rope.ROPE;
LOR: TYPE = LIST OF ROPE;
BindList: TYPE = LIST OF RECORD[wire: Core.Wire, name: ROPE];
Primitive Data Base
primitives: SymTab.Ref ← SymTab.Create[]; -- cell type name to Primitive
Primitive: TYPE = REF PrimitiveRec;
PrimitiveRec: TYPE = RECORD [
translate: TranslateProc,
data: REF ANY];
TranslateProc: TYPE = PROC [circuit: FlatCircuit, root, cell: Core.CellType, name: ROPE, flatCell: CoreFlat.FlatCellTypeRec, flatWireToSignal, bindings: RefTab.Ref, part2000: BOOL, data: REF ANY];
Pins: TYPE = LIST OF Pin;
PinRecList: TYPE = LIST OF PinRec;
Pin: TYPE = REF PinRec;
PinRec: TYPE = RECORD [
coreName: ROPE,
xilinxName: ROPE,
direction: InOrOut,
physicalPin: BOOLFALSE,
tristate: BOOLFALSE];
InOrOut: TYPE = {In, Out};
directionNames: ARRAY InOrOut OF ROPE ← ["I", "O"];
Flattened Circuit
FlatCircuit: TYPE = REF FlatCircuitRec;
FlatCircuitRec: TYPE = RECORD [
symbols: Symbols ← NIL,
signals: Signals ← NIL,
partType: ROPENIL];
Symbols: TYPE = LIST OF Symbol;
Symbol: TYPE = REF SymbolRec;
SymbolRec: TYPE = RECORD [
name: ROPENIL,
type: ROPENIL,
connections: SymbolSignalPins ← NIL,
parameters: LORNIL,
configs: LORNIL];
SymbolSignalPins: TYPE = LIST OF SymbolSignalPin;
SymbolSignalPin: TYPE = REF SymbolSignalPinRec;
SymbolSignalPinRec: TYPE = RECORD [
symbol: Symbol ← NIL,
signal: Signal ← NIL,
pin: Pin ← NIL,
parameters: LORNIL];
Signals: TYPE = LIST OF Signal;
Signal: TYPE = REF SignalRec;
SignalRec: TYPE = RECORD [
name: ROPENIL,
connections: SymbolSignalPins ← NIL,
pin: REF INTNIL, -- NIL => not forced
unbonded: BOOLFALSE,
parameters: LORNIL];
some connections' pin.physicalPin = TRUE causes an EXT record to be emitted using unbonded, pin, and parameters
all connections' pin.physicalPin = FALSE and parameters#NIL causes a SIG record to be emitted
Functions
SaveCellType: PUBLIC PROC [cellType: Core.CellType, fileName: ROPENIL] RETURNS [multiplyDriven: LORNIL] = {
circuit: FlatCircuit ← FlattenCircuit[cellType];
pruned: RefTab.Ref ← PruneFlattenedCircuit[circuit];
multiplyDriven ← CheckMultipleDrivers[circuit];
IF fileName=NIL THEN fileName ← Rope.Cat[CoreOps.GetCellTypeName[cellType], ".xnf"];
WriteFlattenedCircuit[circuit, pruned, fileName];
};
FlattenCircuit: PROC [cellType: Core.CellType] RETURNS [circuit: FlatCircuit] = {
FlattenCellType: CoreFlat.BoundFlatCellProc = {
name: ROPE ← CoreOps.GetCellTypeName[cell];
primitive: Primitive ← NARROW[SymTab.Fetch[primitives, name].val];
IF primitive=NIL THEN CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, FlattenCellType]
ELSE primitive.translate[circuit, cellType, cell, name, flatCell, flatWireToSignal, bindings, part2000, primitive.data];
};
flatWireToSignal: RefTab.Ref ← RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
part2000: BOOLFALSE;
circuit ← NEW[FlatCircuitRec];
circuit.partType ← NARROW[CoreProperties.InheritCellTypeProp[cellType, $XilinxPartType]];
IF circuit.partType=NIL THEN circuit.partType ← "2064PC68-33";
part2000 ← Rope.Fetch[circuit.partType]='2;
FlattenCellType[cell: cellType, bindings: CoreFlat.InitialBindingTable[cellType]];
};
PruneFlattenedCircuit: PROC [circuit: FlatCircuit] RETURNS [pruned: RefTab.Ref] = {
CheckSignal: RefTab.EachPairAction = {
signal: Signal ← NARROW[key];
sensed, physical: BOOLFALSE;
IF RefTab.Fetch[pruned, signal].found THEN RETURN;
[sensed, physical] ← SensedPhysicalDrivenTristate[signal, pruned];
IF NOT sensed AND (signal.unbonded OR NOT physical) THEN {
IF NOT RefTab.Insert[pruned, signal, signal] THEN ERROR;
FOR cl: SymbolSignalPins ← signal.connections, cl.rest UNTIL cl=NIL DO
ssp: SymbolSignalPin ← cl.first;
IF ssp.pin.direction=Out THEN IF NOT RefTab.Insert[pruned, ssp, ssp] THEN ERROR;
[] ← RefTab.Insert[symbolCheck, ssp.symbol, ssp.symbol];
ENDLOOP;
};
};
CheckSymbol: RefTab.EachPairAction = {
symbol: Symbol ← NARROW[key];
IF RefTab.Fetch[pruned, symbol].found THEN RETURN;
FOR cl: SymbolSignalPins ← symbol.connections, cl.rest UNTIL cl=NIL DO
ssp: SymbolSignalPin ← cl.first;
IF ssp.pin.direction=Out AND NOT RefTab.Fetch[pruned, ssp].found THEN RETURN;
ENDLOOP;
IF NOT RefTab.Insert[pruned, symbol, symbol] THEN ERROR;
FOR cl: SymbolSignalPins ← symbol.connections, cl.rest UNTIL cl=NIL DO
ssp: SymbolSignalPin ← cl.first;
IF ssp.pin.direction=In THEN IF NOT RefTab.Insert[pruned, ssp, ssp] THEN ERROR;
[] ← RefTab.Insert[signalCheck, ssp.signal, ssp.signal];
ENDLOOP;
};
signalCheck: RefTab.Ref ← RefTab.Create[];
symbolCheck: RefTab.Ref ← RefTab.Create[];
pruned ← RefTab.Create[];
FOR sl: Signals ← circuit.signals, sl.rest UNTIL sl=NIL DO
IF NOT RefTab.Insert[signalCheck, sl.first, sl.first] THEN ERROR;
ENDLOOP;
UNTIL RefTab.GetSize[symbolCheck]=0 AND RefTab.GetSize[signalCheck]=0 DO
[] ← RefTab.Pairs[signalCheck, CheckSignal];
RefTab.Erase[signalCheck];
[] ← RefTab.Pairs[symbolCheck, CheckSymbol];
RefTab.Erase[symbolCheck];
ENDLOOP;
};
CheckMultipleDrivers: PROC [circuit: FlatCircuit] RETURNS [names: LORNIL]= {
Driven: TYPE = {Never, Always, Tristate};
FOR sl: Signals ← circuit.signals, sl.rest UNTIL sl=NIL DO
driven: Driven ← Never;
FOR cl: SymbolSignalPins ← sl.first.connections, cl.rest UNTIL cl=NIL DO
ssp: SymbolSignalPin ← cl.first;
IF ssp.pin.direction=Out THEN {
IF driven=Always OR (driven=Tristate AND NOT ssp.pin.tristate) THEN {
names ← CONS[sl.first.name, names];
EXIT;
};
driven ← IF ssp.pin.tristate THEN Tristate ELSE Always;
};
ENDLOOP;
ENDLOOP;
};
WriteFlattenedCircuit: PROC [circuit: FlatCircuit, pruned: RefTab.Ref, fileName: ROPE] = {
WriteRecord: PROC [record: ROPE, parameters: LORNIL] = {
FOR rl: LOR ← parameters, rl.rest UNTIL rl=NIL DO
record ← Rope.Cat[record, ",", rl.first];
ENDLOOP;
IF Rope.Length[record]>=253 THEN ERROR;
IO.PutF[stream, "%g\n", IO.rope[record]];
};
stream: IO.STREAMFS.StreamOpen[fileName, $create];
WriteRecord["LCANET,1"];
WriteRecord[IO.PutFR["PROG,Core2XNF,1,%g", IO.time[]]];
WriteRecord[Rope.Cat["PART,", circuit.partType]];
FOR sl: Symbols ← circuit.symbols, sl.rest UNTIL sl=NIL DO
symbol: Symbol ← sl.first;
IF NOT RefTab.Fetch[pruned, symbol].found THEN {
WriteRecord[IO.PutFR["SYM,%g,%g", IO.rope[symbol.name], IO.rope[symbol.type]], symbol.parameters];
FOR cl: SymbolSignalPins ← symbol.connections, cl.rest UNTIL cl=NIL DO
ssp: SymbolSignalPin ← cl.first;
pinRecord: ROPEIO.PutFR["PIN,%g,%g,%g", IO.rope[ssp.pin.xilinxName], IO.rope[directionNames[ssp.pin.direction]], IO.rope[ssp.signal.name]];
IF ssp.parameters#NIL THEN pinRecord ← Rope.Cat[pinRecord, ","];
WriteRecord[pinRecord, ssp.parameters];
ENDLOOP;
FOR rl: LOR ← symbol.configs, rl.rest UNTIL rl=NIL DO
WriteRecord[Rope.Cat["CFG,", rl.first]];
ENDLOOP;
WriteRecord["END"];
};
ENDLOOP;
WriteRecord["PWR,1,public-$Vdd"];
WriteRecord["PWR,0,public-$Gnd"];
FOR sl: Signals ← circuit.signals, sl.rest UNTIL sl=NIL DO
signal: Signal ← sl.first;
sensed, physical, driven, tristate: BOOLFALSE;
[sensed, physical, driven, tristate] ← SensedPhysicalDrivenTristate[signal, pruned];
IF physical OR signal.parameters#NIL THEN {
signalRecord: ROPEIF physical THEN "EXT," ELSE "SIG,";
signalRecord ← Rope.Cat[signalRecord, signal.name];
IF physical THEN {
signalRecord ← Rope.Cat[signalRecord, SELECT TRUE FROM
signal.unbonded => ",U",
driven AND sensed => ",B",
driven AND tristate => ",T",
driven => ",O",
sensed => ",I",
ENDCASE => ERROR];
IF signal.pin#NIL OR signal.parameters#NIL THEN signalRecord ← Rope.Cat[signalRecord, SELECT TRUE FROM
signal.pin#NIL => IO.PutFR[",%g", IO.int[signal.pin^]],
signal.parameters#NIL => ",",
ENDCASE => ERROR];
};
WriteRecord[signalRecord, signal.parameters];
};
ENDLOOP;
WriteRecord["EOF"];
IO.Close[stream];
};
Simple
SimpleData: TYPE = REF SimpleDataRec;
SimpleDataRec: TYPE = RECORD [
xilinxType: ROPE,
pins: Pins];
RegisterSimplePrimitive: PROC [coreName: ROPE, xilinxType: ROPE, pins: PinRecList, aliases: LORNIL] = {
simpleData: SimpleData ← NEW[SimpleDataRec ← [
xilinxType: xilinxType,
pins: PinRecListToPinList[pins]]];
RegisterPrimitive[coreName, FlattenSimplePrimitive, simpleData];
FOR al: LOR ← aliases, al.rest UNTIL al=NIL DO
RegisterPrimitive[al.first, FlattenSimplePrimitive, simpleData];
ENDLOOP;
};
FlattenSimplePrimitive: TranslateProc = {
simpleData: SimpleData ← NARROW[data];
MakeSymbol[CoreFlat.CellTypePathRope[root, flatCell], simpleData.xilinxType, MakeBindList[cell.public], simpleData.pins, circuit, root, flatCell, flatWireToSignal, bindings];
};
CLB
CLBData: TYPE = REF CLBDataRec;
CLBDataRec: TYPE = RECORD [
config: ROPE,
equate: ROPE];
clbPins: Pins ← PinRecListToPinList[LIST[
["A", "A", In],
["B", "B", In],
["C", "C", In],
["D", "D", In],
["X", "X", Out]]];
RegisterCLBPrimitive: PROC [coreName: ROPE, config: ROPE, equate: ROPE] = {
clbData: CLBData ← NEW[CLBDataRec ← [
config: config,
equate: equate]];
RegisterPrimitive[coreName, FlattenCLBPrimitive, clbData];
};
FlattenCLBPrimitive: TranslateProc = {
clbData: CLBData ← NARROW[data];
configs: LORLIST[Rope.Cat["EQUATE F=", clbData.equate]];
configs ← CONS[Rope.Cat["CONFIG X:F F:", clbData.config], configs];
configs ← CONS[Rope.Cat["BASE ", IF part2000 THEN "F" ELSE "FG"], configs];
MakeSymbol[CoreFlat.CellTypePathRope[root, flatCell], "CLB", MakeBindList[cell.public], clbPins, circuit, root, flatCell, flatWireToSignal, bindings, NIL, configs];
};
Flop
flopPins: Pins ← PinRecListToPinList[LIST[
["D", "D", In],
["CK", "C", In],
["Q", "Q", Out]]];
invPins: Pins ← PinRecListToPinList[LIST[
["I", "I", In],
["X", "O", Out]]];
FlattenFlopPrimitive: TranslateProc = {
flatName: ROPE ← CoreFlat.CellTypePathRope[root, flatCell];
d: Core.Wire ← CoreOps.FindWire[cell.public, "D"];
c: Core.Wire ← CoreOps.FindWire[cell.public, "CK"];
q: Core.Wire ← CoreOps.FindWire[cell.public, "Q"];
nq: Core.Wire ← CoreOps.FindWire[cell.public, "NQ"];
MakeSymbol[flatName, "DFF", LIST[[d, "D"], [c, "CK"], [q, "Q"]], flopPins, circuit, root, flatCell, flatWireToSignal, bindings];
MakeSymbol[Rope.Cat[flatName, "ManufacturedInverter"], "INV", LIST[[q, "I"], [nq, "X"]], invPins, circuit, root, flatCell, flatWireToSignal, bindings];
};
SymDriver
symPins: Pins ← PinRecListToPinList[LIST[
["I", "I", In],
["X", "O", Out]]];
FlattenSymDriverPrimitive: TranslateProc = {
flatName: ROPE ← CoreFlat.CellTypePathRope[root, flatCell];
i: Core.Wire ← CoreOps.FindWire[cell.public, "I"];
x: Core.Wire ← CoreOps.FindWire[cell.public, "X"];
nx: Core.Wire ← CoreOps.FindWire[cell.public, "nX"];
MakeSymbol[Rope.Cat[flatName, "ManufacturedBuffer"], "BUF", LIST[[i, "I"], [x, "X"]], symPins, circuit, root, flatCell, flatWireToSignal, bindings];
MakeSymbol[Rope.Cat[flatName, "ManufacturedInverter"], "INV", LIST[[i, "I"], [nx, "X"]], symPins, circuit, root, flatCell, flatWireToSignal, bindings];
};
Utilities
RegisterPrimitive: PROC [coreName: ROPE, proc: TranslateProc, data: REF ANYNIL] = {
primitive: Primitive ← NEW[PrimitiveRec ← [
translate: proc,
data: data]];
IF NOT SymTab.Insert[primitives, coreName, primitive] THEN ERROR;
};
PinRecListToPinList: PROC [pins: PinRecList] RETURNS [refPins: Pins ← NIL] = {
FOR pl: PinRecList ← pins, pl.rest UNTIL pl=NIL DO
refPins ← CONS[NEW[PinRec ← pl.first], refPins];
ENDLOOP;
};
MakeBindList: PROC [public: Core.Wire] RETURNS [bindlist: BindList ← NIL] = {
MakeBind: PROC [wire: Core.Wire] = {
coreName: ROPE ← CoreOps.GetFullWireName[public, wire];
IF NOT GlobalDelete[coreName] THEN bindlist ← CONS[[wire, coreName], bindlist];
};
CoreOps.VisitRootAtomics[public, MakeBind];
};
MakeSymbol: PROC [name, type: ROPE, bind: BindList, pins: Pins, circuit: FlatCircuit, root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec, flatWireToSignal, bindings: RefTab.Ref, parameters, configs: LORNIL] = {
symbol: Symbol ← NEW[SymbolRec];
symbol.name ← name;
symbol.type ← type;
symbol.parameters ← parameters;
symbol.configs ← configs;
circuit.symbols ← CONS[symbol, circuit.symbols];
FOR bl: BindList ← bind, bl.rest UNTIL bl=NIL DO
IF NOT GlobalDelete[bl.first.name] THEN FOR pl: Pins ← pins, pl.rest UNTIL pl=NIL DO
IF Rope.Equal[pl.first.coreName, bl.first.name] THEN {
ssp: SymbolSignalPin ← NEW[SymbolSignalPinRec];
flatWire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[bindings, bl.first.wire].val];
signal: Signal ← NARROW[RefTab.Fetch[flatWireToSignal, flatWire].val];
IF flatWire=NIL THEN ERROR;
IF signal=NIL THEN {
signal ← NEW[SignalRec];
IF NOT RefTab.Insert[flatWireToSignal, NEW[CoreFlat.FlatWireRec ← flatWire^], signal] THEN ERROR;
signal.name ← SignalName[root, flatWire];
circuit.signals ← CONS[signal, circuit.signals];
};
ssp.symbol ← symbol;
ssp.signal ← signal;
ssp.pin ← pl.first;
symbol.connections ← CONS[ssp, symbol.connections];
signal.connections ← CONS[ssp, signal.connections];
EXIT;
};
REPEAT FINISHED => ERROR;
ENDLOOP;
ENDLOOP;
};
GlobalDelete: PROC [name: ROPE] RETURNS [yes: BOOLFALSE] = {
yes ← Rope.Equal[name, "Vdd"] OR Rope.Equal[name, "Gnd"] OR Rope.Equal[name, "RosemaryLogicTime"];
};
nameCount: INT ← 0;
SignalName: PROC [cellType: Core.CellType, flatWire: CoreFlat.FlatWire] RETURNS [name: ROPENIL] = {
CoreFlat uses Letter Digit / ( ) [ ] . *
LCA allows Letter Digit $ — - < > /
but / is reserved for path names and names are case insensitive
BuildNew: Rope.ActionType = {
c ← SELECT c FROM
'/ => '$,
'(, '[ => '<,
'), '] => '>,
'. => '-,
'* => '←,
ENDCASE => c;
IF c IN ['A..'Z] THEN name ← Rope.Concat[name, "$"];
name ← Rope.Concat[name, Rope.FromChar[c]];
};
old: ROPE ← CoreFlat.WirePathRope[cellType, flatWire^];
[] ← Rope.Map[base: old, action: BuildNew];
shortName: ROPE ← CoreOps.GetShortWireName[flatWire.wire];
SELECT TRUE FROM
Rope.Equal[shortName, "Vdd"] => name ← "public-$Vdd";
Rope.Equal[shortName, "Gnd"] => name ← "public-$Gnd";
ENDCASE => {
name ← IO.PutFR["N%g", IO.int[nameCount]];
nameCount ← nameCount + 1;
};
};
SensedPhysicalDrivenTristate: PROC [signal: Signal, pruned: RefTab.Ref] RETURNS [sensed, physical, driven, tristate: BOOLFALSE] = {
FOR cl: SymbolSignalPins ← signal.connections, cl.rest UNTIL cl=NIL DO
ssp: SymbolSignalPin ← cl.first;
IF NOT RefTab.Fetch[pruned, ssp].found THEN {
sensed ← sensed OR ssp.pin.direction=In;
physical ← physical OR ssp.pin.physicalPin;
driven ← driven OR ssp.pin.direction=Out;
tristate ← tristate OR ssp.pin.tristate;
};
ENDLOOP;
};
Registration
Really should load the primitive definitions by scanning a cell in Xilinx.dale
I/O Symbols
RegisterSimplePrimitive["IBuf", "IBUF", LIST[
["I", "I", In, TRUE],
["X", "O", Out]]];
RegisterSimplePrimitive["OBuf", "OBUF", LIST[
["I", "I", In],
["X", "O", Out, TRUE]]];
RegisterSimplePrimitive["OBufZ", "OBUFZ", LIST[
["I", "I", In],
["EN", "T", In],
["X", "O", Out, TRUE, TRUE]]];
RegisterSimplePrimitive["OutFF", "OUTFF", LIST[
["D", "D", In],
["CK", "C", In],
["Q", "Q", Out, TRUE]]];
RegisterSimplePrimitive["OutFFZ", "OUTFFZ", LIST[
["D", "D", In],
["EN", "T", In],
["CK", "C", In],
["Q", "Q", Out, TRUE, TRUE]]];
RegisterSimplePrimitive["InFF", "INFF", LIST[
["D", "D", In, TRUE],
["CK", "C", In],
["Q", "Q", Out]]];
RegisterSimplePrimitive["InLatch", "INLATCH", LIST[
["D", "D", In, TRUE],
["E", "E", In],
["X", "O", In],
["Q", "Q", Out]]];
Inverters, Buffers
RegisterSimplePrimitive["inv", "INV", LIST[
["I", "I", In],
["X", "O", Out]], LIST["invP", "invB", "invPB", "invBuffer", "invDriver"]];
RegisterSimplePrimitive["driver", "BUF", LIST[
["I", "I", In],
["X", "O", Out]]];
RegisterPrimitive["symDriver", FlattenSymDriverPrimitive, NIL];
RegisterSimplePrimitive["3BufferNI", "TBUF", LIST[
["I", "I", In],
["EN", "T", In],
["X", "O", Out, FALSE, TRUE]]];
RegisterSimplePrimitive["AClk", "ACLK", LIST[
["I", "I", In],
["X", "O", Out]]];
RegisterSimplePrimitive["GClk", "GCLK", LIST[
["I", "I", In],
["X", "O", Out]]];
Gates: 2, 3, and 4 input
RegisterSimplePrimitive["and2", "AND", LIST[
["I-A", "1", In],
["I-B", "2", In],
["X", "O", Out]]];
RegisterSimplePrimitive["and3", "AND", LIST[
["I-A", "1", In],
["I-B", "2", In],
["I-C", "3", In],
["X", "O", Out]]];
RegisterSimplePrimitive["and4", "AND", LIST[
["I-A", "1", In],
["I-B", "2", In],
["I-C", "3", In],
["I-D", "4", In],
["X", "O", Out]]];
RegisterSimplePrimitive["or2", "OR", LIST[
["I-A", "1", In],
["I-B", "2", In],
["X", "O", Out]]];
RegisterSimplePrimitive["or3", "OR", LIST[
["I-A", "1", In],
["I-B", "2", In],
["I-C", "3", In],
["X", "O", Out]]];
RegisterSimplePrimitive["or4", "OR", LIST[
["I-A", "1", In],
["I-B", "2", In],
["I-C", "3", In],
["I-D", "4", In],
["X", "O", Out]]];
RegisterSimplePrimitive["nand2", "NAND", LIST[
["I-A", "1", In],
["I-B", "2", In],
["X", "O", Out]]];
RegisterSimplePrimitive["nand3", "NAND", LIST[
["I-A", "1", In],
["I-B", "2", In],
["I-C", "3", In],
["X", "O", Out]]];
RegisterSimplePrimitive["nand4", "NAND", LIST[
["I-A", "1", In],
["I-B", "2", In],
["I-C", "3", In],
["I-D", "4", In],
["X", "O", Out]]];
RegisterSimplePrimitive["nor2", "NOR", LIST[
["I-A", "1", In],
["I-B", "2", In],
["X", "O", Out]]];
RegisterSimplePrimitive["nor3", "NOR", LIST[
["I-A", "1", In],
["I-B", "2", In],
["I-C", "3", In],
["X", "O", Out]]];
RegisterSimplePrimitive["nor4", "NOR", LIST[
["I-A", "1", In],
["I-B", "2", In],
["I-C", "3", In],
["I-D", "4", In],
["X", "O", Out]]];
RegisterSimplePrimitive["xor2", "XOR", LIST[
["I-A", "1", In],
["I-B", "2", In],
["X", "O", Out]]];
RegisterSimplePrimitive["xnor2", "XNOR", LIST[
["I-A", "1", In],
["I-B", "2", In],
["X", "O", Out]]];
Gates, compound
RegisterCLBPrimitive["a22o2iP", "A:B:C:D", "~((A*B)+(C*D))"];
RegisterCLBPrimitive["a22o2i", "A:B:C:D", "~((A*B)+(C*D))"];
RegisterCLBPrimitive["o22a2iP", "A:B:C:D", "~((A+B)*(C+D))"];
RegisterCLBPrimitive["o22a2i", "A:B:C:D", "~((A+B)*(C+D))"];
RegisterCLBPrimitive["a21o2i", "A:B:C", "~((A*B)+C)"];
RegisterCLBPrimitive["o21a2i", "A:B:C", "~((A+B)*C)"];
Flops
RegisterSimplePrimitive["DFF", "DFF", LIST[
["D", "D", In],
["ap", "SD", In],
["ar", "RD", In],
["CK", "C", In],
["Q", "Q", Out]]];
RegisterSimplePrimitive["ffAR", "DFF", LIST[
["D", "D", In],
["r", "RD", In],
["CK", "C", In],
["Q", "Q", Out]]];
RegisterPrimitive["ff", FlattenFlopPrimitive, NIL];
Misc.
RegisterSimplePrimitive["pullUp", "PULLUP", LIST[
["out", "O", Out, FALSE, FALSE]]];
RegisterSimplePrimitive["Osc", "OSC", LIST[
["X", "O", Out]]];
END.