XilinxIOImpl:
CEDAR
PROGRAM
IMPORTS Atom, CDCommandOps, CoreCDUser, CoreClasses, CoreFlat, CoreOps, CoreProperties, FS, RefTab, Sisyph, SymTab, TerminalIO, IO, Rope
EXPORTS XilinxIO
SHARES Sisyph
= BEGIN OPEN XilinxIO;
Placement
seqProp: ATOM = $XilinxIOSeqProp;
SeqData: TYPE = REF SeqDataRec;
SeqDataRec:
TYPE =
RECORD [
axis: Axis,
startIndex: NAT,
orthogonalIndex: NAT,
delta: INT];
Loc:
PUBLIC
PROC [cx: Sisyph.Context, x, y:
INT]
RETURNS [trash:
NAT ← 0] = {
SELECT
TRUE
FROM
x>=0 AND y>=0 => Sisyph.AddProp[cx, $ParLoc, IO.PutFR["\"LOC=%g%g\"", IO.char[NumToLet[y]], IO.char[NumToLet[x]]], TRUE];
x<0 AND y<0 => NULL;
ENDCASE => ERROR;
};
Set:
PUBLIC
PROC [cx: Sisyph.Context, x, y:
INT, axis: Axis ← ax]
RETURNS [trash:
NAT ← 0] = {
Sisyph.Store[cx, "x", NEW[INT ← x]];
Sisyph.Store[cx, "y", NEW[INT ← y]];
Sisyph.Store[cx, "axis", NEW[Axis ← axis]];
};
Seq:
PUBLIC
PROC [cx: Sisyph.Context, axis: Axis, startIndex, orthogonalIndex:
NAT, delta:
INT ← 1]
RETURNS [trash:
NAT ← 0] = {
previousProps: Core.Properties ← Sisyph.GetCoreInstProps[cx];
Sisyph.Store[cx, Sisyph.coreInstPropsRope, NEW [Core.Properties ← CoreProperties.PutProp[previousProps, seqProp, NEW[SeqDataRec ← [axis, startIndex, orthogonalIndex, delta]]]]];
};
Functions
SaveCellType:
PUBLIC
PROC [cellType: Core.CellType, fileName:
ROPE ←
NIL]
RETURNS [multiplyDriven:
LOR ←
NIL] = {
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] = {
PushPins: CoreOps.EachWireProc = {
pinList: ROPE ← NARROW[CoreProperties.GetWireProp[wire, $Pins]];
IF pinList#
NIL
THEN {
ris: IO.STREAM ← IO.RIS[pinList];
FOR i:
INT
IN [0..wire.size)
DO
pin: ROPE ← IO.GetCedarTokenRope[ris].token;
currentValue: ROPE ← NARROW[CoreProperties.GetWireProp[wire[i], $Pin]];
IF i#(wire.size-1)
THEN {
kind: IO.TokenKind;
token: IO.ROPE;
[kind, token] ← IO.GetCedarTokenRope[ris];
IF kind#tokenSINGLE OR NOT Rope.Equal[token, ","] THEN ERROR;
};
IF wire[i].size#0 THEN ERROR;
IF currentValue=NIL THEN CoreProperties.PutWireProp[wire[i], $Pin, pin];
ENDLOOP;
};
};
FlattenCellType: CoreFlat.BoundFlatCellProc = {
GetParms: CoreOps.EachWireProc = {
FindParms:
PROC [prop:
ATOM, val:
REF
ANY] = {
propName: ROPE ← Atom.GetPName[prop];
IF Rope.Match["Par*", propName,
FALSE]
THEN {
SetParm:
PROC [wire: Core.Wire] = {
signal: Signal ← CreateBoundSignal[wire, circuit, cellType, flatWireToSignal, bindings, flatCell];
signal.parameters ← CONS[parm, signal.parameters];
};
parm: ROPE ← NARROW[val];
IF wire.size#0 THEN [] ← CoreOps.VisitRootAtomics[wire, SetParm]
ELSE SetParm[wire];
};
};
CoreProperties.Enumerate[wire.properties, FindParms];
};
name: ROPE ← CoreOps.GetCellTypeName[cell];
primitive: Primitive ← NARROW[SymTab.Fetch[primitives, name].val];
clbMapProp: REF BOOL ← NARROW[CoreProperties.GetCellTypeProp[cell, $CLBMap]];
IF clbMapProp#NIL AND clbMapProp^ THEN CreateCLBMap[circuit, cellType, cell, instance, name, flatCell, flatWireToSignal, bindings, part2000, NIL];
IF cell.class=CoreClasses.recordCellClass
THEN {
rct: CoreClasses.RecordCellType ← NARROW[cell.data];
FOR instanceIndex:
NAT
IN [0..rct.size)
DO
seqData: SeqData ← NARROW[CoreProperties.GetCellInstanceProp[rct[instanceIndex], seqProp]];
IF seqData#
NIL
THEN {
child: Core.CellType ← rct[instanceIndex].type;
sct: Sequence.SequenceCellType ← NARROW[child.data];
recast: Core.CellType ← CoreOps.Recast[child];
recastRCT: CoreClasses.RecordCellType ← NARROW[recast.data];
FOR subInstanceIndex:
NAT
IN [0..recastRCT.size)
DO
seqIndex: NAT ← seqData.startIndex + (subInstanceIndex*seqData.delta);
x, y: NAT ← 0;
SELECT seqData.axis
FROM
ax => {x ← seqIndex; y ← seqData.orthogonalIndex};
ay => {x ← seqData.orthogonalIndex; y ← seqIndex};
ENDCASE => ERROR;
CoreProperties.PutCellInstanceProp[recastRCT[subInstanceIndex], $ParLoc, IO.PutFR["LOC=%g%g", IO.char[NumToLet[y]], IO.char[NumToLet[x]]]];
ENDLOOP;
};
ENDLOOP;
[] ← CoreOps.VisitWireSeq[NARROW[cell.data, CoreClasses.RecordCellType].internal, GetParms];
};
IF primitive=NIL THEN CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, FlattenCellType]
ELSE primitive.translate[circuit, cellType, cell, instance, name, flatCell, flatWireToSignal, bindings, part2000, primitive.data];
};
flatWireToSignal: RefTab.Ref ← RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
part2000: BOOL ← FALSE;
circuit ← NEW[FlatCircuitRec];
circuit.nameTable ← SymTab.Create[];
circuit.partType ← NARROW[CoreProperties.InheritCellTypeProp[cellType, $XilinxPartType]];
IF circuit.partType=NIL THEN circuit.partType ← "2064PC68-33";
part2000 ← Rope.Fetch[circuit.partType]='2;
[] ← CoreOps.VisitWire[cellType.public, PushPins];
FlattenCellType[cell: cellType, bindings: CoreFlat.InitialBindingTable[cellType]];
};
clbMapPins: Pins ← PinRecListToPinList[
LIST[
["A", "A", In],
["B", "B", In],
["C", "C", In],
["D", "D", In],
["E", "E", In],
["DI", "DI", In],
["CE", "CE", In],
["K", "K", In],
["RD", "RD", In],
["X", "X", In],
["Y", "Y", In]]];
CreateCLBMap: TranslateProc = {
MakeBind:
PROC [wire: Core.Wire] = {
coreName: ROPE ← NARROW[CoreProperties.GetWireProp[wire, $Pin]];
IF coreName=NIL AND NOT GlobalDelete[CoreOps.GetFullWireName[public, wire]] THEN ERROR;
IF coreName#NIL THEN bindlist ← CONS[[wire, coreName], bindlist];
};
bindlist: BindList ← NIL;
symbol: Symbol ← NIL;
public: Core.Wire ← cell.public;
CoreOps.VisitRootAtomics[public, MakeBind];
symbol ← MakeSymbol[CoreFlat.CellTypePathRope[root, flatCell], "CLBMAP", bindlist, clbMapPins, circuit, root, flatCell, flatWireToSignal, bindings];
GetParameters[symbol, instance];
};
PruneFlattenedCircuit:
PROC [circuit: FlatCircuit]
RETURNS [pruned: RefTab.Ref] = {
CheckSignal: RefTab.EachPairAction = {
signal: Signal ← NARROW[key];
sensed, physical, driven, tristate: BOOL ← FALSE;
IF RefTab.Fetch[pruned, signal].found THEN RETURN;
[sensed, physical, driven, tristate] ← SensedPhysicalDrivenTristate[signal, pruned];
IF (NOT sensed OR NOT (driven OR tristate)) AND (signal.unbonded OR NOT physical) THEN {
IF
NOT sensed
AND (signal.unbonded
OR
NOT physical)
THEN {
IF trace THEN TerminalIO.PutF["\npruning signal: %g", IO.rope[signal.name]];
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 trace THEN TerminalIO.PutF["\npruning symbol: %g", IO.rope[symbol.name]];
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:
LOR ←
NIL]= {
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:
LOR ←
NIL] = {
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.STREAM ← FS.StreamOpen[fileName, $create];
WriteRecord["LCANET,2"];
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;
IF NOT RefTab.Fetch[pruned, ssp.signal].found THEN {
pinRecord: ROPE ← IO.PutFR["PIN,%g,%g,%g", IO.rope[ssp.pin.xilinxName], IO.rope[directionNames[ssp.pin.direction]], IO.rope[ssp.signal.name]];
IF ssp.pin.invert OR ssp.parameters#NIL THEN pinRecord ← Rope.Cat[pinRecord, ","];
IF ssp.pin.invert THEN pinRecord ← Rope.Cat[pinRecord, ",INV"];
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,$Vdd"];
WriteRecord["PWR,0,$Gnd"];
FOR sl: Signals ← circuit.signals, sl.rest
UNTIL sl=
NIL
DO
signal: Signal ← sl.first;
sensed, physical, driven, tristate: BOOL ← FALSE;
[sensed, physical, driven, tristate] ← SensedPhysicalDrivenTristate[signal, pruned];
IF physical
OR signal.parameters#
NIL
THEN {
signalRecord: ROPE ← IF 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[",,LOC=%g%g", IO.rope[IF Rope.Fetch[signal.pin] IN ['0..'9] THEN "P" ELSE NIL], IO.rope[signal.pin]],
signal.parameters#NIL => ",",
ENDCASE => ERROR];
};
WriteRecord[signalRecord, signal.parameters];
};
ENDLOOP;
WriteRecord["EOF"];
IO.Close[stream];
};
Utilities
NumToLet:
PROC [n:
NAT]
RETURNS [l:
CHAR] = {
l ← LOOPHOLE[LOOPHOLE['A, NAT] + n];
};
RegisterPrimitive:
PUBLIC
PROC [coreName:
ROPE, proc: TranslateProc, data:
REF
ANY ←
NIL] = {
primitive: Primitive ←
NEW[PrimitiveRec ← [
translate: proc,
data: data]];
[] ← SymTab.Store[primitives, coreName, primitive];
};
PinRecListToPinList:
PUBLIC
PROC [pins: PinRecList]
RETURNS [refPins: Pins ←
NIL] = {
t: Pins ← NIL;
FOR pl: PinRecList ← pins, pl.rest
UNTIL pl=
NIL
DO
t ← CONS[NEW[PinRec ← pl.first], t];
ENDLOOP;
FOR pl: Pins ← t, pl.rest
UNTIL pl=
NIL
DO
refPins ← CONS[pl.first, refPins];
ENDLOOP;
};
MakeBindList:
PUBLIC
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:
PUBLIC
PROC [name, type:
ROPE, bind: BindList, pins: Pins, circuit: FlatCircuit, root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec, flatWireToSignal, bindings: RefTab.Ref, parameters, configs:
LOR ←
NIL]
RETURNS [symbol: Symbol] = {
symbol ← CreateSymbol[circuit, name, type, parameters, configs];
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 {
signal: Signal ← CreateBoundSignal[bl.first.wire, circuit, root, flatWireToSignal, bindings, flatCell];
CreateSSP[symbol, pl.first, signal];
EXIT;
};
REPEAT FINISHED => ERROR;
ENDLOOP;
ENDLOOP;
};
AddSymbol:
PUBLIC
PROC [circuit: FlatCircuit, name, type:
ROPE, bindings: PinSignals]
RETURNS [symbol: Symbol] = {
symbol ← CreateSymbol[circuit, name, type];
FOR ps: PinSignals ← bindings, ps.rest
UNTIL ps=
NIL
DO
CreateSSP[symbol, ps.first.pin, ps.first.signal];
ENDLOOP;
};
CreateSymbol:
PROC [circuit: FlatCircuit, name, type:
ROPE, parameters, configs:
LOR ←
NIL]
RETURNS [symbol: Symbol] = {
symbol ← NEW[SymbolRec];
symbol.name ← name;
symbol.type ← type;
symbol.parameters ← parameters;
symbol.configs ← configs;
circuit.symbols ← CONS[symbol, circuit.symbols];
};
CreateBoundSignal:
PUBLIC
PROC [wire: Core.Wire, circuit: FlatCircuit, root: Core.CellType, flatWireToSignal: RefTab.Ref, bindings: RefTab.Ref, flatCell: CoreFlat.FlatCellTypeRec]
RETURNS [signal: Signal] = {
flatWire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[bindings, wire].val];
IF flatWire=
NIL
THEN {
flatWire ← NEW[CoreFlat.FlatWireRec];
flatWire.wire ← wire;
flatWire.flatCell ← flatCell;
};
signal ← NARROW[RefTab.Fetch[flatWireToSignal, flatWire].val];
IF signal=
NIL
THEN {
newFlatWire: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec ← flatWire^];
signal ← CreateSignal[circuit, SignalName[circuit, root, newFlatWire]];
IF NOT RefTab.Insert[flatWireToSignal, newFlatWire, signal] THEN ERROR;
signal.pin ← NARROW[CoreProperties.GetWireProp[flatWire.wire, $Pin]];
};
};
CreateSignal:
PUBLIC
PROC [circuit: FlatCircuit, name:
ROPE ←
NIL]
RETURNS [signal: Signal] = {
signal ← NEW[SignalRec];
IF name=NIL THEN name ← SignalName[circuit, NIL, NIL];
signal.name ← name;
circuit.signals ← CONS[signal, circuit.signals];
};
CreateSSP:
PROC [symbol: Symbol, pin: Pin, signal: Signal] = {
ssp: SymbolSignalPin ← NEW[SymbolSignalPinRec];
ssp.symbol ← symbol;
ssp.pin ← pin;
ssp.signal ← signal;
symbol.connections ← CONS[ssp, symbol.connections];
signal.connections ← CONS[ssp, signal.connections];
};
vddName: ROPE ← "Vdd";
gndName: ROPE ← "Gnd";
GlobalDelete:
PROC [name:
ROPE]
RETURNS [yes:
BOOL ←
FALSE] = {
yes ← Rope.Equal[name, vddName] OR Rope.Equal[name, gndName] OR Rope.Equal[name, "RosemaryLogicTime"];
};
Never call this procedure more than once with the same arguments! (except NIL)
SignalName:
PROC [circuit: FlatCircuit, cellType: Core.CellType, flatWire: CoreFlat.FlatWire]
RETURNS [name:
ROPE ←
NIL] = {
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]];
};
ManufactureName:
PROC = {
name ← IO.PutFR["N%g", IO.int[circuit.nameCount]];
circuit.nameCount ← circuit.nameCount + 1;
};
IF cellType=
NIL
OR flatWire=
NIL
THEN {
ManufactureName[];
IF NOT SymTab.Insert[circuit.nameTable, name, $Manufactured] THEN ERROR;
}
ELSE {
old: ROPE ← CoreFlat.WirePathRope[cellType, flatWire^];
shortName: ROPE ← CoreOps.GetShortWireName[flatWire.wire];
IF Rope.Length[old]>7 AND Rope.Equal[Rope.Substr[old, 0, 7], "public."] THEN old ← Rope.Substr[old, 7];
SELECT
TRUE
FROM
Rope.Equal[shortName, vddName] => name ← "$Vdd";
Rope.Equal[shortName, gndName] => name ← "$Gnd";
ENDCASE => [] ← Rope.Map[base: old, action: BuildNew];
IF Rope.Length[name]>16 THEN name ← Rope.Substr[name, Rope.Length[name]-16];
IF
NOT SymTab.Insert[circuit.nameTable, name, flatWire]
THEN {
ManufactureName[];
IF NOT SymTab.Insert[circuit.nameTable, name, flatWire] THEN ERROR;
};
};
};
SensedPhysicalDrivenTristate:
PROC [signal: Signal, pruned: RefTab.Ref]
RETURNS [sensed, physical, driven, tristate:
BOOL ←
FALSE] = {
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;
};
GetParameters:
PUBLIC
PROC [symbol: Symbol, instance: CoreClasses.CellInstance] = {
FindParms:
PROC [prop:
ATOM, val:
REF
ANY] = {
propName: ROPE ← Atom.GetPName[prop];
IF Rope.Match["Par*", propName,
FALSE]
THEN {
parm: ROPE ← NARROW[val];
symbol.parameters ← CONS[parm, symbol.parameters];
};
};
CoreProperties.Enumerate[instance.properties, FindParms];
};
CDCommandOps.RegisterWithMenu[$SpecialMenu, "WriteXNF", "Extract selected cells and write xnf files", $WriteXNF, WriteXNF];