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;
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
THEN LOOPHOLE[OpAB MOD 16] ELSE preEUAluOp0BA;
EUCondSel0BA ←
IF condSelIsOp57BA
THEN LOOPHOLE[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.STREAM ← NIL;
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.WR ← NIL;
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
ANY ←
NIL ]
-- 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 ANY ← LIST[IFUPreRef, IFUInstrDecodeRef, IFUControlPipeRef, IFUFetchRef, IFUKBusInRef, IFULitGenRef, IFUPCRef, IFULSRef, IFUStatusRef, IFUABCRef, IFUInterlockRef, IFUStackRef, IFUMainControlRef, IFUPostRef, IFUKBusOutRef, IFULoggerRef];
modulesB: LIST OF REF ANY ← LIST[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
ANY ←
NIL ] = {
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: BOOL ← TRUE;
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:
REF ←
NIL, msg: Rope.
ROPE ←
NIL]
-- Commander.CommandProc -- =
{NULL};
Commander.Register["IFU2", IFU2CmdProc];
END.