BEGIN
IFUInconsistent: PUBLIC ERROR = CODE;
ROPE: TYPE = Rope.ROPE;
II: TYPE = IFU2.II;
IFUState: TYPE = IFU2.IFUState;
IFUStateRec: TYPE = IFU2.IFUStateRec;
ModSim: TYPE = IFU2.ModSim;
ModSimRec: TYPE = IFU2.ModSimRec;
ModuleSimProc: TYPE = IFU2.ModuleSimProc;
IFURoseClass:
ROPE = Rosemary.Register
[roseClassName: "IFU", init: IFUInit, evalSimple: IFUSimple];
PortData:
TYPE =
RECORD [ name: 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"],
EURdFromPBus3AB: ["EURdFromPBus3AB", , drive],
EUWriteToPBus3AB: ["EUWriteToPBus3AB", , drive],
UserMode2BA: ["UserMode2BA", , drive],
DPCmdA: ["DPCmdA", 8, drive],
DPRejectB: ["DPRejectB"],
DPFaultB: ["DPFaultB", 4],
IPData: ["IPData", 32],
IPCmdFetchA: ["IPCmdFetchA", , drive],
IPRejectB: ["IPRejectB"],
IPFaultingB: ["IPFaultingB"],
DShA: ["DShA"],
DShB: ["DShB"],
DShRd: ["DShRd"],
DShWt: ["DShWt"],
DShIn: ["DShIn"],
DShOut: ["DShOut"],
ResetAB: ["ResetAB"],
RescheduleAB: ["RescheduleAB"],
PhA: ["PhA"],
PhB: ["PhB"],
NotPhA: ["NotPhA"],
NotPhB: ["NotPhB"],
Vdd: ["Vdd"],
Gnd: ["Gnd"],
PadVdd: ["PadVdd"],
PadGnd: ["PadGnd"] ];
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]]]]};
IFUPre:
PUBLIC ModuleSimProc = {
OPEN state;
LoadStage1Bc ← ph=B AND NOT NotBcLoadStage1AB;
X2ASrcStatus2Ac ← ph=A AND X2ASrcStatus1BA;
X2ASrcLit2Ac ← ph=A AND X2ASrcLit1BA;
IF ph=A
THEN {
ResetAB ← p[II[ResetAB ].ORD].b;
DPFaultAB ← DPFaultBA};
IF ph=B
THEN {
ResetBA ← ResetAB;
RescheduleBA ← p[II[RescheduleAB ].ORD].b;
IPData ← p[II[IPData].ORD].lc;
IPRejectBA ← p[II[IPRejectB ].ORD].b;
IPFaultingBA ← p[II[IPFaultingB ].ORD].b;
DPFaultBA ← VAL[ p[II[DPFaultB ].ORD].c];
DPRejectBA ← p[II[DPRejectB ].ORD].b;
EUCondition2BA ← p[II[EUCondition2B ].ORD].b };
IF p[
II[DShA].
ORD].b
THEN {
inputBit: BOOL = 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] ← NOT drShifterBA.bits[i-1];
ENDLOOP}
ELSE {
-- mass copy drShifterAB from DShIn
FOR i:
NAT
IN [0..drShifterAB.size)
DO
drShifterAB.bits[i] ← NOT 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
REFBit.Set[buf, i, drShifterAB.bits[offset+i]];
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
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[DShB].
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[DShOut].ORD].b ← drShifterBA.bits[drShifterAB.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.rschClear ← 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,
rschWaiting: RschWaitingAB,
push2: Push2AB,
instFault2: InstFault2BA, -- ControlPipe
iStkNearlyFull: IStkNearlyFullBA, -- StackControl
rschClear: 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[ UserMode2BA].ORD].b ← userMode [2] [b];
TrapsEnabled2BA ← trapsEnabled [2] [b];
status ← ToStatus[LFPipe3BA];
status.version ← IFU2.CurrentIFUVersion;
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: IFU2.CurrentIFUVersion,
rescheduleKeep: TRUE ];
status[a].reschedule ←
(RescheduleBA AND NOT rsPipe[b]) OR
(IF ~X1ADstStatusBA
THEN status[b].reschedule
ELSE IF newstatusRec.rescheduleKeep
THEN status[b].reschedule
ELSE newstatusRec.reschedule);
status[a].userMode ← NOT ClearUserModeBA AND
(IF ~X1ADstStatusBA
THEN status[b].userMode
ELSE IF newstatusRec.userModeKeep
THEN status[b].userMode
ELSE newstatusRec.userMode);
status[a].trapsEnabled ← NOT ClearTrapsEnabledBA AND
(IF ~X1ADstStatusBA
THEN status[b].trapsEnabled
ELSE IF 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[IPCmdFetchA].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
jumpPending: JumpPendingAB,
fetching: FetchingAB,
fetchBytesM1: FCIN.fetchBytesM1, -- PRESERVE PhA changes
iPFaulted: 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^;
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,
push3: Push3AB,
pop3: 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 => {
LAB ← LBA;
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 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;
DPCmnd3A ←
IF (ph=A
AND
NOT DPRejectBA
AND Stage3ANormalBA)
THEN ctlPipe2BA.dpCmnd ELSE NoOp;
p[II[DPCmdA].ORD].c ← DPCmnd3A.ORD;
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[EUAluOp2AB].ORD].c ← ctlPipe2AB.aluOp.ORD;
p[II[EUCondSel2AB].ORD].c ← ctlPipe2AB.condSel.ORD;
CondEffect2AB ← ctlPipe2AB.condEffect;
CIsField2AB ← ctlPipe2AB.cIsField;
CIsField3AB ← ctlPipe3AB.cIsField;
EUCondSel3AB ← ctlPipe3AB.condSel;
p[II[EURdFromPBus3AB].ORD].b ← ctlPipe3AB.rdFromPBus;
p[II[EUWriteToPBus3AB].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
THEN LOOPHOLE[OpAB MOD 16] ELSE AluOpBA;
CondSel0BA ←
IF CondSelIsOp57BA
THEN LOOPHOLE[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 };
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[IFU2.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.STREAM ← NIL;
NewDisposition:
PROC [ pipeState: IFU2.LogPipeState, disp: IFU2.MicroInstDisposition ]
RETURNS [ newPipeState: IFU2.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:
BOOL ←
SELECT 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
ANY ←
LIST[IFUPreRef, IFUInstrDecodeRef, IFUControlPipeRef, IFUFetchRef, IFUKBusInRef, IFULitGenRef, IFUPCRef, IFULSRef, IFUStatusRef, IFUABCRef, IFUInterlockRef, IFUStackRef, IFUMainPipeControlRef, IFUMicroCycleRef, IFUPostRef, IFUKBusOutRef, IFULoggerRef];
modulesB: LIST OF REF ANY ← LIST[IFUPreRef, IFUInstrDecodeRef, IFUControlPipeRef, IFUKBusInRef, IFULitGenRef, IFUPCRef, IFULSRef, IFUFetchRef, IFUStatusRef, IFUABCRef, IFUInterlockRef, IFUStackRef, IFUMainPipeControlRef, IFUMicroCycleRef, IFUPostRef, IFUKBusOutRef, IFULoggerRef];
CreateIFU:
PUBLIC
PROC[ typeData:
REF IFU2.IFUTypeData, fullIFU, quickIFU:
BOOL ←
FALSE ]
RETURNS [ ct: Core.CellType ] = {
WGet:
PROC [ wireId:
II ]
RETURNS [ w: Core.Wire ] =
{w ← ct.public[wireId.ORD]};
wireList: LIST OF CoreCreate.WR ← NIL;
public: Core.Wire ← 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;
public ← CoreCreate.WireList[wireList];
ct ←
IF fullIFU
THEN IFUSim.FormalIFU[public, quickIFU]
ELSE CoreOps.CreateCellType[
class: CoreClasses.unspecifiedCellClass,
public: public,
name: "IFU"];
CoreProperties.PutCellTypeProp[ct, $ClusterInfo, typeData];
FOR wireId:
II
IN
II
DO
[] ← Ports.InitPort[wire: ct.public[wireId.
ORD],
levelType: (
SELECT iITypes[wireId].width
FROM
1 => b,
<=16 => c,
<=32 => lc,
ENDCASE => ERROR),
initDrive: iITypes[wireId].drive ];
ENDLOOP;
[] ← Rosemary.SetFixedWire[CoreOps.FindWire[ct.public, "Vdd"], H];
[] ← Rosemary.SetFixedWire[CoreOps.FindWire[ct.public, "Gnd"], L];
[] ← Rosemary.SetFixedWire[CoreOps.FindWire[ct.public, "PadVdd"], H];
[] ← Rosemary.SetFixedWire[CoreOps.FindWire[ct.public, "PadGnd"], L];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: IFURoseClass]};
IFUInit:
PROC
[cellType: Core.CellType, p: Ports.Port, oldStateAny:
REF
ANY ←
NIL, steady:
BOOL ←
FALSE]
RETURNS [stateAny: REF ANY ← 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;
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:
PROC [ p: Ports.Port, stateAny:
REF
ANY ]
-- Rosemary.EvalProc -- = {
state: IFUState = NARROW[stateAny];
OnePass:
PROC [ modules:
LIST
OF
REF
ANY ←
NIL ] = {
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: BOOL ← TRUE;
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.WriteF[
"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: ltDrFromPads, sense: output]],
NEW[PLAShiftChainEntry ← [pla: ltDrDebug, sense: output]],
NEW[PLAShiftChainEntry ← [pla: ltDrToPads, sense: input]],
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: rtDrFromPads, sense: output]],
NEW[PLAShiftChainEntry ← [pla: rtDrToPads, 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]] ];
IFU2CmdProc:
PROC
-- Commander.CommandProc
[cmd: Commander.Handle] RETURNS [result: REF ← NIL, msg: Rope.ROPE ← NIL] = {NULL};
Commander.Register["IFU2", IFU2CmdProc];
END.