IFetcher.rose
Copyright © 1984 by Xerox Corporation. All rights reserved.
Last edited by: McCreight, June 12, 1984 11:41:28 am PDT
Last edited by: Curry, August 21, 1984 12:40:17 pm PDT
Imports Atom, BitOps, CacheOps, Dragon;
Cedar
iBufMaxWords: NAT = 32;
iBufMaxBytes: NAT = 4*iBufMaxWords;
IFCState: TYPE = {pendingJump, fetchingFirst, fetchingMore, full, faulted};
;
IFetcherControl: CELL [
Signal names obey the following convention: If a signal x is computed during PhA and remains valid throughout the following PhB, it is denoted as xAB. If x is computed during PhA and can change during the following PhB (as, for example, in precharged logic), it is denoted as xA. In this latter case, a client wanting to use x during PhB must receive it in his own latch open during PhA. xBA and xB are defined symmetrically. Positive logic is assumed (asserted = TRUE = 1 = more positive logic voltage); negative-logic signals have an extra "N" at or very near the beginning of the signal name (e.g., PNPError for PBus Negative-TRUE Parity Error).
Interface to rest of IFU
PreLengthAB  >INT[3],
InstReadyAB   >BOOL,
PreFetchFaultedBA >BOOL,
GetNextInstB   <BOOL, -- iff InstReadyA
JumpB     <BOOL, -- allowed any time
XBus     <INT[32], -- used during PhB
P Interfaces for IFU cache
IPData   =INT[32], -- driven on PhA
IPParityB   <BOOL,
IPCmdA   >EnumType["Dragon.PBusCommands"],
IPRejectB   <BOOL,
IPFaultB   <EnumType["Dragon.PBusFaults"],
IPNPErrorB   =BOOL,
Interface to IFetcherArray
NoneValidAB  >BOOL,
FetchFinishedB  >BOOL,
FlushB    >BOOL,
Take1B    >BOOL,
Take2B    >BOOL,
Take3B    >BOOL,
Take5B    >BOOL,
PreOpA    <INT[8],
NHas1A    <BOOL,
Has2A    <BOOL,
Has3A    <BOOL,
Has5A    <BOOL,
NoRoomForMoreA <BOOL,
Serial debugging interface
All the following signals change during PhA and propagate during the remainder of PhA and PhB, giving an entire clock cycle for them to propagate throughout the machine. Each user must receive them into a latch open during PhB. The effects of changes are intended to happen throughout the following PhA, PhB pair.
DHold0BA, DHold1AB <BOOL, -- must be high before testing
Timing and housekeeping interface
PhA    <BOOL,
PhB    <BOOL
]
State
pDataBA: Dragon.HexWord, -- for computing IP bus parity
pParityBA: BOOL,
pParityErrorAB: BOOL,
noRoomForMoreAB: BOOL,
state: ARRAY Dragon.Phase OF IFCState,
newFetchBA, successfulFetchBA: BOOL,
preFetchPCWord: ARRAY Dragon.Phase OF Dragon.HexWord, -- prefetch word PC (byte PC/4)
firstByteOffset: ARRAY Dragon.Phase OF [0..4)
EvalSimple
IF PhA THEN
BEGIN
op0: BOOL = BitOps.EBFW[PreOpA, 8, 0];
op1: BOOL = BitOps.EBFW[PreOpA, 8, 1];
op2: BOOL = BitOps.EBFW[PreOpA, 8, 2];
not2: BOOL = NOT (op0 AND NOT op1); -- OpLength[op]#2
not3: BOOL = NOT (op0 AND op1); -- OpLength[op]#3
not5: BOOL = NOT (NOT op0 AND NOT op1 AND op2); -- OpLength[op]#5
len0: BOOL = NOT not5;
len1: BOOL = NOT (not2 AND not3);
len2: BOOL = not2;
PreLengthAB ← BitOps.IBIW[len0, PreLengthAB, 3, 0];
PreLengthAB ← BitOps.IBIW[len1, PreLengthAB, 3, 1];
PreLengthAB ← BitOps.IBIW[len2, PreLengthAB, 3, 2];
InstReadyAB ← NOT (NHas1A OR NOT (not2 OR Has2A) OR NOT (not3 OR Has3A) OR NOT (not5 OR Has5A));
IPCmdA ← IF newFetchBA THEN Fetch ELSE NoOp;
IPData ← BitOps.InsertLongInDouble[source: preFetchPCWord[b], container: IPData, containerWidth: 32, fieldPosition: 0, fieldWidth: 32];
state[a] ← state[b];
preFetchPCWord[a] ← SELECT TRUE FROM
NOT DHold0BA AND newFetchBA => preFetchPCWord[b]+1,
ENDCASE => preFetchPCWord[b];
firstByteOffset[a] ← firstByteOffset[b];
pParityErrorAB ← (NOT DHold0BA AND successfulFetchBA)
AND (CacheOps.Parity32[pDataBA] # pParityBA);
NoneValidAB ← NHas1A;
noRoomForMoreAB ← NoRoomForMoreA;
END; -- of PhA evaluation
IF PhB THEN
BEGIN
Dragon.Assert[NOT (IPFaultB # None AND NOT IPRejectB)];
Dragon.Assert[NOT (GetNextInstB AND JumpB)];
Dragon.Assert[NOT (GetNextInstB AND NOT InstReadyAB)];
PreFetchFaultedBA ← state[a] = faulted AND NOT InstReadyAB AND NOT JumpB;
IF pParityErrorAB THEN IPNPErrorB ← FALSE;
pDataBA ← BitOps.ExtractLongFDouble[container: IPData, containerWidth: 32, fieldPosition: 0, fieldWidth: 32]; -- latch for parity check
pParityBA ← IPParityB;
FetchFinishedB ← successfulFetchBA ← NOT DHold1AB
AND NOT IPRejectB
AND NOT JumpB
AND state[a] IN [fetchingFirst..fetchingMore];
state[b] ← SELECT TRUE FROM
DHold1AB => state[a],
JumpB AND IPRejectB => pendingJump,
NOT IPRejectB AND (JumpB OR state[a] = pendingJump) => fetchingFirst,
state[a] IN [fetchingFirst..fetchingMore] AND IPFaultB # None => faulted,
IPRejectB, state[a] = faulted => state[a],
NOT noRoomForMoreAB => fetchingMore,
ENDCASE => full;
newFetchBA ← NOT IPRejectB AND state[b] IN [fetchingFirst..fetchingMore];
IF (FlushB ← NOT DHold1AB AND JumpB) THEN
BEGIN
firstByteOffset[b] ← BitOps.ExtractLongFDouble[container: XBus, containerWidth: 32, fieldPosition: 0, fieldWidth: 32] MOD 4;
preFetchPCWord[b] ← BitOps.ExtractLongFDouble[container: XBus, containerWidth: 32, fieldPosition: 0, fieldWidth: 32]/4;
END
ELSE
BEGIN
firstByteOffset[b] ← firstByteOffset[a];
preFetchPCWord[b] ← preFetchPCWord[a];
END;
Take1B ← GetNextInstB OR ((state[a]=fetchingFirst AND NOT IPRejectB) AND (firstByteOffset[a]>=1));
Take2B ← (GetNextInstB AND (PreLengthAB>=2)) OR ((state[a]=fetchingFirst AND NOT IPRejectB) AND (firstByteOffset[a]>=2));
Take3B ← (GetNextInstB AND (PreLengthAB>=3)) OR ((state[a]=fetchingFirst AND NOT IPRejectB) AND (firstByteOffset[a]>=3));
Take5B ← GetNextInstB AND (PreLengthAB>=5);
END; -- of PhB evaluation
ENDCELL;
IFetcherArray: CELL [
Interface within IFetcher
IPDataB    <INT[32],
NoneValidAB  <BOOL,
FetchFinishedB  <BOOL,
FlushB     <BOOL,
Take1B    <BOOL,
Take2B    <BOOL,
Take3B    <BOOL,
Take5B    <BOOL,
PreOpA    >INT[8],
PreAlphaA   >INT[8],
PreBetaA    >INT[8],
PreGammaA   >INT[8],
PreDeltaA    >INT[8],
NHas1A    >BOOL,
Has2A    >BOOL,
Has3A    >BOOL,
Has5A    >BOOL,
NoRoomForMoreA >BOOL,
Timing and housekeeping interface
PhA    <BOOL,
PhB    <BOOL
]
State
iBufWords: [0..iBufMaxWords) ← 8,
noneValidB: BOOL,
validAB, validBA, firstAB, firstBA: ARRAY [0..iBufMaxBytes) OF BOOL,
byteBA: ARRAY [0..iBufMaxBytes) OF Dragon.HexByte
EvalSimple
iBufBytes: [0..iBufMaxBytes) ← 4*iBufWords;
IF PhA THEN
BEGIN
FOR i: [0..iBufMaxBytes) IN [0..iBufBytes) DO
Dragon.Assert[NOT validBA[i] OR validBA[i+3-(i MOD 4)]];
.. if any byte of a buffer word is valid, the last one is.
ENDLOOP;
FOR i: [0..iBufMaxBytes) IN [0..iBufBytes) DO
SELECT TRUE FROM
firstBA[i] =>
BEGIN
PreOpA ← BitOps.WAND[PreOpA, byteBA[i]];
NHas1A ← FALSE;
END;
firstBA[(i+iBufBytes-1) MOD iBufBytes] =>
BEGIN
PreAlphaA ← BitOps.WAND[PreAlphaA, byteBA[i]];
Has2A ← Has2A AND validBA[i];
END;
firstBA[(i+iBufBytes-2) MOD iBufBytes] =>
BEGIN
PreBetaA ← BitOps.WAND[PreBetaA, byteBA[i]];
Has3A ← Has3A AND validBA[i];
END;
firstBA[(i+iBufBytes-3) MOD iBufBytes] =>
BEGIN
PreGammaA ← BitOps.WAND[PreGammaA, byteBA[i]];
Has5A ← Has5A AND validBA[i];
END;
firstBA[(i+iBufBytes-4) MOD iBufBytes] =>
BEGIN
PreDeltaA ← BitOps.WAND[PreDeltaA, byteBA[i]];
Has5A ← Has5A AND validBA[i];
END;
ENDCASE => NULL;
ENDLOOP;
FOR i: NAT ← 3, i+4 WHILE i < iBufBytes DO
NoRoomForMoreA ← NoRoomForMoreA
AND (validBA[i] OR validBA[(i+5) MOD iBufBytes]);
.. at least one byte of the buffer must remain invalid, so that we can identify the start and end of the data. One fetch could already be in progress (storing into (i-4...i] ), so in the worst case we are deciding whether another one (into (i..i+4] ) can also finish without wiping out the invalid gap.
ENDLOOP;
validAB ← validBA;
FOR i: [0..iBufMaxBytes) IN [0..iBufBytes) DO
SELECT i FROM
0 => firstAB[i] ← firstBA[i] OR NoneValidAB;
ENDCASE => firstAB[i] ← firstBA[i];
ENDLOOP;
END; -- of PhA evaluation
IF PhB THEN
BEGIN
IF FlushB THEN
BEGIN
r: REF = Atom.GetProp[$Cluster, $IBufWords];
iBufWords ← IF r#NIL THEN NARROW[r, REF INT]^ ELSE 8;
iBufBytes ← 4*iBufWords;
END;
FOR i: [0..iBufMaxBytes) IN [0..iBufBytes) DO
validBA[i] ←
(validAB[i]
.. was valid before
OR
(FetchFinishedB
AND
((validAB[(i+iBufBytes-1-(i MOD 4)) MOD iBufBytes]
AND NOT validAB[(i+3-(i MOD 4))])
OR (NoneValidAB AND i<4))))
.. becoming valid because memory read is finishing
AND NOT FlushB
AND NOT (Take1B AND firstAB[i])
AND NOT (Take2B AND firstAB[(i+iBufBytes-1) MOD iBufBytes])
AND NOT (Take3B AND firstAB[(i+iBufBytes-2) MOD iBufBytes])
AND NOT (Take5B AND firstAB[(i+iBufBytes-3) MOD iBufBytes])
AND NOT (Take5B AND firstAB[(i+iBufBytes-4) MOD iBufBytes]);
.. becoming invalid because IFU has taken this byte
IF FetchFinishedB
AND
((validAB[(i+iBufBytes-1-(i MOD 4)) MOD iBufBytes]
AND NOT validAB[(i+3-(i MOD 4))])
OR (NoneValidAB AND i<4)) THEN
byteBA[i] ← BitOps.ECFD[IPDataB, 32, 8*(i MOD 4), 8];
ENDLOOP;
FOR i: [0..iBufMaxBytes) IN [0..iBufBytes) DO
firstBA[i] ← validBA[i] AND NOT validBA[(i+iBufBytes-1) MOD iBufBytes];
ENDLOOP;
PreOpA ← PreAlphaA ← PreBetaA ← PreGammaA ← PreDeltaA ← LAST[Dragon.HexByte];
NHas1A ← Has2A ← Has3A ← Has5A ← NoRoomForMoreA ← TRUE;
END; -- of PhB evaluation
ENDCELL;
Cedar
PreFetcherState: TYPE = {pendingJump, fetching, waiting, faulted} ← faulted;
;
IFetcher: CELL [
Interface within IFU
PreOpA    >INT[8],
PreAlphaA   >INT[8],
PreBetaA    >INT[8],
PreGammaA   >INT[8],
PreDeltaA    >INT[8],
PreLengthAB  >INT[3],
InstReadyAB   >BOOL,
PreFetchFaultedBA >BOOL, -- generated during PhB (there's no hurry)
GetNextInstB   <BOOL, -- used during PhB, iff InstReadyAB
JumpB     <BOOL, -- used during PhB, allowed any time
XBus     <INT[32], -- used during PhB
P Interfaces for IFU cache
IPData    =INT[32], -- address PhA, data PhB
IPCmdA   >EnumType["Dragon.PBusCommands"],
IPRejectB   <BOOL,
IPFaultB   <EnumType["Dragon.PBusFaults"],
IPParityB   <BOOL,
IPNPErrorB   =BOOL,
Serial debugging interface
DHold0BA  <BOOL,
DHold1AB  <BOOL,
DShiftAB   <BOOL,
DExecuteAB  <BOOL,
DNSelectAB  <BOOL,
DDataInAB  <BOOL,
DDataOutAB  =BOOL,
Timing and housekeeping interface
PhA    <BOOL,
PhB    <BOOL
]
Expand
FetchFinishedB  :BOOL;
FlushB    :BOOL;
Take1B    :BOOL;
Take2B    :BOOL;
Take3B    :BOOL;
Take5B    :BOOL;
NHas1A    :BOOL;
Has2A    :BOOL;
Has3A    :BOOL;
Has5A    :BOOL;
NoneValidAB  :BOOL;
NoRoomForMoreA :BOOL;
control: IFetcherControl[];
array: IFetcherArray[ IPDataB: IPData ]
ENDCELL