IFUTopImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
McCreight, June 6, 1986 4:25:49 pm PDT
Don Curry April 20, 1987 11:27:19 am PST
Last Edited by: Louis Monier April 7, 1987 1:16:36 pm PST
Last Edited by: Don Curry February 23, 1988 5:54:03 pm PST
DIRECTORY Basics, Commander, Core, CoreIO, CoreClasses, CoreOps, CoreProperties, Dragon, DragonRosemary, DragOpsCross, EqualCheck, IFUTop, IFUPLA, IFUPublic, IFUPLAFetchControl, IFUPLAInstrDecode, IFUPLAInterlock, IFUPLAMainPipeControl, IFUPLAStackControl, IO, Ports, REFBit, Rope, Rosemary, TerminalIO, UncountedAssignHack;
IFUTopImpl: CEDAR PROGRAM
IMPORTS Basics, Commander, CoreClasses, CoreIO, CoreOps, CoreProperties, DragonRosemary, EqualCheck, IFUPLA, IFUPublic, IO, Rope, Rosemary, Ports, REFBit, TerminalIO, UncountedAssignHack
EXPORTS IFUTop =
BEGIN
version: [0..255] ← IFUPublic.CurrentIFUVersion;
IFUInconsistent: PUBLIC ERROR = CODE;
ROPE:    TYPE = Rope.ROPE;
II:     TYPE = IFUPublic.II;
IFUState:   TYPE = IFUTop.IFUState;
IFUStateRec:  TYPE = IFUTop.IFUStateRec;
ModSim:   TYPE = IFUTop.ModSim;
ModSimRec:  TYPE = IFUTop.ModSimRec;
ModuleSimProc: TYPE = IFUTop.ModuleSimProc;
IFURoseClass: ROPE = Rosemary.Register
[roseClassName: "IFU", init: IFUInit, evalSimple: IFUSimple];
PortData: TYPE = RECORD [ name: ROPE, width: NAT ← 1, drive: Ports.Drive ← none ];
Two:   TYPE = RECORD[w0, w1: WORD];
Swap:  PROC[in: Two] RETURNS[out: Two] = {RETURN[[in.w1, in.w0]]};
ToStatus: PROC[word: Dragon.Word] RETURNS[DragOpsCross.StackedStatusWord] =
{RETURN[LOOPHOLE[Swap[LOOPHOLE[word]]]]};
FromStatus: PROC[status: DragOpsCross.StackedStatusWord] RETURNS[Dragon.Word] =
{RETURN[LOOPHOLE[Swap[LOOPHOLE[status]]]]};
debugRegSize: NAT = 32;
IFUPre:      PUBLIC ModuleSimProc = {
OPEN state;
p[II[VbbGen].ORD].b ← TRUE;
p[II[PhAOut].ORD].b ←   p[II[Clk].ORD].b;
p[II[PhBOut].ORD].b ← NOT p[II[Clk].ORD].b;
LoadStage1Bc  ← ph=B AND NOT NotBcLoadStage1AB;
X2ASrcStatus2Ac ← ph=A AND X2ASrcStatus1BA;
X2ASrcLit2Ac  ← ph=A AND X2ASrcLit1BA;
IF ph=A THEN {
ResetAB   ← p[II[Reset   ].ORD].b;
DPFaultAB  ← DPFaultBA};
IF ph=B AND NOT drShWt THEN {
ResetBA    ← ResetAB;
RescheduleBA  ← p[II[Reschedule  ].ORD].b;
IPData    ← p[II[IPData    ].ORD].lc;
IPRejectBA   ← p[II[IPReject   ].ORD].b;
IPFaultingBA  ← p[II[IPFaulting  ].ORD].b;
DPFaultBA ← VAL[ p[II[DPFault   ].ORD].c];
DPRejectBA   ← p[II[DPReject   ].ORD].b;
EUCondition2BA ← p[II[EUCondition  ].ORD].b };
buf: REF ANY = plaBuffers[pla][sense];
rtIO: IFUPLAPass.RtDrPadIO ← [
dPReject:    BOOL      ← FALSE,   -- BA <= B dual
dPFault:    Dragon.PBusFaults  ← none,   -- BA <= B
dPFaultCode:   PBusFaultCode   ← memAccess, -- BA => BAA
dPFaultCodeD:  PBusFaultCode   ← memAccess, -- AB <= BAA
dPCmnd3:   Dragon.PBusCommands ← NoOp,   -- BA => BAA
userMode2:   BOOL      ← FALSE,   -- BA => BAA
eUAluOp2:   Dragon.ALUOps   ← Or,    -- AB => ABB
eUCondSel2:   Dragon.CondSelects  ← False,   -- AB => ABB
eUCondition2:  BOOL      ← FALSE,   -- BA <= B
eUWriteToPBus3: BOOL      ← FALSE,   -- AB => ABB
eURdFromPBus3: BOOL      ← FALSE,   -- AB => ABB
K0PadsIn4:   BOOL      ← FALSE,   -- Ac <= BA
K1PadsIn4:   BOOL      ← FALSE,   -- Ac <= BA
K0PadsOut3:   BOOL      ← FALSE,   -- BA <= BA
K1PadsOut3:   BOOL      ← FALSE,   -- BA <= BA
X2ASrcLit1:   BOOL      ← FALSE,   -- BA => BAA
X2ASrcLit2:   BOOL      ← FALSE,   -- Ac <= BAA dual
debugABGD:   BOOL      ← FALSE,   --  <debug>
debugPC:    BOOL      ← FALSE,   --  <debug>
debugLSC:   BOOL      ← FALSE,   --  <debug>
debugABStLim:  BOOL      ← FALSE ];  --  <debug>
ltIO: IFUPLAPass.LtDrPadIO ← [
iPReject:    BOOLFALSE,      -- B  => BA
iPFaulting:   BOOLFALSE,      -- B  => BA
newFetch:   BOOLFALSE,      -- BAA <= BA
reset:     BOOLFALSE,      -- AB  => BA
reschedule:   BOOLFALSE ];     -- AB  => BA
IF p[II[DShA].ORD].b THEN {
inputBit: BOOL = NOT p[II[DShIn].ORD].b;
DragonRosemary.Assert [ NOT p[II[DShRd].ORD].b,
"Error in IFU shifter clocking sequence" ];
IF NOT p[II[DShB].ORD].b
THEN { -- shift drShifterAB from drShifterBA
drShifterAB.bits[0] ← inputBit;
FOR i: NAT IN [1..drShifterAB.size) DO
drShifterAB.bits[i] ← drShifterBA.bits[i-1];
ENDLOOP}
ELSE { -- mass copy drShifterAB from DShIn
FOR i: NAT IN [0..drShifterAB.size) DO
drShifterAB.bits[i] ← drShifterBA.bits[i] ← inputBit;
ENDLOOP } };
DragonRosemary.Assert[ NOT (p[II[DShRd].ORD].b AND p[II[DShWt].ORD].b),
"Error in IFU shifter clocking sequence"];
broadside copy from shift register to drivers
IF p[II[DShWt].ORD].b THEN
FOR pla: IFUPLA.PLAs IN IFUPLA.PLAs DO
FOR sense: IFUPLA.Sense IN IFUPLA.Sense DO
IF plaOffsets[pla][sense] > 0 THEN {
offset: NAT = plaOffsets[pla][sense];
buf: REF ANY = plaBuffers[pla][sense];
FOR i: NAT IN [0..IFUPLA.plaSizes[pla][sense]) DO
inv: BOOL ← REFBit.Get[IFUPublic.scanDrInv, offset+i];
REFBit.Set[buf, i, drShifterAB.bits[offset+i] # inv];
ENDLOOP};
ENDLOOP;
ENDLOOP };
IFUPreRef:     ModSim ← NEW[ModSimRec ← [IFUPre]];
IFUPost:      PUBLIC ModuleSimProc = {
OPEN state;
IF p[II[DShRd].ORD].b THEN {-- broadside copy into shift register
xbus: LONG CARDINAL ← XBus;
FOR pla: IFUPLA.PLAs IN IFUPLA.PLAs DO
FOR sense: IFUPLA.Sense IN IFUPLA.Sense DO
IF plaOffsets[pla][sense] > 0 THEN {
offset: NAT = plaOffsets[pla][sense];
buf: REF ANY = plaBuffers[pla][sense];
FOR i: NAT IN [0..IFUPLA.plaSizes[pla][sense]) DO
inv: BOOL ← REFBit.Get[IFUPublic.scanDrInv, offset+i];
drShifterAB.bits[offset+i] ← REFBit.Get[buf, i] # inv;
ENDLOOP};
ENDLOOP;
ENDLOOP;
FOR i: INT IN [0..debugRegSize) DO
drShifterAB.bits[drShifterAB.size-debugRegSize+i] ← (xbus MOD 2)=1;
xbus ← xbus/2 ENDLOOP};
IF p[II[DShB].ORD].b THEN { -- shift drShifterBA from drShifterAB
FOR i: NAT IN [0..drShifterAB.size) DO
drShifterBA.bits[i] ← drShifterAB.bits[i]; ENDLOOP};
p[II[DShOut].ORD].b ← NOT drShifterBA.bits[drShifterBA.size-1]};
IFUPostRef:     ModSim ← NEW[ModSimRec ← [IFUPost]];
IFUInstrDecode:    PUBLIC ModuleSimProc = {
OPEN state;
X1ASrcSLimitAc ← ph=A AND x1ASrcSLimitBA;
X1ADstSLimitAc ← ph=A AND x1ADstSLimitBA;
SELECT ph FROM
A => { };
ab => {
IF NOT drShWt THEN {
All seven instruction decoding sub-PLA's are strung on these input wires, and attached to the same input record.
inTYPE: TYPE = IFUPLAInstrDecode.InstrDecodeIn;
inRec:  inTYPE ← [
reset:    ResetAB,
state:    StateAB,
instReady:  InstReadyAB,
op:    DragOpsCross.Inst[VAL[OpAB]],
alpha:    AlphaAB,
beta:    BetaAB,
pushPending: PushPendingAB,
popPending:  PopPendingAB,
userMode0:  UserMode0AB ];
NARROW[ plaBuffers[instrDecode0][input], REF inTYPE]^ ← inRec;
NARROW[ plaBuffers[instrDecode1][input], REF inTYPE]^ ← inRec;
NARROW[ plaBuffers[instrDecode2][input], REF inTYPE]^ ← inRec;
NARROW[ plaBuffers[instrDecode3][input], REF inTYPE]^ ← inRec;
NARROW[ plaBuffers[instrDecode4][input], REF inTYPE]^ ← inRec;
NARROW[ plaBuffers[instrDecode5][input], REF inTYPE]^ ← inRec;
NARROW[ plaBuffers[instrDecode6][input], REF inTYPE]^ ← inRec } };
B => {
PLAEval[state, instrDecode0];
PLAEval[state, instrDecode1];
PLAEval[state, instrDecode2];
PLAEval[state, instrDecode3];
PLAEval[state, instrDecode4];
PLAEval[state, instrDecode5];
PLAEval[state, instrDecode6];
[
nextMacro:   NextMacroBA,
pcNext:    PCNextBA,
pcBusSrc:    PCBusSrcBA,
pcPipeSrc:   PCPipeSrcBA,
x2ALitSource:  X2ALitSourceBA,
kIsRtOp0:    KIsRtOp0BA,
push0:    Push0BA ]
NARROW[plaBuffers[instrDecode6][output], REF
IFUPLAInstrDecode.InstrDecodeOut6]^;
[
instStarting0:   InstStarting0BA,
microCycleNext:  MicroCycleNextBA,
protMicroCycle:  ProtMicroCycleBA,
pop0:     Pop0BA,
dPCmnd:    DPCmndBA,
dPCmndIsRd0:  DPCmndIsRd0BA,
dPCmndSel:   DPCmndSelBA ] ← NARROW[plaBuffers[instrDecode5][output], REF IFUPLAInstrDecode.InstrDecodeOut5]^;
[
flagSrc:    FlagSrcBA,
lSource:    [LSourceLtBA, LSourceRtBA],
sSource:    [SSourceLtBA, SSourceRtBA],
popSa:     PopSaBA,
popSb:    PopSbBA
] ← NARROW[plaBuffers[instrDecode4][output], REF IFUPLAInstrDecode.InstrDecodeOut4]^;
[
kPadsIn0:    KPadsIn0BA,
fCtlIsRtOp0:   FCtlIsRtOp0BA,
pushSc:    PushScBA,
cReg:     [CRegLtBA, CRegRtBA, CRegOffBA, CRegModBA]
] ← NARROW[plaBuffers[instrDecode3][output], REF IFUPLAInstrDecode.InstrDecodeOut3]^;
[
bReg:     [BRegLtBA, BRegRtBA, BRegOffBA, BRegModBA]
] ← NARROW[plaBuffers[instrDecode2][output], REF IFUPLAInstrDecode.InstrDecodeOut2]^;
[
aReg:     [ARegLtBA, ARegRtBA, ARegOffBA, ARegModBA]
] ← NARROW[plaBuffers[instrDecode1][output], REF IFUPLAInstrDecode.InstrDecodeOut1]^;
[
aluOp:    AluOpBA,
aluOpIsOp47:   AluOpIsOp47BA,
condSel:    CondSelBA,
condSelIsOp57:  CondSelIsOp57BA,
condEffect0:   CondEffect0BA,
x1ADstSLimit:  x1ADstSLimitBA,
x1ASrcSLimit:  x1ASrcSLimitBA,
x1ADstStack:   X1ADstStackBA,
x1ASrcStack:   X1ASrcStackBA,
x1ASrcStackL:
x1ASrcStackP:
xBusStackL:   XBusStackLBA,
xBusStackEldest:  XBusStackEldestBA,
cIsField0:    CIsField0BA
] ← NARROW[plaBuffers[instrDecode0][output], REF IFUPLAInstrDecode.InstrDecodeOut0]^};
ba  => NULL;
ENDCASE => ERROR IFUInconsistent};
IFUInstrDecodeRef:   ModSim ← NEW[ModSimRec ← [IFUInstrDecode]];
IFUMainPipeControl:  PUBLIC ModuleSimProc = {
OPEN state;
MCPIN: REF IFUPLAMainPipeControl.MainPipeControlIn
NARROW[plaBuffers[mainPipeControl][input]];
MCPOUT: REF IFUPLAMainPipeControl.MainPipeControlOut
NARROW[plaBuffers[mainPipeControl][output]];
SELECT ph FROM
A => {
[
loadStage1:   LoadStage1Ac,
loadStage2:   LoadStage2Ac,
loadStage3:   LoadStage3Ac,
stage1BHolding:  Stage1BHoldingAB,
notBcLoadStage1: NotBcLoadStage1AB, -- really just Stage1BHoldingAB
stage2B:    Stage2B,
stage3BCPipe:  Stage3BCPipe,
microExcptJmp:  MicroExcptJmpAB,
except:    ExceptAB,
rschClear:   RschClearAB,
rschWaiting:   RschWaitingAB ] ← MCPOUT^;
LoadStage1Ac   ← MCPOUT.loadStage1;
LoadStage2Ac   ← MCPOUT.loadStage2;
LoadStage3Ac   ← MCPOUT.loadStage3;
Stage1BHoldingAB  ← MCPOUT.stage1BHolding;
NotBcLoadStage1AB  ← MCPOUT.notBcLoadStage1;
Stage2BNormalAB  ← MCPOUT.stage2B=normal;
Stage2BAbortAB   ← MCPOUT.stage2B=abort;
Stage3BCPipeNormalAB ← MCPOUT.stage3BCPipe=normal;
Stage3BCPipeAbortAB ← MCPOUT.stage3BCPipe=abort;
MicroExcptJmpAB  ← MCPOUT.microExcptJmp;
ExceptAB     ← MCPOUT.except;
RschClearAB    ← MCPOUT.rschClear;
RschWaitingAB   ← MCPOUT.rschWaiting;
IF NOT drShWt THEN
MCPIN.rschClearIn ← RschClearAB;
PLAEval[state, mainPipeControl];
RschWaitingAB   ← MCPOUT.rschWaiting};
ab => {
LoadStage1Ac ← FALSE;
LoadStage2Ac ← FALSE;
LoadStage3Ac ← FALSE};
B => {
IF NOT drShWt THEN MCPIN^ ← [
reset:      ResetBA,      -- Pre
dPReject:     DPRejectBA,     -- Pre
dPFaulting:    DPFaultBA # none,  -- Pre
protMicroCycle:   ProtMicroCycleBA,   -- InstrDecode
microExcptJmpBubble: MicroExcptJmpAB=bubble,
stage2BAbort:   Stage2BAbortAB,
stage1BHold:    Stage1BHoldBA,    -- Interlock
condEffect1:    CondEffect1BA,    -- ControlPipe
condEffect2:    CondEffect2BA,    -- ControlPipe
eUCondition2:   EUCondition2BA,   -- Pre
trapsEnabled2:   TrapsEnabled2BA,   -- Status
eStkOverflow2:   EStkOverflow2BA,   -- ControlPipe
instStarting2:    InstStarting2BA,    -- ControlPipe
reschedule:    RescheduleBA,
rschWaitingIn:   RschWaitingAB,
push2:     Push2AB,
instFault2:    InstFault2BA,    -- ControlPipe
iStkNearlyFull:   IStkNearlyFullBA,   -- StackControl
rschClearIn:    RschClearAB ];    -- PRESERVE PhA change
PLAEval[state, mainPipeControl];
Stage2ANormalBA ← MCPOUT.stage2A=normal;
Stage2ABubbleBA ← MCPOUT.stage2A=bubble;
Stage3ANormalBA ← MCPOUT.stage3A=normal;
Stage3AAbortBA  ← MCPOUT.stage3A=abort};
ba => { };
ENDCASE => ERROR IFUInconsistent};
IFUMainPipeControlRef: ModSim ← NEW[ModSimRec ← [IFUMainPipeControl]];
IFUMicroCycle:    PUBLIC ModuleSimProc = {
OPEN state;
SELECT ph FROM
A => {
See: IFUPLAMainPipeControl.MicroExcptJmp
StateAB ← (SELECT MicroExcptJmpAB FROM
none   => StateBA MOD 128,  -- 0sss ssss
bubble  => StateBA MOD 128+128, -- 1sss ssss
microJump => 48,       -- 0011 0000
resetting  => 112, -- exception   0111 0000
trap   => 116, -- exception   0111 0100
cJump  => 120, -- exception   0111 1000
ENDCASE  => ERROR IFUInconsistent) };
ab => { };
B => {
StateBA ← SELECT MicroCycleNextBA FROM
clear   => 0,
hold    => StateAB,
next   => StateAB +1,
ENDCASE => ERROR IFUInconsistent};
ba => { };
ENDCASE => ERROR IFUInconsistent};
IFUMicroCycleRef:   ModSim ← NEW[ModSimRec ← [IFUMicroCycle]];
IFUStatus:     PUBLIC ModuleSimProc = {
OPEN state;
SELECT ph FROM
A => {
UserMode0AB   ←
userMode   [0][a] ← nextUserModeBA;
trapsEnabled  [0][a] ← nextTrapsEnabledBA;
IF LoadStage1Ac THEN {
userMode   [1][a] ← userMode  [0][b];
trapsEnabled  [1][a] ← trapsEnabled [0][b]};
IF LoadStage2Ac THEN SELECT TRUE FROM
Stage2ABubbleBA => {
userMode   [2][a] ← TRUE;
trapsEnabled  [2][a] ← FALSE};
Stage2ANormalBA => {
userMode   [2][a] ← userMode  [1][b];
trapsEnabled  [2][a] ← trapsEnabled [1][b]};
ENDCASE => IFUInconsistent;
IF LoadStage3Ac THEN {
userMode   [3][a] ← userMode  [2][b];
trapsEnabled  [3][a] ← trapsEnabled [2][b]} };
ab => NULL;
B => {
status: DragOpsCross.StackedStatusWord;
SELECT FlagSrcBA FROM
same  => {
nextUserModeBA  ← userMode  [0][a];
nextTrapsEnabledBA ← trapsEnabled [0][a]};
clear  => {
nextUserModeBA  ← FALSE;
nextTrapsEnabledBA ← FALSE};
stack  => {
nextUserModeBA  ← ToStatus[LFStkTopAB].userMode;
nextTrapsEnabledBA ← ToStatus[LFStkTopAB].trapsEnabled};
lev3  => {
nextUserModeBA  ← userMode  [3][a];
nextTrapsEnabledBA ← trapsEnabled [3][a]};
ENDCASE => ERROR IFUInconsistent;
userMode   [0][b] ← userMode  [0][a];
trapsEnabled  [0][b] ← trapsEnabled [0][a];
IF LoadStage1Bc THEN {
userMode   [1][b] ← userMode  [1][a];
trapsEnabled  [1][b] ← trapsEnabled [1][a] };
userMode   [2][b] ← userMode   [2][a];
trapsEnabled  [2][b] ← trapsEnabled  [2][a];
p[II[ UserMode].ORD].b ← userMode  [2] [b];
TrapsEnabled2BA    ← trapsEnabled [2] [b];
status     ← ToStatus[LFPipe3BA];
status.version  ← version;
status.userMode  ← userMode  [3][a];
status.trapsEnabled ← trapsEnabled [3][a];
LFPipe3BA   ← FromStatus[status]};
ba => NULL;
ENDCASE => ERROR IFUInconsistent} ;
IFUStatus:     PUBLIC ModuleSimProc = {
OPEN state;
SELECT ph FROM
A => {
newstatusRec: DragOpsCross.IFUStatusRec ←
DragOpsCrossUtils.WordToStatus[DragOpsCrossUtils.CardToWord[XBus]];
rsPipe[a] ← RescheduleBA;
status[a] ← [
version:   IFUTop.CurrentIFUVersion,
rescheduleKeep: TRUE ];
status[a].reschedule ←
(RescheduleBA AND NOT rsPipe[b]) OR
(IF ~X1ADstStatusBA
THEN status[b].reschedule
ELSEIF newstatusRec.rescheduleKeep
THEN status[b].reschedule
ELSE newstatusRec.reschedule);
status[a].userMode ← NOT ClearUserModeBA AND
(IF ~X1ADstStatusBA
THEN status[b].userMode
ELSEIF newstatusRec.userModeKeep
THEN status[b].userMode
ELSE newstatusRec.userMode);
status[a].trapsEnabled ← NOT ClearTrapsEnabledBA AND
(IF ~X1ADstStatusBA
THEN status[b].trapsEnabled
ELSEIF newstatusRec.trapsEnabledKeep
THEN status[b].trapsEnabled
ELSE newstatusRec.trapsEnabled);
IF X2ASrcStatus2Ac THEN {
XBus ← DragOpsCrossUtils.WordToCard[DragOpsCrossUtils.StatusToWord[statPipe[b]]]};
IF LoadStage1Ac THEN
statPipe[a]  ← status[b];
UserMode0AB ← status[a].userMode };
ab => NULL;
B => {
status[b]  ← status[a];
rsPipe[b] ← rsPipe[a];
IF LoadStage1Bc THEN statPipe[b] ← statPipe[a];
RschWaiting2BA ← status[b].reschedule  AND NOT X1ADstStatusBA; -- just in case
TrapsEnabled2BA ← status[b].trapsEnabled AND NOT ClearTrapsEnabledBA };
ba => NULL;
ENDCASE => ERROR IFUInconsistent};
IFUStatusRef:    ModSim ← NEW[ModSimRec ← [IFUStatus]];
IFUInterlock:     PUBLIC ModuleSimProc = {
OPEN state;
SELECT ph FROM
A, ab => NULL;
B => {
IF NOT drShWt THEN
NARROW[plaBuffers[interlock][input], REF
IFUPLAInterlock.InterlockIn]^ ← [
kIsRtOp1:    KIsRtOp1BA,    -- ControlPipe
fCtlIsRtOp1:   FCtlIsRtOp1BA,   -- ControlPipe
cIsField2:    CIsField2AB,
cIsField3:    CIsField3AB,
dPCmndIsRd2:  DPCmndIsRd2BA,  -- ControlPipe
a1IsC2:    A1IsC2B,     -- ABC
a1IsC3:    A1IsC3B,     -- ABC
b1IsC2:    B1IsC2B,     -- ABC
b1IsC3:    B1IsC3B ];    -- ABC
PLAEval[state, interlock]; -- static
[
stage1BHold:   Stage1BHoldBA,
stage1BHoldIfReject: Stage1BHoldIfRejectBA,
eUAluLeftSrc1:  EUAluLeftSrc1B,
eUAluRightSrc1:  EUAluRightSrc1B,
eUStore2ASrc1:  EUStore2ASrc1B,
eUSt3AIsCBus1:  EUSt3AIsCBus1BA
] ← NARROW[plaBuffers[interlock][output], REF
IFUPLAInterlock.InterlockOut]^};
ba => NULL;
ENDCASE => ERROR IFUInconsistent };
IFUInterlockRef:    ModSim ← NEW[ModSimRec ← [IFUInterlock]];
IFUFetch:     PUBLIC ModuleSimProc = {
OPEN state;
FCIN: REF IFUPLAFetchControl.FetchControlIn
NARROW[plaBuffers[fetchControl][input]];
FCOUT: REF IFUPLAFetchControl.FetchControlOut
NARROW[plaBuffers[fetchControl][output]];
PA4BFromCard: PROC [ in: [0..16) ] RETURNS [ out: PACKED ARRAY [0..4) OF BOOL] =
TRUSTED { out ← LOOPHOLE[in]; };
PA16BFromCard: PROC [ in: CARDINAL] RETURNS [ out: PACKED ARRAY [0..16) OF BOOL] =
TRUSTED { out ← LOOPHOLE[in] };
p[II[IPData].ORD].d   ← (IF ph=A THEN drive ELSE none);
p[II[IPCmdFetch].ORD].b ← (IF ph=A THEN NewFetchBA ELSE FALSE);
SELECT ph FROM
A => {
FetchIndexing
wtAB   ← wtBA;
rdAB   ← rdBA;
FetchWtAB ← (wtAB MOD 16)/4;
IF NOT drShWt THEN
NARROW[plaBuffers[fetchRdDecode][input], REF IFUPLAFetchControl.FetchRdDecodeIn]^ ← [
fetchRd:   FetchRdBA];
PLAEval[state, fetchRdDecode]; -- static
FetchBufRdByteAc ← PA16BFromCard[NARROW[plaBuffers[fetchRdDecode][output], REF IFUPLAFetchControl.FetchRdDecodeOut]^];
p[II[IPData].ORD].lc ← IPData ← fetchAddrBA/4; -- Byte to word happens here
fetchAddrAB ← fetchAddrBA+(IF NewFetchBA THEN 4 ELSE 0); -- byte offset in 30,31
OpAB   ← iBuf[(rdBA+0) MOD 16];
AlphaAB  ← iBuf[(rdBA+1) MOD 16];
BetaAB  ← iBuf[(rdBA+2) MOD 16];
GammaAB ← iBuf[(rdBA+3) MOD 16];
DeltaAB  ← iBuf[(rdBA+4) MOD 16];
FetchingAB ← FetchingBA;
FetchBytesM1AB ← (wtBA-rdBA-1+64) MOD 32;
IF NOT drShWt THEN {
FCIN.op    ← VAL[OpAB] / 32;  -- (3 msbs)   Fetch
FCIN.fetchBytesM1 ← FetchBytesM1AB}; --      Fetch
PLAEval[state, fetchControl];
[
jumpPending: JumpPendingAB,
iPFaulted:  IPFaultedAB,
notInstReady: NotInstReadyAB,
jumpOffset:  JumpOffsetAB,
opLength:  OpLengthAB -- A latched copy for fetch indexing
] ← FCOUT^;
IF DragonRosemary.OpLength[OpAB] # OpLengthAB THEN ERROR;
InstReadyAB ← NOT NotInstReadyAB};
ab => {
FetchBufRdByteAc ← ALL[FALSE]};
B => {
FCIN^ ← [
nextMacroJump:  NextMacroBA=jump,
reset:     ResetBA,    -- Pre
iPReject:    IPRejectBA,   -- Pre
jumpPendingIn:  JumpPendingAB,
fetchingIn:   FetchingAB,
fetchBytesM1:  FCIN.fetchBytesM1, -- PRESERVE PhA changes
iPFaultedIn:   IPFaultedAB,
iPFaulting:   IPFaultingBA,  -- Pre (this can be pipeline delayed)
op:     FCIN.op ];   -- PRESERVE PhA changes
PLAEval[state, fetchControl]; -- static
[
newFetch:   NewFetchBA,
fetching:    FetchingBA,
fetchWtIndexCtl:  FetchWtIndexCtlBA,
opLengthb:   OpLengthbBA,  -- B latched copy for pc adjustment
instFault0:   InstFault0BA   ] ← FCOUT^;
p[II[IPCmdFetch].ORD].b ← NewFetchBA;
SELECT FetchWtIndexCtlBA FROM -- from FetchIndexing
clear  => wtBA ← 0;
hold  => wtBA ← wtAB;
inc  => wtBA ← (wtAB+4) MOD 32;
ENDCASE => ERROR IFUInconsistent;
rdBA ← (SELECT NextMacroBA FROM
jump  => PCBusB MOD DragOpsCross.bytesPerWord,
get  => (rdAB+OpLengthAB) MOD 32,
hold  => rdAB,
ENDCASE => ERROR);
FetchRdBA ← rdBA MOD 16;
IF NOT drShWt THEN
NARROW[plaBuffers[fetchWtDecode][input], REF IFUPLAFetchControl.FetchWtDecodeIn]^ ← [
fetching: FetchingAB,
fetchWt: FetchWtAB];
PLAEval[state, fetchWtDecode]; -- static
FetchBufWtWdBc ← PA4BFromCard[NARROW[plaBuffers[fetchWtDecode][output], REF IFUPLAFetchControl.FetchWtDecodeOut]^];
fetchAddrBA ← (IF NextMacroBA=jump THEN PCBusB ELSE fetchAddrAB);
from FetchAddr
IF FetchingAB THEN {
base:   [0..16) = 4*((wtAB MOD 16)/4);
iWd:   Basics.LongNumber;
iWd.lc  ← IPData;
iBuf[base+0] ← iWd.hh;
iBuf[base+1] ← iWd.hl;
iBuf[base+2] ← iWd.lh;
iBuf[base+3] ← iWd.ll } };
ba => {
FetchBufWtWdBc ← ALL[FALSE]};
ENDCASE => ERROR IFUInconsistent};
IFUFetchRef:     ModSim ← NEW[ModSimRec ← [IFUFetch]];
IFULitGen:     PUBLIC ModuleSimProc = {
OPEN state;
SELECT ph FROM
A => {
IF LoadStage1Ac THEN xaPipe1AB ← xaPipe0BA;
IF X2ASrcLit2Ac THEN XBus ← xaPipe1BA};
ab => NULL;
B => {
xaPipe0BA ← SELECT X2ALitSourceBA FROM
none    => 0, -- but will not drive XBus in 2A
zero    => 0,
alpha    => AlphaAB,
alphaBeta   => AlphaAB*LONG[256] + BetaAB,
alpBetGamDel => ((AlphaAB*LONG[256] + BetaAB)*256 + GammaAB)*256 + DeltaAB,
ENDCASE   => ERROR IFUInconsistent;
IF LoadStage1Bc THEN xaPipe1BA ← xaPipe1AB};
ba => NULL;
ENDCASE => ERROR IFUInconsistent};
IFULitGenRef:    ModSim ← NEW[ModSimRec ← [IFULitGen]];
IFUPC:       PUBLIC ModuleSimProc = {
OPEN state;
There are three PC values that may be needed for an instruction: the PC of the instruction itself, the PC of the next sequential instruction, and the PC of a call or jump target. The instruction PC is carried down pcPipe. One of the other two PC's, which may be needed as the return address of a call-type instruction or as the alternate PC of a failed conditional jump, is carried down altPcPipe. The third PC, if any, is passed immediately to the prefetcher.
The two pipelined PC's merge at stage 3A, based on conditions computed at stage 2B. In the normal case, the merged value is altPc. In case of a trap or fault, the merged value is the pc of the offending instruction, carried in pcPipe.
SExtnd: PROC[b: Dragon.HexByte] RETURNS [INT] = {
RETURN[ IF b>=128 THEN (LONG[b]-256) ELSE LONG[b]] };
SELECT ph FROM
A => {
pcSum ← OpLengthbBA + pcBA;
IF LoadStage1Ac THEN {
pcPipe[1][a] ← pcBA;
pcAltPipe[1][a] ← SELECT PCPipeSrcBA FROM
seqPC  => pcSum -- next sequential instruction -- ,
offSetPC => targetPCBA -- jump target instruction -- ,
thisPC => pcBA -- for traps that are recognized only at stage 0 -- ,
ENDCASE => ERROR IFUInconsistent};
Memory reference instructions fail within stage 3, so they must specify PCLSPipeSrcBA = old. This shouldn't be a problem, since the only instructions that need to do otherwise are conditional jumps.
IF LoadStage2Ac THEN {pcPipe[2][a] ← pcPipe[1][b]; pcAltPipe[2][a] ← pcAltPipe[1][b]};
IF LoadStage3Ac THEN {
pcPipe[3][a] ← (SELECT TRUE FROM
Stage3AAbortBA => pcPipe[2][b],  -- pc of aborting micro
Stage3ANormalBA => pcAltPipe[2][b], -- whatever top of pipe suggested
ENDCASE => ERROR IFUInconsistent) };
pcAB ← SELECT PCNextBA FROM
incr   => pcSum,
fromPCBus => npcBA,
ENDCASE   => ERROR IFUInconsistent;
PCForLogAB ← pcAB };
ab => NULL;
B => {
IF LoadStage1Bc THEN {pcPipe[1][b] ← pcPipe[1][a]; pcAltPipe[1][b] ← pcAltPipe[1][a]};
pcPipe[2][b] ← pcPipe[2][a]; pcAltPipe[2][b] ← pcAltPipe[2][a];
PCPipe3BA ← pcPipe[3][b] ← pcPipe[3][a];
pcBranchOSetB ← (SELECT JumpOffsetAB FROM
alpha  => SExtnd[AlphaAB],
beta  => SExtnd[BetaAB],
alphaBeta => SExtnd[AlphaAB]*256 + BetaAB,
xa   => xAB,
ENDCASE => ERROR IFUInconsistent );
targetPCBA ← pcSum ← pcBranchOSetB + pcAB;
pcBA ← pcAB;
PCBusB ← npcBA ← (SELECT PCBusSrcBA FROM
offSetPC   => pcSum,
pc     => pcAB,
x     => xAB,
xopGen   => DragOpsCross.bytesPerWord*(DragOpsCross.XopBase + DragOpsCross.TrapWidthWords*OpAB),
trapGen => DragOpsCross.bytesPerWord* (DragOpsCross.TrapBase+DragOpsCross.TrapWidthWords*(
SELECT ExceptAB.type FROM
specialCode => 00B + ExceptAB.code.ORD MOD 20B,
condCode  => 20B + EUCondSel3AB.ORD, -- TrapIndex[ALUCondFalse]
dpFault  => 40B + (DPFaultAB.ORD MOD 8),-- TrapIndex[MemAccessFault]
ENDCASE  => ERROR)),
alpBetGamDel => ((AlphaAB*LONG[256]+BetaAB)*256+GammaAB)*256+DeltaAB,
pipe3    => PCPipe3BA,
stack    => PCStkTopAB,
ENDCASE   => ERROR IFUInconsistent);
OpBA  ← OpAB;
AlphaBA ← AlphaAB;
BetaBA ← BetaAB };
ba => NULL;
ENDCASE => ERROR IFUInconsistent };
IFUPCRef:     ModSim ← NEW[ModSimRec ← [IFUPC]];
IFUStack:      PUBLIC ModuleSimProc = {
OPEN state;
IF X1ADstStackBA
THEN { -- static multiplexer
pWrtBufA ← XBus;
lWrtBufA ← XBus}
ELSE {
pWrtBufA ← PCPipe3BA;
lWrtBufA ← LFPipe3BA};
SELECT ph FROM
A => {
adderMuxA: [0..32);
addendA:  [0..32);
carryA:  [0..1];
sumA:  [0..32);
sdo:   IFUPLAStackControl.StackDecodeOut ← NARROW[plaBuffers[stackDecode][output], REF
IFUPLAStackControl.StackDecodeOut]^;
StkLdPAc  ← LOOPHOLE[sdo.stkLdP];
StkLdLAc ← LOOPHOLE[sdo.stkLdL];
StkRdAc  ← LOOPHOLE[sdo.stkRd];
PLAEval[state, stackAControl]; -- dynamic
[
stackAdjTos:   StackAdjTosAB,
stackAddendIsOnes: StackAddendIsOnesAB,
stackCarryIsOne:  StackCarryIsOneAB
] ← NARROW[plaBuffers[stackAControl][output], REF IFUPLAStackControl.StackAControlOut]^;
adderMuxA ← IF StackAdjTosAB   THEN TosBA ELSE BosBA;
addendA  ← IF StackAddendIsOnesAB THEN 31  ELSE 0;
carryA  ← IF StackCarryIsOneAB  THEN 1  ELSE 0;
sumA   ← (adderMuxA+addendA+carryA) MOD 32;
TosAB ← SELECT TRUE FROM
ResetBA     => 0,
StackAdjTosAB   => sumA,
ENDCASE     => TosBA; -- needed because StackAdjTosAB might glitch
BosAB ← BosAB ← SELECT TRUE FROM
ResetBA     => 1,
NOT StackAdjTosAB => sumA,
ENDCASE     => BosBA; -- needed because StackAdjTosAB might glitch
FOR index: NAT IN [0..16) DO
IF StkLdLAc[index] THEN lStack[index] ← lWrtBufA;
IF StkLdPAc[index] THEN pStack[index] ← pWrtBufA;
ENDLOOP;
IF Push3BA
THEN { -- bypass
DragonRosemary.Assert[NOT X1ADstStackBA];
pRdBufA ← pWrtBufA; -- or PCPipe3BA
lRdBufA ← lWrtBufA} -- or LFPipe3BA
ELSE
FOR index: NAT IN [0..16) DO
IF StkRdAc[index] THEN {
lRdBufA ← lStack[index];
pRdBufA ← pStack[index]};
ENDLOOP;
PCStkTopAB ← pRdBufA;
LFStkTopAB ← lRdBufA;
IF X1ASrcStackBA THEN
XBus ← (IF XBusStackLBA THEN lRdBufA ELSE pRdBufA)};
ab => {StkLdLAc ← StkLdPAc ← StkRdAc ← ALL[FALSE]};
B => {
StackDiffBA ← (32+TosAB-BosAB) MOD 32;
IF NOT drShWt THEN NARROW[plaBuffers[stackBControl][input], REF
IFUPLAStackControl.StackBControlIn]^ ← [
stackDiff:    StackDiffBA,           -- Stack
microExcptJmpTrap: MicroExcptJmpAB=trap,
pushIn3:    Push3AB,
popIn3:     Pop3AB ];
PLAEval[state, stackBControl]; -- static
[
push3:   Push3BA,
pop3:    Pop3BA,
iStkNearlyFull: IStkNearlyFullBA
] ← NARROW[plaBuffers[stackBControl][output], REF IFUPLAStackControl.StackBControlOut]^;
TosBA ← TosAB;
BosBA ← BosAB;
IF NOT drShWt THEN NARROW[plaBuffers[stackDecode][input], REF IFUPLAStackControl.StackDecodeIn]^ ← [
bos:    BosBA,     -- was BosAB Stack
tos:    TosBA,     -- was TosAB Stack
x1ASrcStack:  X1ASrcStackBA,   --     InstrDecode
x1ADstStack:  X1ADstStackBA,   --     InstrDecode
xBusStackEldest: XBusStackEldestBA,  --     InstrDecode
xBusStackL:  XBusStackLBA,   --     InstrDecode
push3:   Push3BA,    --     Stack
pop3:    Pop3BA ];    --     Stack
PLAEval[state, stackDecode] };
ba => {
IF NOT drShWt THEN
NARROW[plaBuffers[stackAControl][input], REF IFUPLAStackControl.StackAControlIn]^ ← [
x1ASrcStack:  X1ASrcStackBA,
x1ADstStack:  X1ADstStackBA,
xBusStackEldest: XBusStackEldestBA,
xBusStackL:  XBusStackLBA,
push3:   Push3BA,
pop3:    Pop3BA ] };
ENDCASE => ERROR IFUInconsistent };
IFUStackRef:     ModSim ← NEW[ModSimRec ← [IFUStack]];
IFULS:       PUBLIC ModuleSimProc = {
OPEN state;
SELECT ph FROM
A => {
LABLBA;
SABSBA;
IF LoadStage1Ac THEN {
lPipe[1][a] ← lPipe[0][b];
sPipe[1][a] ← sPipe[0][b]};
IF LoadStage2Ac THEN {
lPipe[2][a] ← lPipe[1][b];
sPipe[2][a] ← sPipe[1][b]};
IF LoadStage3Ac THEN {
lPipe[3][a] ← lPipe[2][b];
sPipe[3][a] ← sPipe[2][b]};
IF X1ADstSLimitAc THEN sLimitAB ← XBus MOD 256;
IF X1ASrcSLimitAc THEN XBus ← sLimitAB};
ab => NULL;
B => {
status: DragOpsCross.StackedStatusWord;
lBusLtB, lBusRtB: Dragon.HexByte;
sBusLt, sBusRt: Dragon.HexByte;
DeltaSBA ← ( 256 +
(IF PushScBA THEN 1 ELSE 0) +
(IF PopSaBA  THEN -1 ELSE 0) +
(IF PopSbBA  THEN -1 ELSE 0) ) MOD 256;
lPipe[0][b] ← LAB;
lBusLtB ← SELECT LSourceLtBA FROM
l   => LAB,
s   => SAB,
zero  => 0,
l3   => lPipe[3][a],
ENDCASE => ERROR IFUInconsistent;
lBusRtB ← SELECT LSourceRtBA FROM
zero  => 0,
alpha  => AlphaBA,
stack  => ToStatus[LFStkTopAB].lBase,
one  => 1,
ENDCASE => ERROR IFUInconsistent;
LBA ← (lBusLtB + lBusRtB) MOD 128;
sPipe[0][b] ← SAB;
sBusLt ← SELECT SSourceLtBA FROM
s   => SAB,
l   => LAB,
s2   => sPipe[2][a],
s3   => sPipe[3][a],
ENDCASE => ERROR IFUInconsistent;
sBusRt ← SELECT SSourceRtBA FROM
deltaS  => DeltaSBA,
alpha  => AlphaBA,
zero  => 0,
one  => 1,
ENDCASE => ERROR IFUInconsistent;
SBA ← (sBusLt+sBusRt+256) MOD 128;
IF LoadStage1Bc THEN {
lPipe[1][b] ← lPipe[1][a];
sPipe[1][b] ← sPipe[1][a] };
lPipe[2][b]  ← lPipe[2][a];
sPipe[2][b]  ← sPipe[2][a];
lPipe[3][b]  ← lPipe[3][a];
status    ← ToStatus[LFPipe3BA];
status.lBase  ← lPipe[3][b];
LFPipe3BA  ← FromStatus[status];
EStkOverflow1BA ← ((SAB+(255-sLimitAB)+1) MOD 128) IN [0..16)};
ba => NULL;
ENDCASE => ERROR IFUInconsistent};
IFULSRef:     ModSim ← NEW[ModSimRec ← [IFULS]];
IFUABC:      PUBLIC ModuleSimProc = {
OPEN state;
noStore: Dragon.HexByte = DragOpsCross.ProcessorRegister[euJunk].ORD;
SELECT ph FROM
A => {
A1IsC2B ← A1IsC3B ← B1IsC2B ← B1IsC3B ← TRUE; -- precharge
IF LoadStage1Ac THEN {
aPipe[1][a] ← aPipe[0][b];
bPipe[1][a] ← bPipe[0][b];
cPipe[1][a] ← cPipe[0][b];
};
a1BEarly1AB ← IF Stage1BHoldingAB THEN aPipe[1][b] ELSE aPipe[1][a];
b1BEarly1AB ← IF Stage1BHoldingAB THEN bPipe[1][b] ELSE bPipe[1][a];
IF LoadStage2Ac THEN cPipe[2][a] ← (SELECT TRUE FROM
Stage2ABubbleBA => noStore,
Stage2ANormalBA => cPipe[1][b],
ENDCASE    => ERROR IFUInconsistent);
IF LoadStage3Ac THEN cPipe[3][a] ← (SELECT TRUE FROM
Stage3AAbortBA  => noStore,
Stage3ANormalBA => cPipe[2][b],
ENDCASE    => ERROR IFUInconsistent)};
ab => NULL;
B => {
aBusLt, aBusRt: Dragon.HexByte;
bBusLt, bBusRt: Dragon.HexByte;
cBusLt, cBusRt: Dragon.HexByte;
aBusLt ← SELECT ARegLtBA FROM
cBase  => DragOpsCross.ProcessorRegister[euConstant].ORD,
aBase  => DragOpsCross.ProcessorRegister[euAux].ORD,
s   => SAB,
l   => LAB,
zero  => 0,
ENDCASE => ERROR IFUInconsistent;
aBusRt ← SELECT ARegRtBA FROM
alpha  => AlphaBA,
alpha47 => AlphaBA MOD 16,
op47  => OpBA MOD 16,
beta  => BetaBA,
beta03  => BetaBA/16,
beta47  => BetaBA MOD 16,
ENDCASE => SELECT ARegOffBA FROM
zero  => 0,
one  => 1,
two  => 2,
three  => 3,
minus4 => 256-4,
minus3 => 256-3,
minus2 => 256-2,
minus1 => 256-1,
ENDCASE => ERROR IFUInconsistent;
aPipe[0][b] ← SELECT ARegModBA FROM
half  => (aBusLt + aBusRt) MOD 128,
full  => (aBusLt + aBusRt) MOD 256,
ENDCASE => ERROR IFUInconsistent;
bBusLt ← SELECT BRegLtBA FROM
cBase => DragOpsCross.ProcessorRegister[euConstant].ORD,
aBase => DragOpsCross.ProcessorRegister[euAux].ORD,
s  => SAB,
l  => LAB,
zero => 0,
ENDCASE => ERROR IFUInconsistent;
bBusRt ← SELECT BRegRtBA FROM
op47  => OpBA MOD 16,
alpha  => AlphaBA,
alpha47 => AlphaBA MOD 16,
beta  => BetaBA,
beta03  => BetaBA/16,
beta47  => BetaBA MOD 16,
ENDCASE => SELECT BRegOffBA FROM
zero  => 0,
one  => 1,
two  => 2,
three  => 3,
minus4 => 256-4,
minus3 => 256-3,
minus2 => 256-2,
minus1 => 256-1,
ENDCASE => ERROR IFUInconsistent;
bPipe[0][b] ← SELECT BRegModBA FROM
half  => (bBusLt + bBusRt) MOD 128,
full => (bBusLt + bBusRt) MOD 256,
ENDCASE => ERROR IFUInconsistent;
cBusLt ← SELECT CRegLtBA FROM
cBase  => DragOpsCross.ProcessorRegister[euConstant].ORD,
aBase  => DragOpsCross.ProcessorRegister[euAux].ORD,
l   => LAB,
s   => SAB,
zero  => 0,
ENDCASE => ERROR IFUInconsistent;
cBusRt ← SELECT CRegRtBA FROM
beta  => BetaBA,
beta03  => BetaBA/16,
beta47  => BetaBA MOD 16,
op47  => OpBA MOD 16,
alpha  => AlphaBA,
alpha47 => AlphaBA MOD 16,
ENDCASE => SELECT CRegOffBA FROM
minus4 => 256-4,
minus3 => 256-3,
minus2 => 256-2,
minus1 => 256-1,
zero  => 0,
one  => 1,
two  => 2,
three  => 3,
ENDCASE => ERROR IFUInconsistent;
cPipe[0][b] ← SELECT CRegModBA FROM
half  => (cBusLt + cBusRt) MOD 128,
full  => (cBusLt + cBusRt) MOD 256,
ENDCASE => ERROR IFUInconsistent;
IF (a1BEarly1AB # cPipe[2][a]) THEN A1IsC2B ← FALSE;
IF (a1BEarly1AB # cPipe[3][a]) THEN A1IsC3B ← FALSE;
IF (b1BEarly1AB # cPipe[2][a]) THEN B1IsC2B ← FALSE;
IF (b1BEarly1AB # cPipe[3][a]) THEN B1IsC3B ← FALSE;
IF LoadStage1Bc THEN {
aPipe[1][b] ← aPipe[1][a] -- ( = a1BEarly1AB ) -- ;
bPipe[1][b] ← bPipe[1][a] -- ( = b1BEarly1AB ) -- ;
cPipe[1][b] ← cPipe[1][a]};
cPipe[2][b] ← (SELECT TRUE FROM
Stage2BAbortAB   => noStore,
Stage2BNormalAB  => cPipe[2][a],
ENDCASE     => ERROR IFUInconsistent);
cPipe[3][b] ← (SELECT TRUE FROM
Stage3BCPipeAbortAB => noStore,
Stage3BCPipeNormalAB => cPipe[3][a],
ENDCASE     => ERROR IFUInconsistent);
AReg0BA ← aPipe[0][b];
BReg0BA ← bPipe[0][b];
CReg0BA ← cPipe[0][b] };
ba => NULL;
ENDCASE => ERROR IFUInconsistent };
IFUABCRef:     ModSim ← NEW[ModSimRec ← [IFUABC]];
IFUControlPipe:    PUBLIC ModuleSimProc = {
OPEN state;
SELECT ph FROM
A => {
IF LoadStage1Ac THEN ctlPipe1AB ← [
x2ASrcLit:  X2ALitSourceBA # none,
push:    Push0BA,
pop:    Pop0BA,
kPadsIn:   KPadsIn0BA,
dpCmnd:   DPCmnd0BA,
aluOp:   EUAluOp0BA,
kIsRtOp:   KIsRtOp0BA,
condSel:   CondSel0BA,
condEffect:  CondEffect0BA,
fCtlIsRtOp:   FCtlIsRtOp0BA,
cIsField:   CIsField0BA,
rdFromPBus:  DPCmndIsRd0BA,
writeToPBus:  (Basics.BITAND[DPCmnd0BA.ORD, Dragon.wrt] = Dragon.wrt),
instFault:   InstFault0BA,
firstMicro:  InstStarting0BA ];
IF LoadStage2Ac THEN ctlPipe2AB ← (SELECT TRUE FROM
Stage2ANormalBA => [
x2ASrcLit:  ctlPipe1BA.x2ASrcLit,
push:    ctlPipe1BA.push,
pop:    ctlPipe1BA.pop,
kPadsIn:   ctlPipe1BA.kPadsIn,
dpCmnd:   ctlPipe1BA.dpCmnd,
aluOp:   ctlPipe1BA.aluOp,
condSel:   ctlPipe1BA.condSel,
condEffect:  ctlPipe1BA.condEffect,
cIsField:   ctlPipe1BA.cIsField,
rdFromPBus:  ctlPipe1BA.rdFromPBus,
writeToPBus:  ctlPipe1BA.writeToPBus,
eStkOverflow: EStkOverflow1BA,
st3AisCBus:  EUSt3AIsCBus1BA,
instFault:   ctlPipe1BA.instFault,
firstMicro:  ctlPipe1BA.firstMicro ],
Stage2ABubbleBA => [
x2ASrcLit:  FALSE,
push:    FALSE,
pop:    FALSE,
kPadsIn:   FALSE,
dpCmnd:   NoOp,
aluOp:   Or,
condSel:   False,
condEffect:  bubble,
cIsField:   FALSE,
rdFromPBus:  FALSE,
writeToPBus:  FALSE,
eStkOverflow: FALSE,
st3AisCBus:  FALSE,
instFault:   FALSE,
firstMicro:  FALSE ],
ENDCASE => ERROR IFUInconsistent);
IF LoadStage3Ac THEN ctlPipe3AB ← (SELECT TRUE FROM
Stage3ANormalBA => [
push:    ctlPipe2BA.push,
pop:    ctlPipe2BA.pop,
kPadsIn:   ctlPipe2BA.kPadsIn,
dpCmnd:   ctlPipe2BA.dpCmnd,
condSel:   ctlPipe2BA.condSel,
cIsField:   ctlPipe2BA.cIsField,
rdFromPBus:  ctlPipe2BA.rdFromPBus,
writeToPBus:  ctlPipe2BA.writeToPBus ],
Stage3AAbortBA => [
push:    FALSE,
pop:    FALSE,
kPadsIn:   FALSE,
dpCmnd:   NoOp,
condSel:   ctlPipe2BA.condSel,
cIsField:   FALSE,
rdFromPBus:  FALSE,
writeToPBus:  FALSE ],
ENDCASE => ERROR IFUInconsistent);
PushPendingAB ← ctlPipe1AB.push OR ctlPipe2AB.push OR ctlPipe3AB.push;
PopPendingAB ← ctlPipe1AB.pop OR ctlPipe2AB.pop OR ctlPipe3AB.pop;
p[II[EUAluOp].ORD].c    ← ctlPipe2AB.aluOp.ORD;
p[II[EUCondSel].ORD].c    ← ctlPipe2AB.condSel.ORD;
CondEffect2AB      ← ctlPipe2AB.condEffect;
CIsField2AB       ← ctlPipe2AB.cIsField;
CIsField3AB       ← ctlPipe3AB.cIsField;
EUCondSel3AB      ← ctlPipe3AB.condSel;
p[II[EURdFromPBus].ORD].b  ← ctlPipe3AB.rdFromPBus;
p[II[EUWriteToPBus].ORD].b  ← ctlPipe3AB.writeToPBus;
Push2AB        ← ctlPipe2AB.push;
Push3AB        ← ctlPipe3AB.push;
Pop3AB        ← ctlPipe3AB.pop;
};
ab => NULL;
B => {
DPCmnd0BA ← SELECT DPCmndSelBA FROM
beta  => LOOPHOLE[BetaAB],
ENDCASE => DPCmndBA;
EUAluOp0BA ← IF AluOpIsOp47BA
THENLOOPHOLE[OpAB MOD 16] ELSE AluOpBA;
CondSel0BA ← IF CondSelIsOp57BA
THENLOOPHOLE[OpAB MOD 8] ELSE CondSelBA;
IF LoadStage1Bc THEN ctlPipe1BA ← [
x2ASrcLit:  ctlPipe1AB.x2ASrcLit,
push:    ctlPipe1AB.push,
pop:    ctlPipe1AB.pop,
kIsRtOp:   ctlPipe1AB.kIsRtOp,
dpCmnd:   ctlPipe1AB.dpCmnd,
aluOp:   ctlPipe1AB.aluOp,
kPadsIn:   ctlPipe1AB.kPadsIn,
condSel:   ctlPipe1AB.condSel,
condEffect:  ctlPipe1AB.condEffect,
fCtlIsRtOp:  ctlPipe1AB.fCtlIsRtOp,
cIsField:   ctlPipe1AB.cIsField,
rdFromPBus:  ctlPipe1AB.rdFromPBus,
writeToPBus:  ctlPipe1AB.writeToPBus,
instFault:   ctlPipe1AB.instFault,
firstMicro:  ctlPipe1AB.firstMicro ];
ctlPipe2BA ← (SELECT TRUE FROM
Stage2BNormalAB => [
push:    ctlPipe2AB.push,
pop:    ctlPipe2AB.pop,
kPadsIn:   ctlPipe2AB.kPadsIn,
dpCmnd:   ctlPipe2AB.dpCmnd,
condSel:   ctlPipe2AB.condSel,
condEffect:  ctlPipe2AB.condEffect,
cIsField:   ctlPipe2AB.cIsField,
rdFromPBus:  ctlPipe2AB.rdFromPBus,
writeToPBus:  ctlPipe2AB.writeToPBus,
eStkOverflow: ctlPipe2AB.eStkOverflow,
st3AisCBus:  ctlPipe2AB.st3AisCBus,
instFault:   ctlPipe2AB.instFault,
firstMicro:  ctlPipe2AB.firstMicro ],
Stage2BAbortAB => [
push:    FALSE,
pop:    FALSE,
kPadsIn:   FALSE,
dpCmnd:   NoOp,
condSel:   False,
condEffect:  bubble,
cIsField:   FALSE,
rdFromPBus:  FALSE,
writeToPBus:  FALSE,
eStkOverflow: FALSE,
st3AisCBus:  FALSE,
instFault:   FALSE,
firstMicro:  FALSE ],
ENDCASE => ERROR IFUInconsistent);
ctlPipe3BA ← [
kPadsIn:    ctlPipe3AB.kPadsIn,
cIsField:    ctlPipe3AB.cIsField ];
X2ASrcLit1BA   ← ctlPipe1BA.x2ASrcLit;
KIsRtOp1BA    ← ctlPipe1BA.kIsRtOp;
FCtlIsRtOp1BA   ← ctlPipe1BA.fCtlIsRtOp;
CondEffect1BA   ← ctlPipe1BA.condEffect;
DPCmndIsRd2BA  ← ctlPipe2BA.rdFromPBus;
CondEffect2BA   ← ctlPipe2BA.condEffect;
EStkOverflow2BA  ← ctlPipe2BA.eStkOverflow;
EUSt3AIsCBus2BA  ← ctlPipe2BA.st3AisCBus;
InstFault2BA    ← ctlPipe2BA.instFault;
InstStarting2BA   ← ctlPipe2BA.firstMicro;
KPadsIn3BA    ← ctlPipe3BA.kPadsIn;
DPCmnd2BA ← IF (Stage3ANormalBA AND NOT DPRejectBA)
THEN ctlPipe2BA.dpCmnd ELSE NoOp;
p[II[DPCmd].ORD].c ← DPCmnd2BA.ORD};
ba  => NULL;
ENDCASE => ERROR IFUInconsistent };
IFUControlPipeRef:   ModSim ← NEW[ModSimRec ← [IFUControlPipe]];
IFUKBusIn:     PUBLIC ModuleSimProc =
{OPEN state; IF ph=A AND KPadsIn3BA THEN XBus ← p[II[KBus].ORD].lc};
IFUKBusInRef:    ModSim ← NEW[ModSimRec ← [IFUKBusIn]];
IFUKBusOut:     PUBLIC ModuleSimProc = {
OPEN state;
IF ph=B THEN XBus ← LOOPHOLE[IFUTop.RegAddrRec[
aAddr:  aPipe[1][b],
bAddr:  bPipe[1][b],
cAddr:  cPipe[3][b],
st3AisC:  EUSt3AIsCBus2BA,
aluLeftSrc: EUAluLeftSrc1B,
aluRightSrc: EUAluRightSrc1B,
storeSrc:  EUStore2ASrc1B ]];
IF ph=A THEN xAB ← XBus;
IF ph=B OR (ph=A AND NOT KPadsIn3BA)
THEN { p[II[KBus].ORD].d ← drive; p[II[KBus].ORD].lc ← XBus}
ELSE  p[II[KBus].ORD].d ← none };
IFUKBusOutRef:    ModSim ← NEW[ModSimRec ← [IFUKBusOut]];
IFULogger:     PUBLIC ModuleSimProc = {
OPEN state;
log: IO.STREAMNIL;
NewDisposition: PROC [ pipeState: IFUTop.LogPipeState, disp: IFUTop.MicroInstDisposition ]
RETURNS [ newPipeState: IFUTop.LogPipeState ] = {
newPipeState ← pipeState;
newPipeState.disposition ← disp};
SELECT ph FROM
A => {
bHigh ← FALSE;
dpRejectedAB ← DPRejectBA;
IF LoadStage1Ac THEN opPipe[1][a] ← opPipe[0][b];
IF LoadStage2Ac THEN opPipe[2][a] ← (SELECT TRUE FROM
Stage2ANormalBA => opPipe[1][b],
Stage2ABubbleBA => NewDisposition[opPipe[1][b], interlocked],
ENDCASE    => ERROR IFUInconsistent);
IF LoadStage3Ac THEN opPipe[3][a] ← (SELECT TRUE FROM
Stage3ANormalBA => opPipe[2][b],
Stage3AAbortBA => NewDisposition[opPipe[2][b], killed3a],
ENDCASE    => ERROR IFUInconsistent)};
ab => bHigh ← FALSE;
B => {
bHigh ← TRUE;
opPipe[0][b] ← [
pc:   PCForLogAB,
op:   VAL[OpAB],
alpha:   AlphaAB,
beta:   BetaAB,
gamma:  GammaAB,
delta:   DeltaAB,
microCyc: StateAB,
disposition: IF InstReadyAB THEN valid ELSE unready ];
IF LoadStage1Bc THEN opPipe[1][b] ← opPipe[1][a];
opPipe[2][b] ← (SELECT TRUE FROM
Stage2BNormalAB => opPipe[2][a],
Stage2BAbortAB  => NewDisposition[opPipe[2][a], killed2b],
ENDCASE    => ERROR IFUInconsistent);
opPipe[3][b] ← opPipe[3][a];
IF Stage3BCPipeAbortAB THEN opPipe[3][b].disposition ← killed3b;
xbusBCopy ← XBus;
doTrap3BA ← SELECT ExceptAB.code FROM
none, cJump => FALSE,
ENDCASE => TRUE;
IF last#B THEN {
Log instruction at the beginning of Ph0B.
IF ((log ← state.data.getLog[state.data.data]) # NIL) AND
(ExceptAB # [specialCode, reset]) THEN {
IF (ExceptAB # [specialCode, none]) OR InstReadyAB THEN {
log.PutF["\n%5g%5g", IO.int[state.data.getCycle[state.data.data]], IO.int[instrCount] ];
SELECT TRUE FROM
ExceptAB=[specialCode, reseting  ]  => log.PutF["**Reseting "];
ExceptAB=[specialCode, reset   ]  => log.PutF["**Reset "];
ExceptAB=[dpFault      ]  => log.PutF["**DPFault "];
    dpRejectedAB      => log.PutF["**DPReject "];
ExceptAB=[condCode     ]  => log.PutF["**EUCC "];
ExceptAB=[specialCode, bubble  ]  => log.PutF["**Bubble "];
ExceptAB=[specialCode, cJump  ]  => log.PutF["**CJRestrt "];
ExceptAB=[specialCode, rschlWait  ]  => log.PutF["**Reschdl "];
ExceptAB=[specialCode, iStkOFlow ]  => log.PutF["**IStkOver "];
ExceptAB=[specialCode, eStkOFlow ]  => log.PutF["**EStkOver "];
ExceptAB=[specialCode, ipFault  ]  => log.PutF["**IPgFault "];
ExceptAB=[specialCode, none   ]  => log.PutF[" "];
ENDCASE   => log.PutF[" cy: %2g ", IO.card[ExceptAB.code.ORD]];
log.PutF["pc:%08x", IO.card[PCForLogAB] ];
SELECT TRUE FROM
dpRejectedAB  => log.PutF[" --EU reject delay..."];
NOT InstReadyAB => log.PutF[" --IFetch delay..."];
ENDCASE    => {
opLength: [0..5] = DragonRosemary.OpLength[OpAB];
log.PutF[" %-7g", IO.rope[Rope.Cat[DragonRosemary.OpName[OpAB],
(IF StateAB=0 THEN "" ELSE IO.PutFR["-%g", IO.int[StateAB]])]]];
IF opLength > 1
THEN log.PutF[" %02x", IO.card[AlphaAB]] ELSE log.PutF[" "];
IF opLength > 2
THEN log.PutF["%02x", IO.card[BetaAB]] ELSE log.PutF[" "];
IF opLength > 3
THEN log.PutF["%02x%02x", IO.card[GammaAB], IO.card[DeltaAB]]
ELSE log.PutF[" "];
log.PutF[" l:%02x", IO.card[LAB]]; -- at beginning of instruction
log.PutF[ " s:%02x", IO.card[SAB]]; -- at beginning of instruction
logRegistersB ← TRUE} } };
IF ExceptAB = [specialCode, reset] THEN instrCount ← -1 } }; -- of b
ba =>
IF bHigh THEN { -- the falling edge of B
bHigh ← FALSE;
IF logRegistersB THEN {
IF ((log ← state.data.getLog[state.data.data]) # NIL) THEN {
log.PutF[" a:%02x", IO.card[AReg0BA]];
log.PutF[ " b:%02x", IO.card[BReg0BA]];
log.PutF[ " c:%02x", IO.card[CReg0BA]]};
logRegistersB ← FALSE};
SELECT opPipe[3][b].microCyc FROM
113 => {trapped ← FALSE; instrCount ← -1};  -- Reset finished
116 => {trapped ← TRUE};       -- first cycle of trap
0 => {
incrInstrCount: BOOLSELECT opPipe[3][b].disposition FROM
valid  => TRUE,
killed3a,
killed3b => (StateAB = 116), -- trap that will apply to new instr
ENDCASE => FALSE;
IF NOT DPRejectBA AND incrInstrCount THEN {
The first microinstruction of a new macroinstruction instrCount+1 is now committed to retire, either in victory or defeat (as in "trapped"). This means that all register stores for the macroinstruction instrCount are completed, and none for macroinstruction instrCount+1 have yet occurred.
instrCount ← instrCount +
state.data.checkSynch[
data:  state.data.data,
basicInst: [ -- the completed instruction
cycle:    cycle,
instr:    instrCount,
trapped:   trapped,
trapPC:   IF trapped THEN opPipe[3][b].pc ELSE 0,
pc:    firstMicroOfMacro.pc,
op:    firstMicroOfMacro.op,
alpha:    firstMicroOfMacro.alpha,
beta:    firstMicroOfMacro.beta,
gamma:   firstMicroOfMacro.gamma,
delta:    firstMicroOfMacro.delta ]
].deltaInstrCount;
firstMicroOfMacro ← opPipe[3][b];
trapped    ← FALSE} };
ENDCASE => NULL}; -- end of ba
ENDCASE => ERROR IFUInconsistent;
last ← ph};
IFULoggerRef:    ModSim ← NEW[ModSimRec ← [IFULogger]];
normalConvergencePasses: NAT ← 1;
modulesA: LIST OF REF ANYLIST[IFUPreRef, IFUInstrDecodeRef, IFUControlPipeRef, IFUFetchRef, IFUKBusInRef, IFULitGenRef, IFUPCRef, IFULSRef, IFUStatusRef, IFUABCRef, IFUInterlockRef, IFUStackRef, IFUMainPipeControlRef, IFUMicroCycleRef, IFUPostRef, IFUKBusOutRef, IFULoggerRef];
modulesB: LIST OF REF ANYLIST[IFUPreRef, IFUInstrDecodeRef, IFUControlPipeRef, IFUKBusInRef, IFULitGenRef, IFUPCRef, IFULSRef, IFUFetchRef, IFUStatusRef, IFUABCRef, IFUInterlockRef, IFUStackRef, IFUMainPipeControlRef, IFUMicroCycleRef, IFUPostRef, IFUKBusOutRef, IFULoggerRef];
CreateIFU: PUBLIC PROC[ typeData: REF IFUTop.IFUTypeData, fullIFU, quickIFU, rawIFU: BOOLFALSE ]
RETURNS [ ct: Core.CellType ] = {
ct ← SELECT TRUE FROM
rawIFU => ERROR,
fullIFU => CoreOps.Recast[CoreIO.RestoreCellType["IFU"]],
quickIFU,
ENDCASE => CoreOps.CreateCellType[
class:  CoreClasses.unspecifiedCellClass,
public: IFUPublic.IfuInitializedPublic[],
name:  "IFU"];
CoreProperties.PutCellTypeProp[ct, $ClusterInfo, typeData];
MarkMemoryWires[ct.public[CoreOps.GetWireIndex[ct.public, "DPFault"]]];
MarkMemoryWires[ct.public[CoreOps.GetWireIndex[ct.public, "IPFaulting"]]];
MarkMemoryWires[ct.public[CoreOps.GetWireIndex[ct.public, "DPReject"]]];
MarkMemoryWires[ct.public[CoreOps.GetWireIndex[ct.public, "IPReject"]]];
MarkMemoryWires[ct.public[CoreOps.GetWireIndex[ct.public, "IPData"]]];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: IFURoseClass]};
MarkMemoryWires: PUBLIC PROC[wire: Core.Wire] = {
IF wire.size=0 THEN []←Rosemary.SetWire[wire, L, charge, TRUE];
FOR i: INT IN [0..wire.size) DO MarkMemoryWires[wire[i]] ENDLOOP};
IFUInit:   PROC
[cellType: Core.CellType, p: Ports.Port, oldStateAny: REF ANYNIL, steady: BOOLFALSE]
RETURNS [stateAny: REF ANYNIL, stateValue: Ports.LevelSequence ← NIL ] = {
Rosemary.InitProc
state:    IFUState ← NEW[IFUStateRec];
oldState:   IFUState ← NEW[IFUStateRec];
currentOffset: NAT ← 0;
state.data     ← NARROW[CoreProperties.GetCellTypeProp[cellType, $ClusterInfo]];
state.public    ← cellType.public;
state.oldP     ← Ports.CreatePort[cellType];
state.maxConvergPasses ← normalConvergencePasses;
state.oldState    ← oldState;
IFUPost[p, state]; -- gets multiplexers to a logically acceptable state
FOR psc: LIST OF REF ANY ← plaShiftChain, psc.rest WHILE psc # NIL DO
psce: REF PLAShiftChainEntry = NARROW[psc.first];
state.plaOffsets[psce.pla][psce.sense] ← currentOffset;
currentOffset ← currentOffset+IFUPLA.plaSizes[psce.pla][psce.sense];
ENDLOOP;
state.drShifterAB.size ← state.drShifterBA.size ← currentOffset + debugRegSize;
FOR pla: IFUPLA.PLAs IN IFUPLA.PLAs DO
state.plaBuffers[pla][input] ← UncountedAssignHack.UncountedSmallNewProc[IFUPLA.plas[pla].data];
state.plaBuffers[pla][output] ← UncountedAssignHack.UncountedSmallNewProc[IFUPLA.plas[pla].out];
ENDLOOP;
stateAny ← state};
PLAEval:  PROC [ state: IFUState, pla: IFUPLA.PLAs ] = {
OPEN state;
UncountedAssignHack.UncountedSmallAssignPlease[src: plaBuffers[pla][input], dst: IFUPLA.plas[pla].data];
IFUPLA.IFUPLAEval[pla];
IF NOT state.drShWt THEN
UncountedAssignHack.UncountedSmallAssignPlease[dst: state.plaBuffers[pla][output], src: IFUPLA.plas[pla].out]};
IFUSimple: Rosemary.EvalProc = {
state: IFUState = NARROW[stateAny];
OnePass: PROC [ modules: LIST OF REF ANYNIL ] = {
IF modules = NIL THEN
modules ← (SELECT state.ph FROM
A, ab => modulesA,
B, ba => modulesB,
ENDCASE => ERROR);
FOR m: LIST OF REF ANY ← modules, m.rest WHILE m # NIL DO
module: ModSim = NARROW[m.first];
module.proc[p, state];
ENDLOOP};
SELECT TRUE FROM
p[II[PhA].ORD].b => state.ph ← A;
p[II[PhB].ORD].b  => state.ph ← B;
(state.ph = A)  => state.ph ← ab;
(state.ph = B)  => state.ph ← ba;
ENDCASE    => NULL;
state.drShWt ← p[II[DShWt].ORD].b;
FOR pass: NAT IN [1..state.maxConvergPasses] DO OnePass[] ENDLOOP;
DO
sameVals: BOOLTRUE;
Ports.CopyPortValue[from: p, to: state.oldP];
state.initialized ← state.oldState.initialized OR state.ph=ba;
state.oldState^ ← state^;
OnePass[];
Ports.CheckPortValue[root: state.public, truth: state.oldP, question: p !
Ports.CheckError => {sameVals ← FALSE; REJECT}];
IF state.oldState^ # state^ THEN {
difFields: LIST OF ROPE = EqualCheck.FindDif[state, state.oldState];
IF state.initialized THEN {
TerminalIO.PutF[
"IFU state, including field %g, failed to converge after %g passes.\n",
IO.rope[difFields.first], IO.int[state.maxConvergPasses] ];
Ports.CheckError[IO.PutFR
["IFU state, including field %g, failed to converge after %g passes.",
IO.rope[difFields.first], IO.int[state.maxConvergPasses]]];
state.maxConvergPasses ← state.maxConvergPasses+1};
LOOP};
IF sameVals THEN EXIT;
state.maxConvergPasses ← state.maxConvergPasses+1;
ENDLOOP};
PLAShiftChainEntry: TYPE = RECORD [ pla: IFUPLA.PLAs, sense: IFUPLA.Sense ];
plaShiftChain:   LIST OF REF ANY -- REF PLAShiftChainEntry --LIST [
Left column ...
NEW[PLAShiftChainEntry ← [pla: interlock,    sense: input]],
NEW[PLAShiftChainEntry ← [pla: interlock,    sense: output]],
NEW[PLAShiftChainEntry ← [pla: mainPipeControl,  sense: input]],
NEW[PLAShiftChainEntry ← [pla: mainPipeControl,  sense: output]],
NEW[PLAShiftChainEntry ← [pla: stackBControl,  sense: input]],
NEW[PLAShiftChainEntry ← [pla: stackBControl,  sense: output]],
NEW[PLAShiftChainEntry ← [pla: stackAControl,  sense: input]],
NEW[PLAShiftChainEntry ← [pla: stackAControl,  sense: output]],
NEW[PLAShiftChainEntry ← [pla: stackDecode,   sense: input]],
NEW[PLAShiftChainEntry ← [pla: stackDecode,   sense: output]],
NEW[PLAShiftChainEntry ← [pla: ltDrPadIO,   sense: input]],
NEW[PLAShiftChainEntry ← [pla: fetchControl,   sense: input]],
NEW[PLAShiftChainEntry ← [pla: fetchControl,   sense: output]],
NEW[PLAShiftChainEntry ← [pla: fetchWtDecode,  sense: input]],
NEW[PLAShiftChainEntry ← [pla: fetchWtDecode,  sense: output]],
NEW[PLAShiftChainEntry ← [pla: fetchRdDecode,  sense: input]],
NEW[PLAShiftChainEntry ← [pla: fetchRdDecode,  sense: output]],
Right column ...
NEW[PLAShiftChainEntry ← [pla: rtDrPadIO,   sense: input]],
NEW[PLAShiftChainEntry ← [pla: instrDecode0,   sense: output]],
NEW[PLAShiftChainEntry ← [pla: instrDecode1,   sense: output]],
NEW[PLAShiftChainEntry ← [pla: instrDecode2,   sense: output]],
NEW[PLAShiftChainEntry ← [pla: instrDecode3,   sense: output]],
NEW[PLAShiftChainEntry ← [pla: instrDecode4,   sense: output]],
NEW[PLAShiftChainEntry ← [pla: instrDecode5,   sense: output]],
NEW[PLAShiftChainEntry ← [pla: instrDecode6,   sense: output]],
NEW[PLAShiftChainEntry ← [pla: instrDecode0,   sense: input]] ];
IFUCmdProc: PROC -- Commander.CommandProc
[cmd: Commander.Handle] RETURNS [result: REFNIL, msg: Rope.ROPENIL] = {NULL};
Commander.Register["IFUTop", IFUCmdProc];
END.