Directory Rope, DragOpsCross; Imports Atom, IO, BitOps, Cucumber, Dragon, RoseRun, RoseTypes, CacheOps, DragOpsCrossUtils; Cedar fieldAdr: INTEGER = PRtoByte[euField]; marAdr: INTEGER = PRtoByte[euMAR]; Remark: PROC [ message: Rope.ROPE ] = {RoseRun.DisableableStop[Remark, message]}; FieldOp: PROC[aluLeft, aluRight, fieldDesc: Dragon.HexWord] RETURNS [result:Dragon.HexWord] = BEGIN fd: DragOpsCross.FieldDescriptor _ DragOpsCrossUtils.CardToFieldDescriptor[fieldDesc MOD 65536]; shiftout: BitOps.BitDWord _ [0,0]; -- to begin cleanly maskhole: BitOps.BitDWord _ BitOps.doubleMasks[fd.mask]; Dragon.Assert[fd.shift < 33]; Dragon.Assert[fd.mask < 33]; SELECT fd.shift FROM 0 => shiftout _ Dragon.LTD[aluLeft]; -- no shift 32 => shiftout _ Dragon.LTD[aluRight]; -- full shift ENDCASE => { shiftout _ BitOps.MDTD [Dragon.LTD[aluLeft], 32, fd.shift, 32-fd.shift, shiftout, 32, 0, 32-fd.shift]; shiftout _ BitOps.MDTD [Dragon.LTD[aluRight], 32, 0, fd.shift, shiftout, 32, 32-fd.shift, fd.shift] }; result _ Dragon.LFD[BitOps.DAND[shiftout, maskhole]]; -- mask shiftout IF fd.insert THEN { mask2: BitOps.BitDWord _ BitOps.doubleMasks[fd.shift]; -- another intermediate mask maskhole _ BitOps.DNOT[BitOps.DXOR[maskhole, mask2],32]; result _ WordOp[or, result, WordOp[and, aluRight, Dragon.LFD[maskhole] ] ] }; END; DoubleADD: PROC[al, bl: Dragon.HexWord, carry: BOOL] RETURNS [sl: Dragon.HexWord, c32: BOOL] = { Xor: PROC[x, y: BOOL] RETURNS [z: BOOL] = {RETURN[(x AND NOT y) OR (y AND NOT x)]}; ai, bi: BOOL; s: BOOL _ FALSE; c: BOOL _ carry; i: INTEGER; sum: BitOps.BitDWord _ [0,0]; FOR i IN [1..32] DO ai _ EBFL[al, 32-i]; bi _ EBFL[bl, 32-i]; s _ Xor[ai, Xor[bi, c]]; c _ (ai AND bi) OR (bi AND c) OR (ai AND c); sum _ BitOps.IBID[s, sum, 32, 32-i]; ENDLOOP; RETURN[Dragon.LFD[sum], c]}; DoubleSUB: PROC[a, b: Dragon.HexWord, carry: BOOL] RETURNS [dif: Dragon.HexWord, c32: BOOL] ={ [dif, c32] _ DoubleADD[a, WordOp[not,b], NOT carry]}; PRtoByte:PROC[pr:DragOpsCross.ProcessorRegister] RETURNS [byte:Dragon.HexByte] = {byte _ LOOPHOLE[pr]}; WordOp: PROC[op:{not, or, and, xor}, left, right:Dragon.HexWord _ 0] RETURNS[result:Dragon.HexWord] = { RETURN[Dragon.LFD[SELECT op FROM not => BitOps.DNOT [Dragon.LTD[left], 32], or => BitOps.DOR [Dragon.LTD[left], Dragon.LTD[right]], and => BitOps.DAND [Dragon.LTD[left], Dragon.LTD[right]], xor => BitOps.DXOR [Dragon.LTD[left], Dragon.LTD[right]], ENDCASE => ERROR]] }; EBFL: PROC[word: Dragon.HexWord, index: CARDINAL] RETURNS[BOOL] = { RETURN[ BitOps.EBFD[Dragon.LTD[word], 32, index]] }; DblShiftRt: PROC[msb: BOOL, ltIn, rtIn: Dragon.HexWord] RETURNS[ltOut, rtOut: Dragon.HexWord] = {rtOut _ ShiftRt[EBFL[ltIn, 31], rtIn]; ltOut _ ShiftRt[msb, ltIn]}; ShiftRt: PROC[msb: BOOL, w: Dragon.HexWord] RETURNS[r: Dragon.HexWord] = {r_Dragon.LFD[BitOps.IBID[msb, BitOps.MDTD[Dragon.LTD[w],32,0,31,[0,0],32,1,31],32,0]]}; DblShiftLt: PROC[ltIn, rtIn: Dragon.HexWord, lsb: BOOL] RETURNS[cry: BOOL, ltOut, rtOut: Dragon.HexWord] = {cry _ EBFL[ltIn,0]; ltOut _ ShiftLt[ltIn, EBFL[rtIn, 0]]; rtOut _ ShiftLt[rtIn, lsb]}; ShiftLt: PROC[w: Dragon.HexWord, lsb: BOOL] RETURNS[r: Dragon.HexWord] = {r_Dragon.LFD[BitOps.IBID[lsb, BitOps.MDTD[Dragon.LTD[w],32,1,31,[0,0],32,0,31],32,31]]}; ; EU: CELL [ EPData=INT[32], -- address/data to cache/FP during PhA, data to/from cache/FP during PhB EPRejectB IFU if cAdr in [ifuXBus..ifuLast] during the previous PhiB, otherwise it is IFU -> EU or FP. EUAluLeftisR1BA, EUAluLeftisR3BA < BOOL, -- same timing as RAM addresses: 1B EUAluRightisKBA, EUAluRightisR1BA, EUAluRightisR3BA < BOOL, -- same timing as RAM addresses: 1B EUS1isR1BA, EUS1isR3BA < BOOL, -- same timing as RAM addresses: 1B EUR2isR3BA < BOOL, -- sent when data is in result1: 2B EUS3isR3BA < BOOL, -- sent when data is in store2: 2B EUHoldCarryBA < BOOL, -- received on PhB following a CCTrap or an EUCache Fault, and prevents any carry change on next PhA. EUR3isR2AB < BOOL, -- multiplexor control on R3: 3A EUWriteToPBusAB < BOOL, -- sent by the IFU during 3A, stable during 3B; specifies read/write to Cache on 3B. Used for Store instructions, and issued every instruction following an EPrejectB. This is not necessary, but so far OK and simple. EUCheckPParityAB < BOOL, -- sent by the IFU during 3A, stable during 3B; instructs EU to Check parity of cache reads. EUAluOpAB< EnumType["Dragon.ALUOps"], -- sent on 1A, used during 2B. Not latched by EU. EUCondSelAB< EnumType["Dragon.CondSelects"], -- idem for timing EUTrapBA< BOOL, -- if selected condition is true then trap EUConditionBA> BOOL, -- selected condition sent to IFU during 2B, latched during PhA to hide precharge in the carry propagator and other things. InstrCountAB=0 AND aAdr<164]; Dragon.Assert[NOT (EUAluLeftisR1BA AND EUAluLeftisR3BA)]; Dragon.Assert[NOT Dragon.MoreThanOneOf[EUAluRightisR1BA, EUAluRightisR3BA, EUAluRightisKBA]]; Dragon.Assert[NOT (EUS1isR1BA AND EUS1isR3BA)]; Dragon.Assert[NOT (EUAluLeftisR1BA AND EUAluLeftisR3BA)]; IF rejectBA AND faultBA THEN {ram[marAdr] _ result3}; -- save the faulty address IF NOT (EUHoldCarryBA OR rejectBA OR (EUTrapBA AND EUConditionBA)) THEN {carryAB _ carryBA}; mqAB _ mqBA; mulcandSAB _ mulcandSBA; mulProdSAB _ mulProdSBA; mulSubAB _ mulSubBA; divisorSAB _ divisorSBA; divendSAB _ divendSBA; divZeroAB _ divZeroBA; divRmsbAB _ divRmsbBA; divRCorrAB _ divRCorrBA; divQIncrAB _ divQIncrBA; rejected _ rejectBA; IF NOT rejectBA THEN { kBusAB _ Dragon.LFD[KBus]; aluLeft _ SELECT TRUE FROM EUAluLeftisR1BA => result1, EUAluLeftisR3BA => result3, ENDCASE => ram[aAdr]; -- watch out for illegal addresses aluRight _ SELECT TRUE FROM EUAluRightisR1BA => result1, EUAluRightisR3BA => result3, EUAluRightisKBA => Dragon.LFD[KBus], ENDCASE => ram[bAdr]; -- watch out for illegal addresses store1 _ SELECT TRUE FROM EUS1isR1BA => result1, EUS1isR3BA => result3, ENDCASE => ram[bAdr]; -- watch out for illegal addresses result2 _ SELECT TRUE FROM EUR2isR3BA => result3, ENDCASE => result1; EPData _ Dragon.LTD[result1]; store3 _ SELECT TRUE FROM EUS3isR3BA => result3, ENDCASE => store2; parityStore3 _ IF EUS3isR3BA THEN parityResult3 ELSE CacheOps.Parity32[store2]; SELECT TRUE FROM cAdr IN [PRtoByte[euStack] .. PRtoByte[euConstant]+12) => ram[cAdr] _ result3; cAdr IN [PRtoByte[ifuXBus] .. PRtoByte[ifuLast]] => KBus _ Dragon.LTD[result3]; ENDCASE => Dragon.Assert[FALSE, "EU cAdr out of range"]; phBLastFLAG _ FALSE; }; }; IF PhB THEN { -- EPFaultB ??? PlusOrMinusAluRight: Dragon.HexWord; -- temporary used for subtraction c32: BOOL; IF NOT phBLastFLAG AND log # IO.noWhereStream THEN { reset _ resetting AND NOT ResetAB; EULog[InstrCountAB,aAdr,aluLeft,bAdr,aluRight,store1,cAdr,result3]; resetting _ ResetAB}; phBLastFLAG _ TRUE; rejectBA _ EPRejectB; faultBA _ EPFaultB#None; aAdr _ BitOps.ECFD[KBus, 32, 0, 8]; bAdr _ BitOps.ECFD[KBus, 32, 8, 8]; cAdr _ BitOps.ECFD[KBus, 32, 16, 8]; Dragon.Assert[NOT EUWriteToPBusAB OR EUR3isR2AB]; IF EUWriteToPBusAB THEN { -- store in progress EPData _ Dragon.LTD[store3]; -- send data to Cache (Store) EPParityB _ CacheOps.Parity32[store3]; -- EMM, was parityStore3 result3 _ result2} ELSE { -- either a fetch, an op, or a move in progress IF rejectBA -- Fetch with reject => save address in result3 and don't listen to IFU THEN result3 _ result2 ELSE -- Fetch without reject -- IF EUR3isR2AB THEN result3 _ result2 -- op or move ELSE { result3 _ Dragon.LFD[EPData]; parityResult3 _ EPParityB; IF EUCheckPParityAB AND CacheOps.Parity32[result3]#parityResult3 THEN EPNPErrorB _ FALSE } }; store2 _ store1; carryBA _ carryAB; mqBA _ mqAB; divisorSBA _ divisorSAB; divendSBA _ divendSAB; divZeroBA _ divZeroAB; divRmsbBA _ divRmsbAB; divRCorrBA _ divRCorrAB; divQIncrBA _ divQIncrAB; mulcandSBA _ mulcandSAB; mulProdSBA _ mulProdSAB; mulSubBA _ mulSubAB; SELECT EUAluOpAB FROM SAdd => { [aluOut, c32] _ DoubleADD[aluLeft, aluRight, carryAB]; result1 _ aluOut; carryBA _ FALSE}; SSub => { [aluOut, c32] _ DoubleSUB[aluLeft, aluRight, carryAB]; result1 _ aluOut; carryBA _ FALSE}; UAdd => { [aluOut, c32] _ DoubleADD[aluLeft, aluRight, carryAB]; result1 _ aluOut; carryBA _ c32}; USub => { [aluOut, c32] _ DoubleSUB[aluLeft, aluRight, carryAB]; result1 _ aluOut; carryBA _ NOT c32}; VAdd => { [aluOut, c32] _ DoubleADD[aluLeft, aluRight, FALSE]; result1 _ aluOut}; VSub => { [aluOut, c32] _ DoubleSUB[aluLeft, aluRight, FALSE]; result1 _ aluOut}; LAdd => { [aluOut, c32] _ DoubleADD[aluLeft, aluRight, FALSE]; result1 _ aluOut; carryBA _ FALSE}; LSub => { [aluOut, c32] _ DoubleSUB[aluLeft, aluRight, FALSE]; result1 _ aluOut; carryBA _ FALSE}; FOP => { -- field descriptor provided by Field result1 _ aluOut _ FieldOp[aluLeft, aluRight, field]}; FOPK => { -- field descriptor provided by kBusAB. Otherwise identical to FOP result1 _ aluOut _ FieldOp[aluLeft, aluRight, kBusAB]}; And => { result1 _ aluOut _ WordOp[and, aluLeft, aluRight]}; Or => { result1 _ aluOut _ WordOp[or, aluLeft, aluRight]}; Xor => { result1 _ aluOut _ WordOp[xor, aluLeft, aluRight]}; BndChk => { [aluOut, c32] _ DoubleSUB[aluLeft, aluRight, FALSE]; result1 _ aluLeft}; MulLdS => { aluOut _ aluLeft; -- typically, aluOut will be tested for 0 result1 _ 0; mqBA _ aluRight; mulcandSBA _ EBFL[aluLeft, 0]; mulProdSBA _ FALSE; mulSubBA _ FALSE}; MulLdU => { aluOut _ aluLeft; -- typically, aluOut will be tested for 0 result1 _ 0; mqBA _ aluRight; mulcandSBA _ FALSE; mulProdSBA _ FALSE; mulSubBA _ FALSE}; MulStep => { tempR1, tempMQ: Dragon.HexWord; zero: BOOL _ EBFL[mqAB, 30] AND EBFL[mqAB, 31] AND mulSubAB OR ~EBFL[mqAB, 30] AND ~EBFL[mqAB, 31] AND ~mulSubAB; two: BOOL _ EBFL[mqAB, 30] AND ~EBFL[mqAB, 31] AND ~mulSubAB OR ~EBFL[mqAB, 30] AND EBFL[mqAB, 31] AND mulSubAB; one: BOOL _ ~zero AND ~two; mulSubBA _ EBFL[mqAB, 30]; SELECT TRUE FROM zero => { aluOut _ aluLeft; mulProdSBA _ mulProdSAB; [tempR1, tempMQ] _ DblShiftRt[mulProdSBA, aluOut, mqAB]; [result1, mqBA] _ DblShiftRt[mulProdSBA, tempR1, tempMQ]}; one => { IF mulSubBA THEN [aluOut, carryBA] _ DoubleSUB [aluLeft, aluRight, FALSE] ELSE [aluOut, carryBA] _ DoubleADD [aluLeft, aluRight, FALSE]; mulProdSBA _ mulSubBA#mulcandSAB; [tempR1, tempMQ] _ DblShiftRt[mulProdSBA, aluOut, mqAB]; [result1, mqBA] _ DblShiftRt[mulProdSBA, tempR1, tempMQ]}; two => { [tempR1, tempMQ] _ DblShiftRt[mulProdSAB, aluLeft, mqAB]; IF mulSubBA THEN [aluOut, carryBA] _ DoubleSUB [tempR1, aluRight, FALSE] ELSE [aluOut, carryBA] _ DoubleADD [tempR1, aluRight, FALSE]; mulProdSBA _ mulSubBA#mulcandSAB; [result1, mqBA] _ DblShiftRt[mulProdSBA, aluOut, tempMQ]}; ENDCASE => ERROR}; MulAdj => { IF mulSubAB THEN [aluOut, ] _ DoubleADD [aluLeft, aluRight, FALSE] ELSE aluOut _ aluLeft; result1 _ aluOut}; RdMQ => { result1 _ aluOut _ mqAB}; DivLdDbl => { result1 _ aluOut _ aluLeft; mqBA _ aluRight }; DivLdU => { aluOut _ aluLeft; carryBA _ FALSE; divendSBA _ FALSE; divisorSBA _ FALSE; divZeroBA _ aluOut=0; result1 _ aluOut }; DivLdS => { aluOut _ aluLeft; carryBA _ EBFL[mqAB, 0]; divendSBA _ EBFL[aluLeft, 0]; divisorSBA _ EBFL[aluRight, 0]; divZeroBA _ aluOut=0 AND ~EBFL[mqAB,0]; [divRmsbBA, result1, mqBA] _ DblShiftLt[aluOut, mqAB, EBFL[aluRight,0]=EBFL[aluLeft,0]] }; DivCkU => { -- Check for carry on first subtract [aluOut, carryBA] _ DoubleSUB[aluLeft, aluRight, FALSE]; -- Trap if carry divZeroBA _ aluOut=0 AND ~EBFL[mqAB,0]; [divRmsbBA, result1, mqBA] _ DblShiftLt[aluOut, mqAB, FALSE] }; DivCkS => { -- Check aluOut on first operation after a shift - result thrown away IF EBFL[mqAB,31] THEN [aluOut, ] _ DoubleSUB [aluLeft, aluRight, carryAB] -- note carry-in ELSE [aluOut, ] _ DoubleADD [aluLeft, aluRight, carryAB]; -- from DivLdS result1 _ aluLeft }; -- aluOut will be tested here - see DivOvFl. DivStep => { notLocked: BOOL _ divRmsbAB = (divisorSAB = EBFL[mqAB,31]); -- Rmsb = SignRem IF EBFL[mqAB,31] THEN [aluOut, carryBA] _ DoubleSUB [aluLeft, aluRight, FALSE] ELSE [aluOut, carryBA] _ DoubleADD [aluLeft, aluRight, FALSE]; divZeroBA _ ~EBFL[mqAB,0] AND (divZeroAB OR (notLocked AND carryBA AND aluOut=0)); -- new zero only possible if not locked [divRmsbBA, result1, mqBA] _ DblShiftLt[aluOut, mqAB, (EBFL[mqAB,31] # (carryBA = divRmsbAB) )] }; -- reverse op if Rmsb = carry DivAdjM => { notLocked: BOOL _ divRmsbAB = (divisorSAB = EBFL[mqAB,31]); -- Rmsb = SignRem newRemS: BOOL; IF EBFL[mqAB,31] THEN [aluOut, carryBA] _ DoubleSUB [aluLeft, aluRight, FALSE] ELSE [aluOut, carryBA] _ DoubleADD [aluLeft, aluRight, FALSE]; divZeroBA _ ((notLocked AND carryBA AND aluOut=0) OR divZeroAB); newRemS _ notLocked # carryBA; divRCorrBA _ ~divisorSAB AND newRemS OR divisorSAB AND ~newRemS AND ~divZeroBA OR newRemS AND divZeroBA; divQIncrBA _ divisorSAB AND divZeroBA; mqBA _ ShiftLt[mqAB, (EBFL[mqAB,31] # (carryBA = divRmsbAB) )]; result1 _ aluOut }; DivAdjR => { notLocked: BOOL _ divRmsbAB = (divisorSAB = EBFL[mqAB,31]); -- Rmsb = SignRem newRemS: BOOL; IF EBFL[mqAB,31] THEN [aluOut, carryBA] _ DoubleSUB [aluLeft, aluRight, FALSE] ELSE [aluOut, carryBA] _ DoubleADD [aluLeft, aluRight, FALSE]; divZeroBA _ ((notLocked AND carryBA AND aluOut=0) OR divZeroAB); newRemS _ notLocked # carryBA; divRCorrBA _ ~divendSAB AND newRemS OR divendSAB AND ~newRemS AND ~divZeroBA OR newRemS AND divZeroBA; divQIncrBA _ ~divendSAB AND divisorSAB OR divendSAB AND ~divisorSAB AND ~divZeroBA OR divisorSAB AND divZeroBA; mqBA _ ShiftLt[mqAB, (EBFL[mqAB,31] # (carryBA = divRmsbAB) )]; result1 _ aluOut }; DivAdj => { result1Alt: Dragon.HexWord _ IF divRCorrAB THEN aluRight ELSE 0; IF EBFL[mqAB,31] THEN [aluOut, ] _ DoubleSUB [aluLeft, result1Alt, FALSE] ELSE [aluOut, ] _ DoubleADD [aluLeft, result1Alt, FALSE]; carryBA _ divQIncrAB; mqBA _ mqAB; result1 _ aluOut}; ENDCASE => ERROR Stop["Invalid ALU Operation"]; SELECT EUAluOpAB FROM SSub, USub, VSub, LSub => [PlusOrMinusAluRight, ] _ DoubleSUB[0, aluRight, FALSE]; ENDCASE => PlusOrMinusAluRight _ aluRight; overflow _ (EBFL[aluLeft, 0] = EBFL[PlusOrMinusAluRight, 0]) AND (EBFL[aluLeft, 0] # EBFL[aluOut, 0]); conditionB _ SELECT EUCondSelAB FROM EZ => aluOut=0, -- aluOut=0 LZ => EBFL[aluOut, 0], -- aluOut<0 by checking the high-order bit LE => (aluOut=0) OR EBFL[aluOut, 0], -- aluOut<=0, OvFl => overflow, BC => NOT (NOT EBFL[aluLeft, 0] -- 0<=arg -- AND EBFL[aluOut, 0] -- arg-limit<0 --), IL => (EBFL[aluLeft, 0]#EBFL[aluLeft, 1]) OR (EBFL[aluRight, 0]#EBFL[aluRight, 1]) OR (EBFL[aluOut, 0]#EBFL[aluOut, 1]), DivOvFl => (SELECT EUAluOpAB FROM DivCkU => carryBA, DivCkS => (IF aluOut=0 THEN (divendSAB = divisorSAB) ELSE (divendSAB = (aluOut>=20000000000B))), ENDCASE => ERROR Stop["Invalid ALU Operation for DivMul condition"]), False => FALSE, NE => aluOut#0, -- aluOut#0 GE => NOT EBFL[aluOut, 0], -- aluOut>=0 by checking the high-order bit GZ => NOT ((aluOut=0) OR EBFL[aluOut, 0]), -- aluOut>0, NotOvFl => NOT overflow, NotBC => NOT EBFL[aluLeft, 0] -- 0<=arg -- AND EBFL[aluOut, 0] -- arg-limit<0 --, NotIL => NOT ((EBFL[aluLeft, 0]#EBFL[aluLeft, 1]) OR (EBFL[aluRight, 0]#EBFL[aluRight, 1]) OR (EBFL[aluOut, 0]#EBFL[aluOut, 1])), True => TRUE, ENDCASE => ERROR Stop["Invalid EUConditionBA Code"]; EUConditionBA _ conditionB }; Initializer IF initData#NIL THEN WITH initData SELECT FROM pl: Atom.PropList => BEGIN r: REF; IF (r _ pl.GetPropFromList[$LogRef]) # NIL THEN euLogRef _ NARROW[r, REF REF]; END; ENDCASE => NULL; ENDCELL; CEDAR -- Logging stuff EULog:PROC[ instr: BitOps.BitDWord, aRam: Dragon.HexByte, left: Dragon.HexWord, bRam: Dragon.HexByte, right: Dragon.HexWord, store: Dragon.HexWord, cRam: Dragon.HexByte, result: Dragon.HexWord] = { SELECT TRUE FROM reset => { log.Flush[]; log.PutF["\n\n\nEULog.txt %g", IO.time[] ]; log.PutF["\n**Reset**" ]}; rejected => { log.PutF["\n**Rejected**" ]}; ENDCASE => { log.PutF["\n%5g", IO.card[ Dragon.LFD[instr] ] ]; log.PutF[" %02x:%08x", IO.card[aRam], IO.card[ left ] ]; log.PutF[" %02x:%08x", IO.card[bRam], IO.card[ right ] ]; log.PutF[":%08x", IO.card[ store ] ]; log.PutF[" %02x:%08x", IO.card[cRam], IO.card[ result ] ]; } }; reset, resetting: BOOL _ FALSE; rejected: BOOL _ FALSE; phBLastFLAG: BOOL _ FALSE; log: IO.STREAM _ IO.noWhereStream; EUStateHandler: Cucumber.Handler = NEW[Cucumber.HandlerRep _ [ PrepareWhole: EUStatePrepareProc, PartTransfer: EUTransferProc ]]; EUStatePrepareProc: PROC [ whole: REF ANY, where: IO.STREAM, direction: Cucumber.Direction, data: REF ANY ] RETURNS [ leaveTheseToMe: Cucumber.SelectorList ] -- Cucumber.Bracket -- = {leaveTheseToMe _ LIST[$euLogRef]}; EUTransferProc: PROC [ whole: REF ANY, part: Cucumber.Path, where: IO.STREAM, direction: Cucumber.Direction, data: REF ANY ] -- Cucumber.PartTransferProc -- = {NULL}; Cucumber.Register[EUStateHandler, CODE[EUStateRec]]; zEU.rose Copyright c 1984 by Xerox Corporation. All rights reserved. Last edited by: Monier, May 10, 1984 7:23:23 pm PDT Last edited by: McCreight, June 12, 1984 5:22:14 pm PDT Last edited by: Curry, August 28, 1984 4:45:09 pm PDT ??? shows something that has to be discussed and fixed Replace by straight logic functions; no case statements maskhole _ a cloud of zeros followed by fd.mask ones Insert 32-fd.shift bits of aluLeft on the left of shiftout Insert fd.shift bits of aluRight on the right of shiftout Maskhole _ zeros, then fd.mask-fd.shift ones, then fd.shift zeros. Merge shiftout and aluRight using the mask Returns a+b+carry and c32, where a and b are considered to be signed numbers Returns a-b-carry and c32, where a and b are considered to be signed numbers Implemented as a+(~b)+1+(~carry) 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 (dragon.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., EPNPErrorB for PBus Negative-TRUE Parity Error). P Interface Timing and housekeeping interface I interface Changes LeftOpSources: TYPE = {aBus(0), rBus(1), cBus(2), reserve3(3)}; RightOpSources: TYPE = {bBus(0), rBus(1), cBus(2), kBus(3)}; Store2ASources: TYPE = {bBus(0), rBus(1), cBus(2), reserve3(3)}; EUStore3AGetscBusB EURes3AGetscBusB EURes3BGetsPB The following signals should change during PhiB and be stable during PhiA. The following signals should change during PhiA and be stable during PhiB. The following signals are sent by the IFU during 1A, stable during 1B and are used on the next cycle. Trap is sent by the IFU during 2B and held during 3A. Serial debugging interface All the following signals change during PhA and PhB, giving an entire clock cycle for them to change, are sampled during PhB, and are applied to the data path during the following PhA. Pipeline registers RAM, RAM addresses and various aliased registers The RAM is organised as follows (Ref DragOpsCross): registers 0 through 127 constitute the stack 128: euJunk i.e. no write 129: (currently spare) 130: euMAR 131: euField 132 through 147 are auxilliary registers 148 thru 151: (currently spare) 152 through 163 are constants Any aAdr larger than 163 is illegal Control bits and register whose useful life does not extend beyond individual macro instructions and therefore need not be pampered Bits and pieces for the ALU and the Field Unit Other pieces from the Control pipeline PhiA phase. Note that rejectBA alone inhibits almost any state change during PhiA No simultaneous bypass control signals on The last cycle of a faulty cache access: rejectBA and EPFaultB are both high These state bits should not require the special protection given carry since they are not shared between macro instructions Always send address to Cache during PhiA It is particularly important that no store in the RAM happens during rejectBA RejectBA should run thru the cAdr decoder cAdr IN 0 to 163 cAdr IN 240 to 255 PhiB phase. Most of the computations take place during PhiB EPRejectB is valid at the end of PhiB but bogus during PhiA, so it must be latched at the end of PhiB. A current problem is that the source for result3 depends upon EPRejectB, and the choice is made during the same PhiB as it is received. So this statement has to be first. Updating the RAM addresses PBus: notice that in case of reject during a store, we keep sending the data even though it is useless EUWriteToPBusAB => EUR3isR2AB save the address in result3, done normally since IFU issues EUR3isR2AB Data pipe Alu and Field Unit computation Set Default values of state log.PutF["\nEU Multiply operation: %g %g times the multiplicand", IO.rope[ (IF EBFL[mqAB, 30] THEN "Subtract" ELSE "Add") ], IO.card[ (IF two THEN 2 ELSE IF one THEN 1 ELSE 0 ] ]; Divide Step 0 Divide Step 1 Divide Step 2 Divide Step 3..33 Here we compute the overflow by checking the high-order bits of the operands (aluLeft and aluRight or - aluRight) and of the result Condition and trap generation ส˜šะbl™Jšœ ฯmœ1™JšŸœ3Ÿœ˜>—Jšœ#˜#Jšœ8˜8Jšœ;˜;—šœ˜Jšœ9˜9šŸœ ˜ JšŸœ3Ÿœ˜=JšŸœ2Ÿœ˜=—Jšœ#˜#Jšœ;˜;—JšŸœŸœ˜——šœ ˜ šŸœ ˜ JšŸœ-Ÿœ˜7JšŸœ˜—Jšœ˜—šœ ˜ Jšœ˜—J˜šก ™ šœ ˜ Jšœ˜Jšœ˜——šก ™ šœ ˜ Jšœ˜Jšœ Ÿœ˜JšœŸœ˜JšœŸœ˜Jšœ˜Jšœ˜—šœ ˜ Jšœ˜Jšœ Ÿœ ˜JšœŸœ ˜JšœŸœ˜!JšœŸœŸœ ˜)šœ5˜5JšŸœ Ÿœ˜$———šก œ™ šœ ก$˜0Jšœ1Ÿœก˜IJšœŸœŸœ ˜)Jšœ6Ÿœ˜?—šœ กE˜QšŸœŸœ ˜JšŸœ6ก˜JJšŸœ6ก˜J—Jšœก.˜C——Jšก œก™šœ ˜ Jšœ ŸœŸœ ก˜MšŸœŸœ ˜JšŸœ3Ÿœ˜=JšŸœ3Ÿœ˜>—šœ Ÿœ Ÿœ Ÿ˜+Jšœ Ÿœ Ÿœ ก'˜N—šœ5˜5JšœŸœ(ก˜J——šœ ˜ Jšœ ŸœŸœ ก˜MJšœ Ÿœ˜šŸœŸœ ˜JšŸœ3Ÿœ˜=JšŸœ3Ÿœ˜>—JšœŸœ Ÿœ Ÿœ ˜@Jšœ˜šœ ˜ Jšœ Ÿœ Ÿ˜Jšœ Ÿœ Ÿœ Ÿ˜+JšœŸœ ˜ —JšœŸœ ˜&JšœŸœ%˜@Jšœ˜—šœ ˜ Jšœ ŸœŸœ ก˜MJšœ Ÿœ˜šŸœŸœ ˜JšŸœ3Ÿœ˜=JšŸœ3Ÿœ˜>—JšœŸœ Ÿœ Ÿœ ˜@Jšœ˜šœ ˜ Jšœ Ÿœ Ÿ˜Jšœ Ÿœ Ÿœ Ÿ˜*JšœŸœ ˜ —šœ ˜ Jšœ ŸœŸ˜Jšœ Ÿœ Ÿœ Ÿ˜-JšœŸœ ˜#—JšœŸœ%˜@Jšœ˜—šœ ˜ JšœŸœ Ÿœ Ÿœ˜@šŸœŸœ ˜JšŸœ/Ÿœ˜9JšŸœ/Ÿœ˜:—Jšœ˜Jšœ ˜ Jšœ˜—JšŸœŸœ˜/J˜—šœƒ™ƒšŸœ Ÿ˜šœ˜Jšœ1Ÿœ˜8—JšŸœ#˜*—Jš œ ŸœŸœŸœŸœŸœ ˜f—J˜Jšœ™šœ Ÿœ Ÿ˜$JšŸœก ˜JšŸœŸœ ก*˜AJšŸœŸœŸœ ก ˜2Jšœ˜JšŸœŸœŸœŸœ ก œŸœŸœ กœ˜TJšŸœŸœ ŸœŸœŸœŸœŸœŸœ Ÿœ ˜xšœ Ÿœ Ÿ˜!Jšœ˜šœ Ÿœ ˜JšŸœ˜JšŸœ'˜+—JšŸœŸœ5˜E—Jšœ Ÿœ˜JšŸœก ˜JšŸœŸœŸœ ก+˜FJš ŸœŸœ ŸœŸœก ˜7Jšœ Ÿœ ˜Jš œ ŸœŸœ ก œŸœŸœ กœ˜QJšœ ŸœŸœ ŸœŸœŸœŸœŸœŸœ Ÿœ˜JšœŸœ˜ JšŸœŸœ$˜4—Jšœ˜J˜———˜ J˜šŸœ ŸœŸ˜šŸœ ŸœŸ˜˜JšŸ˜JšœŸœ˜šŸœ%ŸœŸ˜/Jšœ ŸœŸœŸœ˜—JšŸœ˜—JšŸœŸœ˜——™J™——JšŸœ˜ šขฅะbc˜š œŸœ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜šŸœŸœŸ˜šœ ˜ Jšœ ˜ Jšœ Ÿœ ˜,Jšœ˜—šœ ˜ Jšœ˜—šŸœ˜ JšœŸœŸœ ˜3JšœŸœ Ÿœ˜:JšœŸœ Ÿœ˜:JšœŸœ˜-JšœŸœ Ÿœ˜;Jšœ˜———JšœŸœŸœ˜Jšœ ŸœŸœ˜Jšœ ŸœŸœ˜JšœŸœŸœŸœ˜"J˜šœ#Ÿœ˜>J˜!J˜J˜—J˜š œŸœ ŸœŸœ ŸœŸœ'ŸœŸœŸœ+กœ˜ถJšœŸœ ˜#J˜—š œŸœ ŸœŸœŸœŸœ'ŸœŸœกœŸœ˜ฆJ˜—Jšœ"Ÿœ˜4J˜—J˜—…—Kเu้