IFU2Impl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
McCreight, June 6, 1986 4:25:49 pm PDT
DIRECTORY Basics, Commander, Core, CoreClasses, CoreCreate, CoreOps, CoreProperties, Dragon, DragonRosemary, DragOpsCross, DragOpsCrossUtils, EqualCheck, IFU2, IFUPLA, IFUPLAFetchControl, IFUPLAFetchPreDecode, IFUPLAFetchDecode, IFUPLAInstrDecode, IFUPLAInterlock, IFUPLAMainControl, IFUPLAStackControl, IO, Ports, REFBit, Rope, Rosemary, UncountedAssignHack;
IFU2Impl: CEDAR PROGRAM
IMPORTS Basics, Commander, CoreClasses, CoreCreate, CoreOps, CoreProperties, DragonRosemary, DragOpsCrossUtils, EqualCheck, IFUPLA, IO, Rope, Rosemary, Ports, REFBit, UncountedAssignHack
EXPORTS IFU2
= BEGIN OPEN IFU2, Core;
IFUName: ROPE = Rosemary.Register[roseClassName: "IFU", init: IFUInit, evalSimple: IFUSimple];
PortData: TYPE = RECORD [ name: Core.ROPE, width: NAT ← 1, drive: Ports.Drive ← none ];
iITypes: ARRAY II OF PortData ← [
KBus: ["KBus", 32],
EUAluOp2AB: ["EUAluOp2AB", 4, drive],
EUCondSel2AB: ["EUCondSel2AB", 4, drive],
EUCondition2B: ["EUCondition2B"],
EURes3BisPBus3AB: ["EURes3BisPBus3AB", , drive],
EUWriteToPBus3AB: ["EUWriteToPBus3AB", , drive], -- EU
DPCmdA: ["DPCmdA", 8, drive], -- Data cache
DPRejectB: ["DPRejectB"],
DPFaultB: ["DPFaultB", 5],
IPData: ["IPData", 32], -- Instruction cache
IPCmdA: ["IPCmdA", 8, drive],
IPRejectB: ["IPRejectB"],
IPFaultB: ["IPFaultB", 5],
DrShA: ["DrShA"],
DrShB: ["DrShB"],
DrShRd: ["DrShRd"],
DrShWt: ["DrShWt"],
DrShIn: ["DrShIn"],
DrShOut: ["DrShOut"],
PhA: ["PhA"],
PhB: ["PhB"],
ResetAB: ["ResetAB"],
RescheduleAB: ["RescheduleAB"]
];
IFUPre: PUBLIC ModuleSimProc =
BEGIN OPEN state;
LoadStage1Ac ← ph=a AND wantNewMicro0BA; -- set conditional pipeline advance clocks
LoadStage1Bc ← ph=b AND NOT stage1BHoldingAB;
LoadStage2Ac ← ph=a AND (NOT (DPRejectedBA -- AND Stage1BHoldIfRejectBA -- ) OR ResetBA);
LoadStage3Ac ← ph=a AND (NOT DPRejectedBA OR ResetBA);
IF ph=a THEN {
stage1BHoldingAB ← (EUCondEffect1BA # bubble AND (Stage1BHoldBA OR (DPRejectedBA -- AND Stage1BHoldIfRejectBA -- ))) OR ResetBA;
};
IF ph=b THEN {
ResetBA ← p[II[ResetAB].ORD].b;
DPRejectedBA ← p[II[DPRejectB].ORD].b;
};
IF p[II[DrShA].ORD].b THEN {
inputBit: BOOL = p[II[DrShIn].ORD].b;
DragonRosemary.Assert[ NOT p[II[DrShRd].ORD].b, "Error in IFU shifter clocking sequence" ];
IF NOT p[II[DrShB].ORD].b THEN { -- shift drShifterAB from drShifterBA
drShifterAB.bits[0] ← inputBit;
FOR i: NAT IN [1..drShifterAB.size) DO
drShifterAB.bits[i] ← NOT drShifterBA.bits[i-1];
ENDLOOP;
}
ELSE { -- mass copy drShifterAB from DrShIn
FOR i: NAT IN [0..drShifterAB.size) DO
drShifterAB.bits[i] ← NOT inputBit;
ENDLOOP;
};
};
DragonRosemary.Assert[ NOT (p[II[DrShRd].ORD].b AND p[II[DrShWt].ORD].b), "Error in IFU shifter clocking sequence"];
IF p[II[DrShWt].ORD].b THEN -- broadside copy from shift register
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
REFBit.Set[buf, i, drShifterAB.bits[offset+i]];
ENDLOOP;
};
ENDLOOP;
ENDLOOP;
END;
IFUPreRef: ModSim ← NEW[ModSimRec ← [IFUPre]];
IFUPost: PUBLIC ModuleSimProc =
BEGIN OPEN state;
NormalStage2B2AB ← NOT AbortStage2B2AB; -- set default multiplexer stages
NormalStage2A1BA ← NOT BubbleStage2A1BA;
NormalStage2A1BA ← NOT BubbleStage2A1BA;
NormalStage3A2BA ← NOT AbortStage3A2BA;
IF p[II[DrShRd].ORD].b THEN -- broadside copy into shift register
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
drShifterAB.bits[offset+i] ← NOT REFBit.Get[buf, i];
ENDLOOP;
};
ENDLOOP;
ENDLOOP;
IF p[II[DrShB].ORD].b THEN { -- shift drShifterBA from drShifterAB
FOR i: NAT IN [0..drShifterAB.size) DO
drShifterBA.bits[i] ← NOT drShifterAB.bits[i];
ENDLOOP;
};
p[II[DrShOut].ORD].b ← drShifterBA.bits[drShifterAB.size-1];
END;
IFUPostRef: ModSim ← NEW[ModSimRec ← [IFUPost]];
IFUInstrDecode: PUBLIC ModuleSimProc =
BEGIN OPEN state;
X1ASrcSLimitAc ← ph=a AND x1ASrcSLimitBA;
X1ADstSLimitAc ← ph=a AND x1ADstSLimitBA;
SELECT ph FROM
a => {
PCBusSrcB ← offSetPC; -- precharge
};
postA => {
IF NOT drShWt THEN
NARROW[plaBuffers[instrDecode0][input], REF IFUPLAInstrDecode.InstrDecodeIn]^ ← [
state:    StateAB,
instReady:  InstReadyAB,
op:    DragOpsCross.Inst[VAL[OpAB]],
alpha:    AlphaAB,
beta:    BetaAB,
pushPending: PushPendingAB,
popPending:  PopPendingAB,
userMode:  UserMode0AB
];
All seven instruction decoding sub-PLA's are strung on these input wires, and attached to the same input record.
};
b => {
nextMacroBA:   IFUPLAInstrDecode.NextMacro;
preEUAluOp0BA:  Dragon.ALUOps;
aluOpIs47BA:   BOOL;
preEUCondSel0BA:  Dragon.CondSelects;
condSelIsOp57BA:  BOOL;
preDPCmnd0BA:   Dragon.PBusCommands;
preDPCmndSel0BA:  IFUPLAInstrDecode.DPCmndSel;
PLAEval[state, instrDecode0]; -- all precharged
PLAEval[state, instrDecode1];
PLAEval[state, instrDecode2];
PLAEval[state, instrDecode3];
PLAEval[state, instrDecode4];
PLAEval[state, instrDecode5];
PLAEval[state, instrDecode6];
[
instStarting0:   InstStarting0BA,
nextMacro:   nextMacroBA,
macroJump:   MacroJumpBA,
pcNext:    PCNextBA,
pcBusSrc:    PCBusSrcB,
pcPipeSrc:   PCPipeSrcBA,
x2ALitSource:  X2ALitSourceBA,
kPadsIn:    KPadsIn0BA,
push:     Push0BA
] ← NARROW[plaBuffers[instrDecode0][output], REF IFUPLAInstrDecode.InstrDecodeOut]^;
[
microCycleNext:  MicroCycleNextBA,
clearTrapsEnbled: ClearTrapsEnbledBA,
clearUserMode:  ClearUserModeBA,
pop:     Pop0BA,
dpCmnd:    preDPCmnd0BA,
dpCmndIsRd:   DPCmndRd0BA,
dpCmndSel:   preDPCmndSel0BA
] ← NARROW[plaBuffers[instrDecode1][output], REF IFUPLAInstrDecode.InstrDecodeOut]^;
[aReg:     [ASourceLtBA, ASourceRtBA, ASourceOffBA, ASourceModBA]
] ← NARROW[plaBuffers[instrDecode2][output], REF IFUPLAInstrDecode.InstrDecodeOut]^;
[bReg:     [BSourceLtBA, BSourceRtBA, BSourceOffBA, BSourceModBA]
] ← NARROW[plaBuffers[instrDecode3][output], REF IFUPLAInstrDecode.InstrDecodeOut]^;
[
kIsRtOp:    KIsRtOp0BA,
fCtlIsRtOp:   FCtlIsRtOp0BA,
pushSc:    PushSc0BA,
cReg:     [CSourceLtBA, CSourceRtBA, CSourceOffBA, CSourceModBA]
] ← NARROW[plaBuffers[instrDecode4][output], REF IFUPLAInstrDecode.InstrDecodeOut]^;
[
lSource:    [LSourceLtBA, LSourceRtBA],
sSource:    [SSourceLtBA, SSourceRtBA],
popSa:     PopSa0BA,
popSb:    PopSb0BA
] ← NARROW[plaBuffers[instrDecode5][output], REF IFUPLAInstrDecode.InstrDecodeOut]^;
[
aluOp:    preEUAluOp0BA,
aluOpIsOp47:   aluOpIs47BA,
condSel:    preEUCondSel0BA,
condSelIsOp57:  condSelIsOp57BA,
condEffect:   EUCondEffect0BA,
x1ASrcSLimit:  x1ASrcSLimitBA,
x2ASrcStatus:   X2ASrcStatusBA,
x1ASrcStack:   X1ASrcStackBA,
x1ADstSLimit:  x1ADstSLimitBA,
x1ADstStatus:  X1ADstStatusBA,
x1ADstStack:   X1ADstStackBA,
xBusStackEldest:  XBusStackEldestBA,
xBusStackL:   XBusStackLBA,
cRegIsField:   CIsField0BA
] ← NARROW[plaBuffers[instrDecode6][output], REF IFUPLAInstrDecode.InstrDecodeOut]^;
DPCmnd0BA ← SELECT preDPCmndSel0BA FROM
beta  => LOOPHOLE[BetaAB],
ENDCASE => preDPCmnd0BA;
EUAluOp0BA ← IF aluOpIs47BA
THENLOOPHOLE[OpAB MOD 16] ELSE preEUAluOp0BA;
EUCondSel0BA ← IF condSelIsOp57BA
THENLOOPHOLE[OpAB MOD 8] ELSE preEUCondSel0BA;
X2ASrcLit0BA ← X2ALitSourceBA # none;
GetNextInstBA ← nextMacroBA=get;
};
postB => NULL;
ENDCASE => ERROR IFUInconsistent;
END;
IFUInstrDecodeRef: ModSim ← NEW[ModSimRec ← [IFUInstrDecode]];
IFUMainControl: PUBLIC ModuleSimProc =
BEGIN OPEN state;
SELECT ph FROM
a => {
PLAEval[state, mainControl]; -- precharged
[
abortPipe:    abortPipeAB,
microExcptJmp:  MicroExcptJmpAB,
exceptionCode:  ExceptionCodeAB
] ← NARROW[plaBuffers[mainControl][output], REF IFUPLAMainControl.MainControlOut]^;
wantNewMicro0AB ← MicroExcptJmpAB # bubble;
AbortStage2B2AB ← abortPipeAB;
microCycleAB ← microCycleBA;
MicroCycleAB ← (SELECT MicroExcptJmpAB FROM
none => microCycleBA,
microJump => 64,
bubble => 112,
resetting => 116,
trap => 120,
cJump => 124,
ENDCASE => ERROR IFUInconsistent);
};
postA => NULL;
b => {
wantNewMicro0BA ← wantNewMicro0AB;
dpFaultedBA ← p[II[DPFaultB].ORD].c # Dragon.PBusFaults[none].ORD;
euCondition2BA ← p[II[EUCondition2B].ORD].b;
abortPipeBA ← abortPipeAB;
willBeProtMicroCycBA ← MicroCycleAB>=112 AND (MicroCycleNextBA = next);
stage2FailedBA ← ResetBA
OR abortPipeBA
OR (EUCondEffect2BA=macroTrap AND euCondition2BA)
OR (TrapsEnbled2BA AND
(EStkOverflow2BA
OR (InstStarting2BA AND RschWaiting2BA)
OR (Push2BA AND IStkNearlyFullBA)
));
BubbleStage2A1BA ← Stage1BHoldBA OR stage2FailedBA;
AbortStage3A2BA ← stage2FailedBA;
microCycleBA ← SELECT MicroCycleNextBA FROM
clear   => 0,
hold    => microCycleAB,
next   => MicroCycleAB +1,
ENDCASE => ERROR IFUInconsistent;
};
postB => {
IF NOT drShWt THEN
NARROW[plaBuffers[mainControl][input], REF IFUPLAMainControl.MainControlIn]^ ← [
reseting:    ResetBA,
protMicroCyc:  willBeProtMicroCycBA,
dpFaulted:   dpFaultedBA,
dpRejected:   DPRejectedBA,
euCondition2:  euCondition2BA,
euCondEffect2:  EUCondEffect2BA,
stage1Hold:   Stage1BHoldBA,
stage1HoldIfReject: Stage1BHoldIfRejectBA,
condEffect1:   EUCondEffect1BA,
instStarting2:   InstStarting2BA,
ipFaulted2:   IPFaulted2BA,
trapsEnbled2:  TrapsEnbled2BA,
rschlWaiting2:  RschWaiting2BA,
eStkOverflow2:  EStkOverflow2BA,
iStkNearlyFull2:  IStkNearlyFullBA,
push2:    Push2BA
];
};
ENDCASE => ERROR IFUInconsistent;
END;
IFUMainControlRef: ModSim ← NEW[ModSimRec ← [IFUMainControl]];
IFUControlPipe: PUBLIC ModuleSimProc =
BEGIN OPEN state;
SELECT ph FROM
a => {
IF LoadStage1Ac THEN ctlPipe1AB ← [
x2ASrcLit:  X2ASrcLit0BA,
push:    Push0BA,
pop:    Pop0BA,
kPadsIn:   KPadsIn0BA,
dpCmnd:   DPCmnd0BA,
aluOp:   EUAluOp0BA,
kIsRtOp:   KIsRtOp0BA,
condSel:   EUCondSel0BA,
condEffect:  EUCondEffect0BA,
fCtlIsRtOp:   FCtlIsRtOp0BA,
cIsField:   CIsField0BA,
res3BisPBus:  DPCmndRd0BA,
writeToPBus:  (Basics.BITAND[DPCmnd0BA.ORD, Dragon.wrt] = Dragon.wrt),
instFault:   IPFaulted0BA,
firstMicro:  InstStarting0BA
];
IF LoadStage2Ac THEN ctlPipe2AB ← (SELECT TRUE FROM
NormalStage2A1BA => [
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,
res3BisPBus:  ctlPipe1BA.res3BisPBus,
writeToPBus:  ctlPipe1BA.writeToPBus,
eStkOverflow: EStkOverflow1BA,
st3AisCBus:  EUSt3AisCBus1BA,
instFault:   ctlPipe1BA.instFault,
firstMicro:  ctlPipe1BA.firstMicro
],
BubbleStage2A1BA => [
x2ASrcLit:  FALSE,
push:    FALSE,
pop:    FALSE,
kPadsIn:   FALSE,
dpCmnd:   NoOp,
aluOp:   Or,
condSel:   False,
condEffect:  bubble,
cIsField: FALSE,
res3BisPBus:  FALSE,
writeToPBus:  FALSE,
eStkOverflow: FALSE,
st3AisCBus:  FALSE,
instFault:   FALSE,
firstMicro:  FALSE
],
ENDCASE => ERROR IFUInconsistent);
IF LoadStage3Ac THEN ctlPipe3AB ← (SELECT TRUE FROM
NormalStage3A2BA => [
push:    ctlPipe2BA.push,
pop:    ctlPipe2BA.pop,
kPadsIn:   ctlPipe2BA.kPadsIn,
dpCmnd:   ctlPipe2BA.dpCmnd,
condSel:   ctlPipe2BA.condSel,
cIsField:   ctlPipe2BA.cIsField,
res3BisPBus:  ctlPipe2BA.res3BisPBus,
writeToPBus:  ctlPipe2BA.writeToPBus
],
AbortStage3A2BA => [
push:    FALSE,
pop:    FALSE,
kPadsIn:   FALSE,
dpCmnd:   NoOp,
condSel:   ctlPipe2BA.condSel,
cIsField:   FALSE,
res3BisPBus:  FALSE,
writeToPBus:  FALSE
],
ENDCASE => ERROR IFUInconsistent);
PushPendingAB ← ctlPipe1AB.push OR ctlPipe2AB.push OR ctlPipe3AB.push;
PopPendingAB ← ctlPipe1AB.pop OR ctlPipe2AB.pop OR ctlPipe3AB.pop;
X2ASrcLit1BA   ← ctlPipe2AB.x2ASrcLit;
p[II[EUAluOp2AB].ORD].c   ← ctlPipe2AB.aluOp.ORD;
p[II[EUCondSel2AB].ORD].c   ← ctlPipe2AB.condSel.ORD;
EUCondEffect2AB  ← ctlPipe2AB.condEffect;
CIsField2AB   ← ctlPipe2AB.cIsField;
EUCondSel3AB   ← ctlPipe3AB.condSel;
DPCmnd3A    ← IF DPRejectedBA THEN NoOp ELSE ctlPipe3AB.dpCmnd;
p[II[DPCmdA].ORD].c ← DPCmnd3A.ORD;
p[II[EURes3BisPBus3AB].ORD].b ← ctlPipe3AB.res3BisPBus;
p[II[EUWriteToPBus3AB].ORD].b ← ctlPipe3AB.writeToPBus;
CIsField3AB   ← ctlPipe3AB.cIsField;
};
postA => NULL;
b => {
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,
res3BisPBus:  ctlPipe1AB.res3BisPBus,
writeToPBus:  ctlPipe1AB.writeToPBus,
instFault:   ctlPipe1AB.instFault,
firstMicro:  ctlPipe1AB.firstMicro
];
ctlPipe2BA ← (SELECT TRUE FROM
NormalStage2B2AB =>
[
push:    ctlPipe2AB.push,
pop:    ctlPipe2AB.pop,
kPadsIn:   ctlPipe2AB.kPadsIn,
dpCmnd:   ctlPipe2AB.dpCmnd,
condSel:   ctlPipe2AB.condSel,
condEffect:  ctlPipe2AB.condEffect,
cIsField:  ctlPipe2AB.cIsField,
res3BisPBus:  ctlPipe2AB.res3BisPBus,
writeToPBus:  ctlPipe2AB.writeToPBus,
eStkOverflow: ctlPipe2AB.eStkOverflow,
st3AisCBus:  ctlPipe2AB.st3AisCBus,
instFault:   ctlPipe2AB.instFault,
firstMicro:  ctlPipe2AB.firstMicro
],
AbortStage2B2AB => [
push:    FALSE,
pop:    FALSE,
kPadsIn:   FALSE,
dpCmnd:   NoOp,
condSel:   False,
condEffect:  bubble,
cIsField:  FALSE,
res3BisPBus:  FALSE,
writeToPBus:  FALSE,
eStkOverflow: FALSE,
st3AisCBus:  FALSE,
instFault:   FALSE,
firstMicro:  FALSE
],
ENDCASE => ERROR IFUInconsistent);
ctlPipe3BA ← [
push:    ctlPipe3AB.push OR (MicroExcptJmpAB = trap),
pop:    ctlPipe3AB.pop,
kPadsIn:   ctlPipe3AB.kPadsIn,
cIsField:  ctlPipe3AB.cIsField,
res3BisPBus:  ctlPipe3AB.res3BisPBus
];
KIsRtOp1BA    ← ctlPipe1BA.kIsRtOp;
FCtlIsRtOp1BA   ← ctlPipe1BA.fCtlIsRtOp;
EUCondEffect1BA  ← ctlPipe1BA.condEffect;
DPCmndRd2BA   ← ctlPipe2BA.res3BisPBus;
Push2BA     ← ctlPipe2BA.push;
EUCondEffect2BA  ← ctlPipe2BA.condEffect;
EStkOverflow2BA  ← ctlPipe2BA.eStkOverflow;
EUSt3AisCBus2BA  ← ctlPipe2BA.st3AisCBus;
IPFaulted2BA   ← ctlPipe2BA.instFault;
InstStarting2BA   ← ctlPipe2BA.firstMicro;
DPCmndRd3BA   ← ctlPipe3BA.res3BisPBus;
Push3BA     ← ctlPipe3BA.push;
Pop3BA     ← ctlPipe3BA.pop;
KPadsIn3BA    ← ctlPipe3BA.kPadsIn;
};
postB => NULL;
ENDCASE => ERROR IFUInconsistent;
END;
IFUControlPipeRef: ModSim ← NEW[ModSimRec ← [IFUControlPipe]];
IFUFetch: PUBLIC ModuleSimProc =
BEGIN OPEN state;
PA4BFromCard: PROC [ in: [0..16) ] RETURNS [ out: PACKED ARRAY [0..4) OF BOOL ] =
TRUSTED BEGIN out ← LOOPHOLE[in]; END;
PA16BFromCard: PROC [ in: CARDINAL ] RETURNS [ out: PACKED ARRAY [0..16) OF BOOL ] =
TRUSTED BEGIN out ← LOOPHOLE[in] END;
ipf, notInstReady: BOOL;
p[II[IPData].ORD].d ← (IF ph=a THEN drive ELSE none);
SELECT ph FROM
a => {
wtAB  ← wtBA; -- from FetchIndexing
rdAB  ← rdBA;
IF NOT drShWt THEN
NARROW[plaBuffers[fetchRdDecode][input], REF IFUPLAFetchDecode.FetchRdDecodeIn]^ ←
[
fetchRd: rdBA MOD 16
];
PLAEval[state, fetchRdDecode]; -- static
IBufRdByteAc ← PA16BFromCard[NARROW[plaBuffers[fetchRdDecode][output], REF IFUPLAFetchDecode.FetchRdDecodeOut]^];
BufBytesOccM1A ← (4*wtBA-rdBA-1+64) MOD 32;
jumpPendingAB  ← jumpPendingBA; -- from FetchControl
faultedAB   ← faultedBA;
FetchingAB   ← fetchingBA;
bufBytesOccM1AB ← BufBytesOccM1A;
p[II[IPCmdA].ORD].c ← (IF newFetchBA THEN Dragon.PBusCommands[Fetch].ORD ELSE Dragon.PBusCommands[NoOp].ORD);
p[II[IPData].ORD].lc ← fetchAddrBA/4; -- Byte to word happens here
fetchAddrAB ← fetchAddrBA+(IF IncrPFetchAddrBA THEN 4 ELSE 0); -- byte offset in loc 30,31
FOR j: [0..16) IN [0..16) DO -- from FetchBuffer
IF IBufRdByteAc[j] THEN {
preOpA  ← AND[preOpA,  iBuf[j]];
preAlphaA ← AND[preAlphaA, iBuf[(j+1) MOD 16]];
preBetaA  ← AND[preBetaA,  iBuf[(j+2) MOD 16]];
preGammaA ← AND[preGammaA, iBuf[(j+3) MOD 16]];
preDeltaA ← AND[preDeltaA,  iBuf[(j+4) MOD 16]] };
ENDLOOP;
OpAB ← preOpA ← iBuf[rdBA MOD 16];
AlphaAB ← preAlphaA ← iBuf[(rdBA+1) MOD 16];
BetaAB ← preBetaA ← iBuf[(rdBA+2) MOD 16];
GammaAB ← preGammaA ← iBuf[(rdBA+3) MOD 16];
DeltaAB ← preDeltaA ← iBuf[(rdBA+4) MOD 16];
};
postA => {
IBufRdByteAc ← ALL[FALSE]; -- from FetchIndexing
};
b => {
IF NOT drShWt THEN
NARROW[plaBuffers[fetchControl][input], REF IFUPLAFetchControl.FetchControlIn]^ ← [
jump:     MacroJumpBA,
getNext:    FALSE, -- not used, formerly GetNextInstBA
reset:     ResetBA,
reject:     p[II[IPRejectB].ORD].b,
jumpPending:  jumpPendingAB,
fetching:    FetchingAB,
bytesOccM1:   bufBytesOccM1AB,
faulted:    faultedAB,
ipPageFault:   (p[II[IPFaultB].ORD].c = Dragon.PBusFaults[page].ORD) -- this may be a long path; it can be pipeline delayed
];
PLAEval[state, fetchControl]; -- static
[ -- from FetchControl
jumpPending:  jumpPendingBA,
newFetch:   newFetchBA,
fetching:    fetchingBA,
faulted:    faultedBA,
wtIndexCtl:   FetchWtB
] ← NARROW[plaBuffers[fetchControl][output], REF IFUPLAFetchControl.FetchControlOut]^;
IncrPFetchAddrBA ← newFetchBA;
SELECT FetchWtB FROM -- from FetchIndexing
clear => wtBA ← 0;
hold => wtBA ← wtAB;
inc => wtBA ← (wtAB+1) MOD 8;
ENDCASE => ERROR IFUInconsistent;
rdBA ← (SELECT TRUE FROM
MacroJumpBA => PCBusB MOD DragOpsCross.bytesPerWord,
GetNextInstBA => (rdAB+OpLengthAB) MOD 32,
ENDCASE => rdAB);
IF NOT drShWt THEN
NARROW[plaBuffers[fetchWtDecode][input], REF IFUPLAFetchDecode.FetchWtDecodeIn]^ ← [
fetching: FetchingAB,
fetchWt: wtAB MOD 4
];
PLAEval[state, fetchWtDecode]; -- static
IBufWrtWdBc ← PA4BFromCard[NARROW[plaBuffers[fetchWtDecode][output], REF IFUPLAFetchDecode.FetchWtDecodeOut]^];
OpLengthBA ← OpLengthAB; -- from FetchPreDecode
fetchAddrBA ← (IF MacroJumpBA THEN PCBusB ELSE fetchAddrAB); -- from FetchAddr
FOR j: [0..4) IN [0..4) DO
IF IBufWrtWdBc[j] THEN
FOR k: NAT IN [0..4) DO
iBuf[4*j+k] ← SelectByte[p[II[IPData].ORD].lc, k];
ENDLOOP;
ENDLOOP;
IF FetchingAB THEN {
base: [0..16) = 4*(wtAB MOD 4);
iWd: Basics.LongNumber;
iWd.lc ← p[II[IPData].ORD].lc;
iBuf[base+0] ← iWd.hh;
iBuf[base+1] ← iWd.hl;
iBuf[base+2] ← iWd.lh;
iBuf[base+3] ← iWd.ll;
};
preOpA ← 255; -- prechargefrom FetchBuffer
preAlphaA ← 255;
preBetaA ← 255;
preGammaA ← 255;
preDeltaA ← 255;
};
postB => {
IBufWrtWdBc ← ALL[FALSE]; -- from FetchIndexing
};
ENDCASE => ERROR IFUInconsistent;
IF NOT drShWt THEN
NARROW[plaBuffers[fetchPreDecode][input], REF IFUPLAFetchPreDecode.FetchPreDecodeIn]^ ← [
preOp:  VAL[OpAB],
bytesOccM1: BufBytesOccM1A,
fault:   faultedAB
];
PLAEval[state, fetchPreDecode]; -- static
[ -- from FetchPreDecode
opLength:  OpLengthAB,
jumpOffset:  JumpOffsetSelAB,
notInstReady: notInstReady,
doIPageFault: ipf
] ← NARROW[plaBuffers[fetchPreDecode][output], REF IFUPLAFetchPreDecode.FetchPreDecodeOut]^;
DragonRosemary.Assert[(DragonRosemary.OpLength[OpAB] = OpLengthAB),
"DragonRosemary.OpLength # IFUPLAFetchPreDecode.GenFetchPreDecodePLA.OpLength"];
InstReadyAB ← NOT notInstReady;
IF ph=b THEN IPFaulted0BA ← ipf;
END;
IFUFetchRef: ModSim ← NEW[ModSimRec ← [IFUFetch]];
IFUKBusIn: PUBLIC ModuleSimProc =
BEGIN OPEN state;
IF ph=a AND KPadsIn3BA THEN XBus ← p[II[KBus].ORD].lc;
END;
IFUKBusInRef: ModSim ← NEW[ModSimRec ← [IFUKBusIn]];
IFULitGen: PUBLIC ModuleSimProc =
BEGIN OPEN state;
SELECT ph FROM
a => {
IF LoadStage1Ac THEN xaPipe1AB ← xaPipe0BA;
IF X2ASrcLit1BA THEN XBus ← xaPipe1BA
};
postA => NULL;
b => {
xaPipe0BA ← SELECT X2ALitSourceBA FROM
alpha    => AlphaAB,
beta    => BetaAB,
alphaBeta   => AlphaAB*LONG[256] + BetaAB,
alpBetGamDel => ((AlphaAB*LONG[256] + BetaAB)*256 + GammaAB)*256 + DeltaAB,
ENDCASE => AlphaAB; --changed by JH
IF LoadStage1Bc THEN xaPipe1BA ← xaPipe1AB;
};
postB => NULL;
ENDCASE => ERROR IFUInconsistent;
END;
IFULitGenRef: ModSim ← NEW[ModSimRec ← [IFULitGen]];
IFUStack: PUBLIC ModuleSimProc =
BEGIN OPEN state;
IF X1ADstStackBA THEN { -- static multiplexer
pWrtBufA ← XBus;
lWrtBufA ← XBus MOD 256;
}
ELSE {
pWrtBufA ← PCPipe3BA;
lWrtBufA ← LPipe3BA;
};
SELECT ph FROM
a => {
adderMuxA: [0..32);
addendA: [0..32);
carryA: [0..1];
sumA: [0..32);
PLAEval[state, stackAControl]; -- dynamic
[
adjTos: AdjTosA,
addendIsOnes: AddendIsOnesA,
carryIsOne: CarryIsOneA
] ← NARROW[plaBuffers[stackAControl][output], REF IFUPLAStackControl.StackAControlOut]^;
StkLdLAc ← stkLdLBA;
StkLdPAc ← stkLdPBA;
StkRdAc ← stkRdBA;
adderMuxA ← IF AdjTosA THEN tosBA ELSE bosBA;
addendA ← IF AddendIsOnesA THEN 31 ELSE 0;
carryA ← IF CarryIsOneA THEN 1 ELSE 0;
sumA ← (adderMuxA+addendA+carryA) MOD 32;
TosAB ← tosAB ← SELECT TRUE FROM
ResetBA => 0,
AdjTosA => sumA,
ENDCASE => tosBA; -- needed because AdjTosA might glitch
BosAB ← bosAB ← SELECT TRUE FROM
ResetBA => 1,
NOT AdjTosA => sumA,
ENDCASE => bosBA; -- needed because AdjTosA 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 LPipe3BA
}
ELSE
FOR index: NAT IN [0..16) DO
IF StkRdAc[index] THEN {
lRdBufA ← lStack[index];
pRdBufA ← pStack[index]
};
ENDLOOP;
PCStkTopAB ← pRdBufA;
LStkTopAB ← lRdBufA;
IF X1ASrcStackBA THEN
XBus ← (IF XBusStackLBA THEN lRdBufA ELSE pRdBufA);
};
postA => {StkLdLAc ← StkLdPAc ← StkRdAc ← ALL[FALSE]};
b => {
sdo: IFUPLAStackControl.StackDecodeOut;
DifBA ← difBA ← (32+tosAB-bosAB) MOD 32;
IF NOT drShWt THEN
NARROW[plaBuffers[stackBControl][input], REF IFUPLAStackControl.StackBControlIn]^ ← [
diff: DifBA,
push3: Push3BA,
pop3: Pop3BA -- unused
];
PLAEval[state, stackBControl]; -- static
[
iStkNearlyFull: IStkNearlyFullBA
] ← NARROW[plaBuffers[stackBControl][output], REF IFUPLAStackControl.StackBControlOut]^;
IF NOT drShWt THEN
NARROW[plaBuffers[stackDecode][input], REF IFUPLAStackControl.StackDecodeIn]^ ← [
diff: DifBA, -- unused
tos: TosAB,
bos: BosAB,
x1ASrcStack: X1ASrcStackBA,
x1ADstStack: X1ADstStackBA,
xBusStackEldest: XBusStackEldestBA,
xBusStackL: XBusStackLBA,
push3: Push3BA,
pop3: Pop3BA
];
PLAEval[state, stackDecode]; -- static
sdo ← NARROW[plaBuffers[stackDecode][output], REF IFUPLAStackControl.StackDecodeOut]^;
stkLdPBA ← LOOPHOLE[sdo.stkLdP];
stkLdLBA ← LOOPHOLE[sdo.stkLdL];
stkRdBA ← LOOPHOLE[sdo.stkRd];
tosBA ← tosAB;
bosBA ← bosAB;
};
postB => {
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;
END;
IFUStackRef: ModSim ← NEW[ModSimRec ← [IFUStack]];
IFUPC: PUBLIC ModuleSimProc =
BEGIN 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 ← OpLengthBA + 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
AbortStage3A2BA => pcPipe[2][b], -- pc of aborting micro
NormalStage3A2BA => pcAltPipe[2][b], -- whatever top of pipe suggested
ENDCASE => ERROR IFUInconsistent)
};
pcAB ← SELECT PCNextBA FROM
incr   => pcSum,
fromPCBus => npcBA,
ENDCASE   => ERROR IFUInconsistent;
PCForLogAB ← pcAB;
dpFaultAB ← dpFaultBA;
};
postA => 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 JumpOffsetSelAB FROM
alpha => SExtnd[AlphaAB],
beta => SExtnd[BetaAB],
alphaBeta => SExtnd[AlphaAB]*256 + BetaAB,
xAB => xAB,
ENDCASE => ERROR IFUInconsistent );
targetPCBA ← pcSum ← pcBranchOSetB + pcAB;
pcBA ← pcAB;
PCBusB ← npcBA ← (SELECT PCBusSrcB FROM
offSetPC   => pcSum,
pc     => pcAB,
xA    => xAB,
xopGen   => DragOpsCross.bytesPerWord*(DragOpsCross.XopBase + DragOpsCross.TrapWidthWords*OpAB),
trapGen => DragOpsCross.bytesPerWord* (DragOpsCross.TrapBase+DragOpsCross.TrapWidthWords*(
SELECT ExceptionCodeAB FROM
cTrap  => 20B -- = DragOpsCross.TrapIndex[ALUCondFalse].ORD --
+EUCondSel3AB.ORD,
dpFault => 40B -- = DragOpsCross.TrapIndex[EUPageFault].ORD-1 --
+(dpFaultAB.ORD MOD 8),
ENDCASE => ExceptionCodeAB.ORD MOD 20B)),
alpBetGamDel => ((AlphaAB*LONG[256]+BetaAB)*256+GammaAB)*256+DeltaAB,
pipe3    => PCPipe3BA,
stack    => PCStkTopAB,
ENDCASE   => ERROR IFUInconsistent);
OpBA  ← OpAB;
AlphaBA ← AlphaAB;
BetaBA ← BetaAB;
dpFaultBA ← VAL[p[II[DPFaultB].ORD].c];
};
postB => NULL;
ENDCASE => ERROR IFUInconsistent;
END;
IFUPCRef: ModSim ← NEW[ModSimRec ← [IFUPC]];
IFULS: PUBLIC ModuleSimProc =
BEGIN OPEN state;
DeltaSBA ← (256+(IF PushSc0BA THEN 1 ELSE 0)+(IF PopSa0BA THEN -1 ELSE 0)+(IF PopSb0BA THEN -1 ELSE 0)) MOD 256;
SELECT ph FROM
a => {
LAB ← lAB ← lBA;
SAB ← sAB ← sBA;
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;
IF X1ASrcSLimitAc THEN XBus ← sLimitAB;
};
postA => NULL;
b => {
lBusLtB, lBusRtB: Dragon.HexByte;
sBusLt, sBusRt: Dragon.HexByte;
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  => LStkTopAB,
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];
LPipe3BA ← lPipe[3][b] ← lPipe[3][a];
EStkOverflow1BA ←
((SAB+(255-sLimitAB --NOT sLimitAB-- )+1) MOD 128) IN [0..16);
};
postB => NULL;
ENDCASE => ERROR IFUInconsistent;
END;
IFULSRef: ModSim ← NEW[ModSimRec ← [IFULS]];
IFUStatus: PUBLIC ModuleSimProc =
BEGIN OPEN state;
SELECT ph FROM
a => {
newstatusRec: DragOpsCross.IFUStatusRec ← DragOpsCrossUtils.WordToStatus[DragOpsCrossUtils.CardToWord[XBus]];
rsPipe[a] ← RescheduleBA;
status[a] ← [
version: CurrentIFUVersion,
rescheduleKeep: TRUE
];
status[a].reschedule ← (NOT X1ADstStatusBA AND status[b].reschedule)
OR (X1ADstStatusBA AND newstatusRec.rescheduleKeep AND status[b].reschedule)
OR (X1ADstStatusBA AND NOT newstatusRec.rescheduleKeep AND newstatusRec.reschedule)
OR (RescheduleBA AND NOT rsPipe[b]);
status[a].userMode ← (NOT ClearUserModeBA AND NOT X1ADstStatusBA AND status[b].userMode)
OR (NOT ClearUserModeBA AND X1ADstStatusBA AND newstatusRec.userModeKeep AND status[b].userMode)
OR (NOT ClearUserModeBA AND X1ADstStatusBA AND NOT newstatusRec.userModeKeep AND newstatusRec.userMode);
status[a].trapsEnabled ← (NOT ClearTrapsEnbledBA AND NOT X1ADstStatusBA AND status[b].trapsEnabled)
OR (NOT ClearTrapsEnbledBA AND X1ADstStatusBA AND newstatusRec.trapsEnabledKeep AND status[b].trapsEnabled)
OR (NOT ClearTrapsEnbledBA AND X1ADstStatusBA AND NOT newstatusRec.trapsEnabledKeep AND newstatusRec.trapsEnabled);
IF LoadStage1Ac THEN {x2ASrcStatus[a] ← X2ASrcStatusBA; statPipe[a] ← status[b]};
IF x2ASrcStatus[b] THEN {
XBus ←
DragOpsCrossUtils.WordToCard[DragOpsCrossUtils.StatusToWord[statPipe[b]]];
};
UserMode0AB ← status[a].userMode;
};
postA => NULL;
b => {
status[b] ← status[a];
rsPipe[b] ← rsPipe[a];
IF LoadStage1Bc THEN {x2ASrcStatus[b] ← x2ASrcStatus[a]; statPipe[b] ← statPipe[a]};
RschWaiting2BA ← status[b].reschedule AND NOT X1ADstStatusBA; -- just in case
TrapsEnbled2BA  ← status[b].trapsEnabled AND NOT ClearTrapsEnbledBA;
RescheduleBA ← p[II[RescheduleAB].ORD].b;
};
postB => NULL;
ENDCASE => ERROR IFUInconsistent;
END;
IFUStatusRef: ModSim ← NEW[ModSimRec ← [IFUStatus]];
IFUABC: PUBLIC ModuleSimProc =
BEGIN OPEN state;
noStore: Dragon.HexByte = DragOpsCross.ProcessorRegister[euJunk].ORD;
SELECT ph FROM
a => {
aRegIsC2B ← aRegIsC3B ← bRegIsC2B ← bRegIsC3B ← 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
BubbleStage2A1BA => noStore,
NormalStage2A1BA => cPipe[1][b],
ENDCASE => ERROR IFUInconsistent);
IF LoadStage3Ac THEN cPipe[3][a] ← (SELECT TRUE FROM
AbortStage3A2BA => noStore,
NormalStage3A2BA => cPipe[2][b],
ENDCASE => ERROR IFUInconsistent);
};
postA => NULL;
b => {
aBusLt, aBusRt: Dragon.HexByte;
bBusLt, bBusRt: Dragon.HexByte;
cBusLt, cBusRt: Dragon.HexByte;
aBusLt ← SELECT ASourceLtBA FROM
cBase => DragOpsCross.ProcessorRegister[euConstant].ORD,
aBase => DragOpsCross.ProcessorRegister[euAux].ORD,
s  => SAB,
l  => LAB,
zero => 0,
ENDCASE => ERROR IFUInconsistent;
aBusRt ← SELECT ASourceRtBA FROM
alpha  => AlphaBA,
alpha47 => AlphaBA MOD 16,
op47  => OpBA MOD 16,
beta  => BetaBA,
beta03  => BetaBA/16,
beta47  => BetaBA MOD 16,
ENDCASE => SELECT ASourceOffBA 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 ASourceModBA FROM
half  => (aBusLt + aBusRt) MOD 128,
full  => (aBusLt + aBusRt) MOD 256,
ENDCASE => ERROR IFUInconsistent;
bBusLt ← SELECT BSourceLtBA FROM
cBase => DragOpsCross.ProcessorRegister[euConstant].ORD,
aBase => DragOpsCross.ProcessorRegister[euAux].ORD,
s  => SAB,
l  => LAB,
zero => 0,
ENDCASE => ERROR IFUInconsistent;
bBusRt ← SELECT BSourceRtBA FROM
op47  => OpBA MOD 16,
alpha  => AlphaBA,
alpha47 => AlphaBA MOD 16,
beta  => BetaBA,
beta03  => BetaBA/16,
beta47  => BetaBA MOD 16,
ENDCASE => SELECT BSourceOffBA 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 BSourceModBA FROM
half  => (bBusLt + bBusRt) MOD 128,
full => (bBusLt + bBusRt) MOD 256,
ENDCASE => ERROR IFUInconsistent;
cBusLt ← SELECT CSourceLtBA FROM
cBase => DragOpsCross.ProcessorRegister[euConstant].ORD,
aBase => DragOpsCross.ProcessorRegister[euAux].ORD,
l  => LAB,
s  => SAB,
zero => 0,
ENDCASE => ERROR IFUInconsistent;
cBusRt ← SELECT CSourceRtBA FROM
beta  => BetaBA,
beta03  => BetaBA/16,
beta47  => BetaBA MOD 16,
op47  => OpBA MOD 16,
alpha  => AlphaBA,
alpha47 => AlphaBA MOD 16,
ENDCASE => SELECT CSourceOffBA 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 CSourceModBA FROM
half => (cBusLt + cBusRt) MOD 128,
full => (cBusLt + cBusRt) MOD 256,
ENDCASE => ERROR IFUInconsistent;
IF (a1BEarly1AB # cPipe[2][a]) THEN aRegIsC2B ← FALSE;
IF (a1BEarly1AB # cPipe[3][a]) THEN aRegIsC3B ← FALSE;
IF (b1BEarly1AB # cPipe[2][a]) THEN bRegIsC2B ← FALSE;
IF (b1BEarly1AB # cPipe[3][a]) THEN bRegIsC3B ← 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
AbortStage2B2AB => noStore,
NormalStage2B2AB => cPipe[2][a],
ENDCASE => ERROR IFUInconsistent);
cPipe[3][b] ← (SELECT TRUE FROM
dpFaultedAB => noStore,
NOT dpFaultedAB => cPipe[3][a],
ENDCASE => ERROR IFUInconsistent);
AReg0BA ← aPipe[0][b];
BReg0BA ← bPipe[0][b];
CReg0BA ← cPipe[0][b];
};
postB => NULL;
ENDCASE => ERROR IFUInconsistent;
END;
IFUABCRef: ModSim ← NEW[ModSimRec ← [IFUABC]];
IFUInterlock: PUBLIC ModuleSimProc =
BEGIN OPEN state;
SELECT ph FROM
a, postA => NULL;
b => {
IF NOT drShWt THEN
NARROW[plaBuffers[interlock][input], REF IFUPLAInterlock.InterlockIn]^ ← [
condEffect2:   EUCondEffect2AB,
kIsRtOp:    KIsRtOp1BA,
fCtlIsRtOp:   FCtlIsRtOp1BA,
c2IsFieldCtl:   CIsField2AB,
c3IsFieldCtl:   CIsField3AB,
dpCmndRd2:   DPCmndRd2BA,
dpCmndRd3:   DPCmndRd3BA,
a1IsC2:    aRegIsC2B,
a1IsC3:    aRegIsC3B,
b1IsC2:    bRegIsC2B,
b1IsC3:    bRegIsC3B
];
PLAEval[state, interlock]; -- static
[
stage1BHold:   Stage1BHoldBA,
stage1BHoldIfReject: Stage1BHoldIfRejectBA,
aluLt:     EUAluLeftSrc1B,
aluRt:     EUAluRightSrc1B,
st2A:     EUStore2ASrc1B,
st3AIsCbus:   EUSt3AisCBus1BA
] ← NARROW[plaBuffers[interlock][output], REF IFUPLAInterlock.InterlockOut]^;
XBus ← LOOPHOLE[RegAddrRec[
aAddr: aPipe[1][b],
bAddr: bPipe[1][b],
cAddr: cPipe[3][b],
st3AisC: EUSt3AisCBus2BA,
aluLeftSrc: EUAluLeftSrc1B,
aluRightSrc: EUAluRightSrc1B,
storeSrc: EUStore2ASrc1B
]];
};
postB => NULL;
ENDCASE => ERROR IFUInconsistent;
END;
IFUInterlockRef: ModSim ← NEW[ModSimRec ← [IFUInterlock]];
IFUKBusOut: PUBLIC ModuleSimProc =
BEGIN OPEN state;
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;
END;
IFUKBusOutRef: ModSim ← NEW[ModSimRec ← [IFUKBusOut]];
IFULogger: PUBLIC ModuleSimProc =
BEGIN OPEN state;
log: IO.STREAMNIL;
NewDisposition: PROC [ pipeState: LogPipeState, disp: MicroInstDisposition ] RETURNS [ newPipeState: LogPipeState ] = {
newPipeState ← pipeState;
newPipeState.disposition ← disp;
};
SELECT ph FROM
a => {
bHigh ← FALSE;
dpRejectedAB ← DPRejectedBA;
dpFaultedAB ← dpFaultedBA;
IF LoadStage1Ac THEN opPipe[1][a] ← opPipe[0][b];
IF LoadStage2Ac THEN opPipe[2][a] ← (SELECT TRUE FROM
NormalStage2A1BA => opPipe[1][b],
BubbleStage2A1BA => NewDisposition[opPipe[1][b], interlocked],
ENDCASE => ERROR IFUInconsistent);
IF LoadStage3Ac THEN opPipe[3][a] ← (SELECT TRUE FROM
NormalStage3A2BA => opPipe[2][b],
AbortStage3A2BA => NewDisposition[opPipe[2][b], killed3a],
ENDCASE => ERROR IFUInconsistent);
};
postA => bHigh ← FALSE;
b => {
bHigh ← TRUE;
opPipe[0][b] ← [
pc: PCForLogAB,
op: VAL[OpAB],
alpha: AlphaAB,
beta: BetaAB,
gamma: GammaAB,
delta: DeltaAB,
microCyc: MicroCycleAB,
disposition: IF InstReadyAB THEN valid ELSE unready
];
IF LoadStage1Bc THEN opPipe[1][b] ← opPipe[1][a];
opPipe[2][b] ← (SELECT TRUE FROM
NormalStage2B2AB => opPipe[2][a],
AbortStage2B2AB => NewDisposition[opPipe[2][a], killed2b],
ENDCASE => ERROR IFUInconsistent);
opPipe[3][b] ← opPipe[3][a];
IF dpFaultedAB THEN opPipe[3][b].disposition ← killed3b;
xbusBCopy ← XBus;
doTrap3BA ← SELECT ExceptionCodeAB 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 (ExceptionCodeAB # reset) THEN {
IF (ExceptionCodeAB # none) OR InstReadyAB THEN {
log.PutF["\n%5g%5g", IO.int[state.data.getCycle[state.data.data]], IO.int[instrCount] ];
SELECT TRUE FROM
ExceptionCodeAB=reseting
=> log.PutF["**Reseting "];
ExceptionCodeAB=reset
=> log.PutF["**Reset "];
ExceptionCodeAB=dpFault
=> log.PutF["**DPFault "];
dpRejectedAB
=> log.PutF["**DPReject "];
ExceptionCodeAB=cTrap
=> log.PutF["**EUCC "];
ExceptionCodeAB=bubble
=> log.PutF["**Bubble "];
ExceptionCodeAB=cJump
=> log.PutF["**CJRestrt "];
ExceptionCodeAB=rschlWait
=> log.PutF["**Reschdl "];
ExceptionCodeAB=iStkOFlow
=> log.PutF["**IStkOver "];
ExceptionCodeAB=eStkOFlow
=> log.PutF["**EStkOver "];
ExceptionCodeAB=ipFault
=> log.PutF["**IPgFault "];
ExceptionCodeAB=none
=> log.PutRope[" "];
ENDCASE
=> log.PutF[" cy: %2g ", IO.card[ExceptionCodeAB.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 MicroCycleAB=0 THEN "" ELSE IO.PutFR["-%g", IO.int[MicroCycleAB]])]]];
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 ExceptionCodeAB=reset THEN instrCount ← -1;
};
};
postB =>
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
117 => { -- Reset finished
instrCount ← -1;
trapped ← FALSE;
};
120 => { -- first cycle of trap
trapped ← TRUE;
};
0 => IF NOT DPRejectedBA AND (SELECT opPipe[3][b].disposition FROM
valid => TRUE,
killed3a, killed3b =>
(MicroCycleAB = 120 -- trap that will apply to the new instruction -- ),
ENDCASE => FALSE) 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;
};
ENDCASE => ERROR IFUInconsistent;
last ← ph;
END;
IFULoggerRef: ModSim ← NEW[ModSimRec ← [IFULogger]];
IFUInconsistent: PUBLIC ERROR = CODE;
PLAEval: PROC [ state: REF IFUState, pla: IFUPLA.PLAs ] =
BEGIN
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];
END;
IFU: PUBLIC PROC [ typeData: REF IFUTypeData ] RETURNS [ ct: Core.CellType ] =
BEGIN
WGet: PROC [ wireId: II ] RETURNS [ w: Core.Wire ] = {
w ← ct.public[wireId.ORD];
};
wireList: LIST OF CoreCreate.WRNIL;
FOR wireId: II DECREASING IN II DO
wr: CoreCreate.WR ← (SELECT iITypes[wireId].width FROM
1 => iITypes[wireId].name,
ENDCASE => CoreCreate.Seq[name: iITypes[wireId].name, size: iITypes[wireId].width]
);
wireList ← CONS[wr, wireList];
ENDLOOP;
ct ← CoreOps.CreateCellType[
class: CoreClasses.unspecifiedCellClass,
public: CoreCreate.WireList[wireList],
name: "IFU",
props: CoreProperties.Props[[$ClusterInfo, typeData]]
];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: IFUName];
FOR wireId: II IN II DO
[] ← Ports.InitPort[wire: ct.public[wireId.ORD],
initType: (SELECT iITypes[wireId].width FROM
1 => b,
<=16 => c,
<=32 => lc,
ENDCASE => ERROR),
initDrive: iITypes[wireId].drive
];
ENDLOOP;
END;
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: 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: fetchWtDecode, sense: input]],
NEW[PLAShiftChainEntry ← [pla: fetchWtDecode, sense: output]],
NEW[PLAShiftChainEntry ← [pla: fetchRdDecode, sense: input]],
NEW[PLAShiftChainEntry ← [pla: fetchRdDecode, sense: output]],
NEW[PLAShiftChainEntry ← [pla: fetchControl, sense: input]],
NEW[PLAShiftChainEntry ← [pla: fetchControl, sense: output]],
Right column ...
NEW[PLAShiftChainEntry ← [pla: passRtAB, sense: input]],
NEW[PLAShiftChainEntry ← [pla: passRtBA, 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]],
NEW[PLAShiftChainEntry ← [pla: passLtB, sense: output]],
NEW[PLAShiftChainEntry ← [pla: mainControl, sense: input]],
NEW[PLAShiftChainEntry ← [pla: mainControl, sense: output]]
];
NewIFUState: PUBLIC PROC [ pattern: REF IFUState ← NIL ] RETURNS [ REF IFUState ] =
BEGIN
state: REF IFUState ← NEW[IFUState];
RETURN [ state ];
END;
normalConvergencePasses: NAT ← 1;
IFUInit: PROC [ cellType: Core.CellType, p: Ports.Port ] RETURNS [ stateAny: REF ANYNIL ] -- Rosemary.InitProc -- =
{
state: REF IFUState ← NewIFUState[];
oldState: REF IFUState ← NEW[IFUState];
currentOffset: NAT ← 0;
state.data ← NARROW[CoreProperties.GetCellTypeProp[cellType, $ClusterInfo]];
state.public ← cellType.public;
state.oldP ← Ports.CreatePort[state.public];
state.maxConvergencePasses ← 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;
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;
};
modulesA: LIST OF REF ANYLIST[IFUPreRef, IFUInstrDecodeRef, IFUControlPipeRef, IFUFetchRef, IFUKBusInRef, IFULitGenRef, IFUPCRef, IFULSRef, IFUStatusRef, IFUABCRef, IFUInterlockRef, IFUStackRef, IFUMainControlRef, IFUPostRef, IFUKBusOutRef, IFULoggerRef];
modulesB: LIST OF REF ANYLIST[IFUPreRef, IFUInstrDecodeRef, IFUControlPipeRef, IFUKBusInRef, IFULitGenRef, IFUPCRef, IFULSRef, IFUFetchRef, IFUStatusRef, IFUABCRef, IFUInterlockRef, IFUStackRef, IFUMainControlRef, IFUPostRef, IFUKBusOutRef, IFULoggerRef];
IFUSimple: PROC [ p: Ports.Port, stateAny: REF ANY ] -- Rosemary.EvalProc -- =
BEGIN
state: REF IFUState = NARROW[stateAny];
OnePass: PROC [ modules: LIST OF REF ANYNIL ] = {
IF modules = NIL THEN
modules ← (SELECT state.ph FROM
a, postA => modulesA,
b, postB => 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 ← postA;
(state.ph = b) => state.ph ← postB;
ENDCASE => NULL;
state.drShWt ← p[II[DrShWt].ORD].b;
FOR pass: NAT IN [1..state.maxConvergencePasses] DO OnePass[] ENDLOOP;
DO
sameVals: BOOLTRUE;
Ports.CopyPortValue[from: p, to: state.oldP];
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 Core.ROPE = EqualCheck.FindDif[state, state.oldState];
Ports.CheckError[IO.PutFR["IFU state, including field %g, failed to converge after %g passes.",
IO.rope[difFields.first], IO.int[state.maxConvergencePasses]]];
sameVals ← FALSE;
};
IF sameVals THEN EXIT;
state.maxConvergencePasses ← state.maxConvergencePasses+1;
ENDLOOP;
END;
IFU2CmdProc: PROC [cmd: Commander.Handle] RETURNS [result: REFNIL, msg: Rope.ROPENIL] -- Commander.CommandProc -- =
{NULL};
Commander.Register["IFU2", IFU2CmdProc];
END.