<> <> <> <> <<>> DIRECTORY Basics USING [SwapHalves], CrRPC USING [Error, Handle, CreateClientHandle, DestroyClientHandle], IO, RapunzelP2200V2, Rope USING [Equal, ROPE], SoftcardOps, SoftcardPrivate, XNS USING [Address, GetThisHost, unknownSocket], XNSCH USING [LookupAddressFromRope]; SoftcardOpsImpl: CEDAR PROGRAM IMPORTS Basics, CrRPC, IO, RapunzelP2200V2, Rope, SoftcardOps, XNS, XNSCH EXPORTS SoftcardOps = BEGIN OPEN SoftcardPrivate, Rapunzel: RapunzelP2200V2; ROPE: TYPE = Rope.ROPE; Addr: TYPE = SoftcardOps.Addr; EUPBusCmd: TYPE = SoftcardOps.EUPBusCmd; -- tbd IFUPBusCmd: TYPE = SoftcardOps.IFUPBusCmd; EUInternal: TYPE = SoftcardOps.EUInternal; EURegister: TYPE = SoftcardOps.EURegister; IFUInternalState: TYPE = SoftcardOps.IFUInternalState; -- tbd ClockControl: TYPE = SoftcardOps.ClockControl; ControlBit: TYPE = SoftcardOps.ControlBit; StatusBit: TYPE = SoftcardOps.StatusBit; OneBit: TYPE = SoftcardPrivate.OneBit; Control1Bits: TYPE = SoftcardPrivate.Control1Bits; Control2Bits: TYPE = SoftcardPrivate.Control2Bits; StatusBits: TYPE = SoftcardPrivate.StatusBits; <> FullWordeuPBusCmd: TYPE = MACHINE DEPENDENT RECORD [ unspecifiedAsYet (0: 0..7): [0..377B] _ 0, unused (0: 8..15): [0..377B] _ 0 ]; FullWordifuPBusCmd: TYPE = MACHINE DEPENDENT RECORD [ reserved (0: 0..2): [0..7B] _ 0, ifuPBusCmd (0: 3..3): IFUPBusCmd _ noAccess, r1 (0: 4..6): [0..7B] _ 0, userMode (0: 7..7): BOOL _ FALSE, r2 (0: 8..15): [0..377B] _ 0 ]; crHandle: CrRPC.Handle; <<-- various CmdSeqences to be shared>> numEUBits: CARDINAL = 32; readEUSeq: Rapunzel.SeqCmd; writeEUSeq: Rapunzel.SeqCmd; numIFUBits: CARDINAL = 488; readIFUSeq: Rapunzel.SeqCmd; writeIFUSeq: Rapunzel.SeqCmd; Error: PUBLIC SIGNAL[code: ATOM, explanation: ROPE _ NIL] = CODE; EstablishConnection: PUBLIC PROC[host: ROPE] RETURNS[ok: BOOL] = { Ec: PROC = { netAddr: XNS.Address; IF host.Equal["ME"] THEN netAddr _ [net: [0,0,0,3], host: XNS.GetThisHost[], socket: XNS.unknownSocket] ELSE { netAddr _ XNSCH.LookupAddressFromRope[host].address; netAddr.socket _ XNS.unknownSocket; }; crHandle _ CrRPC.CreateClientHandle[$SPP, netAddr, 0]; }; CarefullyApply[proc: Ec, nilHandleOK: TRUE]; RETURN[crHandle # NIL]; }; CloseConnection: PUBLIC PROC = { CrRPC.DestroyClientHandle[crHandle]; crHandle _ NIL; }; SetEUBrkPtAddr: PUBLIC PROC[addr: Addr] = { Seu: PROC = { [] _ Rapunzel.PokeLong[crHandle, BkptEUH, addr ] }; CarefullyApply[Seu]; }; SetIFUBrkPtAddr: PUBLIC PROC[addr: Addr] = { Sifu: PROC = { [] _ Rapunzel.PokeLong[crHandle, BkptIFUH, addr] }; CarefullyApply[Sifu]; }; ReadEUCmd: PUBLIC PROC RETURNS[euPBusCmd: EUPBusCmd] = { Reuc: PROC = { user: FullWordifuPBusCmd = LOOPHOLE[ReadShort[SpyCmd2]]; most: FullWordeuPBusCmd = LOOPHOLE[ReadShort[SpyCmd1]]; euPBusCmd.userMode _ user.userMode; euPBusCmd.unspecifiedAsYet _ most.unspecifiedAsYet; }; CarefullyApply[Reuc]; }; ReadIFUCmd: PUBLIC PROC RETURNS[ifuPBusCmd: IFUPBusCmd] = { ifuPBusCmd _ LOOPHOLE[ReadShort[SpyCmd2], FullWordifuPBusCmd].ifuPBusCmd }; ReadEUPBusData: PUBLIC PROC RETURNS[value: LONG CARDINAL] = { value _ ReadLong[SpyEUDataH] }; ReadIFUPBusData: PUBLIC PROC RETURNS[value: LONG CARDINAL] = { value _ ReadLong[SpyEUDataH] }; ReadClock: PUBLIC PROC RETURNS[value: LONG CARDINAL] = <> { value _ ReadLong[ClockH] }; <<*************************>> <<>> ReadEURegister: PUBLIC PROC[which: EUInternal] RETURNS[value: LONG CARDINAL] = { resultSeq: Rapunzel.SeqResult; theBits: PACKED ARRAY [0..32) OF OneBit; seqIndex: CARDINAL _ 0; resIndex: CARDINAL _ 0; debugInfo: DebugInfoEntry; setEUAddr: Rapunzel.PokeShortCmd; Reur: PROC = { resultSeq _ Rapunzel.DoCmds[crHandle, readEUSeq] }; debugInfo.debugEUAddr _ ORD[which]; setEUAddr.address _ DebugReadEU; setEUAddr.value _ LOOPHOLE[debugInfo]; IF readEUSeq = NIL THEN readEUSeq _ ConstructReadSeq[isEU: TRUE]; TRUSTED { readEUSeq[2] _ [pokeShort[setEUAddr]] }; CarefullyApply[Reur]; WHILE seqIndex < resultSeq.length DO res: Rapunzel.Result = resultSeq.body[seqIndex]; one: Rapunzel.Result; WITH res: res SELECT FROM shftRead => { FOR resIndex IN [0..res.shftRead.numRepeats) DO seqIndex _ seqIndex + 1; TRUSTED { one _ resultSeq.body[seqIndex] }; WITH one: one SELECT FROM peekShort => { dI: StatusBits = LOOPHOLE[one.peekShort.value]; theBits[resIndex] _ dI.dOutEU; }; ENDCASE => NULL; ENDLOOP; }; ENDCASE => seqIndex _ seqIndex + 1; ENDLOOP; value _ LOOPHOLE[theBits]; <> < value _ [kReg [kVal: LOOPHOLE[theBits]]];>> < value _ [field [fVal: LOOPHOLE[theBits]]];>> < value _ [regular [rVal: LOOPHOLE[theBits]]];>> <<};>> }; WriteEURegister: PUBLIC PROC[which: EUInternal, value: LONG CARDINAL] = { theBits: PACKED ARRAY [0..32) OF OneBit; seqIndex: CARDINAL _ 0; debugInfo: DebugInfoEntry; setEUAddr: Rapunzel.PokeShortCmd; one: Rapunzel.PokeShortCmd; Weur: PROC = { [] _ Rapunzel.DoCmds[crHandle, writeEUSeq] }; <> < theBits _ LOOPHOLE[value.kVal];>> < theBits _ LOOPHOLE[value.fVal];>> < theBits _ LOOPHOLE[value.rVal];>> <> <<};>> theBits _ LOOPHOLE[value]; debugInfo.debugEUAddr _ ORD[which]; setEUAddr.address _ DebugReadEU; setEUAddr.value _ LOOPHOLE[debugInfo]; one.address _ DebugWriteEU; IF writeEUSeq = NIL THEN writeEUSeq _ ConstructWriteSeq[isEU: TRUE]; TRUSTED { writeEUSeq[2] _ [pokeShort[setEUAddr] ] }; WHILE seqIndex < writeEUSeq.length DO this: Rapunzel.Cmd = writeEUSeq.body[seqIndex]; one: Rapunzel.PokeShortCmd; WITH this: this SELECT FROM shftWrite => { FOR valIndex: CARDINAL IN [0..this.shftWrite.numRepeats) DO seqIndex _ seqIndex + 1; one.value _ theBits[valIndex]; TRUSTED { writeEUSeq.body[seqIndex] _ [pokeShort[one]] }; ENDLOOP; }; ENDCASE => seqIndex _ seqIndex + 1; ENDLOOP; CarefullyApply[Weur]; }; <<>> ReadIFUState: PUBLIC PROC RETURNS[ifuState: IFUInternalState] = { <> resultSeq: Rapunzel.SeqResult; seqIndex: CARDINAL _ 0; resIndex: CARDINAL _ 0; Rifu: PROC = { resultSeq _ Rapunzel.DoCmds[crHandle, readIFUSeq] }; IF readIFUSeq = NIL THEN readIFUSeq _ ConstructReadSeq[isEU: FALSE]; CarefullyApply[Rifu]; WHILE seqIndex < resultSeq.length DO res: Rapunzel.Result = resultSeq.body[seqIndex]; one: Rapunzel.Result; WITH res: res SELECT FROM shftRead => { FOR resIndex IN [0..res.shftRead.numRepeats) DO seqIndex _ seqIndex + 1; TRUSTED { one _ resultSeq.body[seqIndex] }; WITH one: one SELECT FROM peekShort => { dI: StatusBits = LOOPHOLE[one.peekShort.value]; ifuState[resIndex] _ dI.dOutIFU; }; ENDCASE => NULL; ENDLOOP; }; ENDCASE => seqIndex _ seqIndex + 1; ENDLOOP; }; WriteIFUState: PUBLIC PROC[ifuState: IFUInternalState] = { seqIndex: CARDINAL _ 0; one: Rapunzel.PokeShortCmd; Wifu: PROC = { [] _ Rapunzel.DoCmds[crHandle, writeIFUSeq] }; one.address _ DebugWriteIFU; IF writeIFUSeq = NIL THEN writeIFUSeq _ ConstructWriteSeq[isEU: FALSE]; WHILE seqIndex < writeEUSeq.length DO this: Rapunzel.Cmd = writeIFUSeq.body[seqIndex]; one: Rapunzel.PokeShortCmd; WITH this: this SELECT FROM shftWrite => { FOR valIndex: CARDINAL IN [0..this.shftWrite.numRepeats) DO seqIndex _ seqIndex + 1; one.value _ ifuState[valIndex]; TRUSTED { writeEUSeq.body[seqIndex] _ [pokeShort[one]] }; ENDLOOP; }; ENDCASE => seqIndex _ seqIndex + 1; ENDLOOP; CarefullyApply[Wifu]; }; <<>> <<*************************>> ReadClockControl: PUBLIC PROC RETURNS[clockControl: ClockControl] = { Rcc: PROC = { clockControl _ LOOPHOLE[Rapunzel.PeekShort[crHandle, ClockControlAddr]] }; CarefullyApply[Rcc]; }; WriteClockControl: PUBLIC PROC[clockControl: ClockControl] = { Wcc: PROC = { Rapunzel.PokeShort[crHandle, ClockControlAddr, LOOPHOLE[clockControl, CARDINAL]] }; CarefullyApply[Wcc]; }; <<*************************>> <> ReadControlBit: PUBLIC PROC[which: ControlBit] RETURNS[current: BOOL] = { isControl1: BOOL = IsControl1[which]; value: CARDINAL = ReadShort[IF isControl1 THEN Consult1 ELSE Consult2]; RETURN[ReturnBit[which, isControl1, value]]; }; SetControlBit: PUBLIC PROC[which: ControlBit] RETURNS[previous: BOOL] = { value: CARDINAL = ReadShort[GetControlResetAddr[which] + 2]; RETURN[ReturnBit[which, IsControl1[which], value]]; }; ResetControlBit: PUBLIC PROC[which: ControlBit] RETURNS[previous: BOOL] = { value: CARDINAL = ReadShort[GetControlResetAddr[which]]; RETURN[ReturnBit[which, IsControl1[which], value]]; }; ResetIFUCacheStateMachine: PUBLIC PROC = { [] _ ReadShort[CasIFUCacheStateMachine]; [] _ ReadShort[CarIFUCacheStateMachine]; }; ResetEUCacheStateMachine: PUBLIC PROC = { [] _ ReadShort[CasEUCacheStateMachine]; [] _ ReadShort[CarEUCacheStateMachine]; }; DisableIFUCache: PUBLIC PROC = { [] _ ReadShort[CarNotResetIFUCache] }; DisableEUCache: PUBLIC PROC = { [] _ ReadShort[CarNotResetEUCache] }; FlushIFUCache: PUBLIC PROC = { [] _ ReadShort[CarNotResetIFUCache]; [] _ ReadShort[CasNotResetIFUCache] }; FlushEUCache: PUBLIC PROC = { [] _ ReadShort[CarNotResetEUCache]; [] _ ReadShort[CasNotResetEUCache] }; DragonHaltInPhase: PUBLIC PROC[phase: SoftcardOps.DragonPhase _ phaseA] = { isPhaseA: BOOL; isBetween: BOOL; currentPhase: SoftcardOps.DragonPhase _ phaseA; NextOf: PROC[current: SoftcardOps.DragonPhase] RETURNS[SoftcardOps.DragonPhase] = { IF current = LAST[SoftcardOps.DragonPhase] THEN RETURN[FIRST[SoftcardOps.DragonPhase]]; RETURN[SUCC[current]]; }; [] _ ReadShort[CarDragonRun]; -- stop if running, noop if stopped isBetween _ ReadControlBit[dragonStep]; isPhaseA _ ReadStatusBit[phaseA]; SELECT TRUE FROM isPhaseA AND ~isBetween => currentPhase _ phaseA; isPhaseA AND isBetween => currentPhase _ betweenAandB; ~isPhaseA AND ~isBetween => currentPhase _ phaseB; ~isPhaseA AND isBetween => currentPhase _ betweenBandA; ENDCASE => NULL; IF currentPhase = phase THEN RETURN; -- we got lucky IF isBetween THEN { [] _ ReadShort[CarDragonStep]; IF (currentPhase _ NextOf[currentPhase]) = phase THEN RETURN; [] _ ReadShort[CasDragonStep]; IF (currentPhase _ NextOf[currentPhase]) = phase THEN RETURN; [] _ ReadShort[CarDragonStep]; } ELSE { [] _ ReadShort[CasDragonStep]; IF (currentPhase _ NextOf[currentPhase]) = phase THEN RETURN; [] _ ReadShort[CarDragonStep]; IF (currentPhase _ NextOf[currentPhase]) = phase THEN RETURN; [] _ ReadShort[CasDragonStep]; }; }; DragonStep: PUBLIC PROC[which: SoftcardOps.DragonStepSize] RETURNS[ok: BOOL] = { IF ReadControlBit[dragonRun] THEN RETURN[FALSE]; -- dragon is running IF ReadControlBit[dragonStep] THEN { [] _ ReadShort[CarDragonStep]; IF which = quarter THEN RETURN[TRUE]; [] _ ReadShort[CasDragonStep]; IF which = half THEN RETURN[TRUE]; [] _ ReadShort[CarDragonStep]; [] _ ReadShort[CasDragonStep]; } ELSE { [] _ ReadShort[CasDragonStep]; IF which = quarter THEN RETURN[TRUE]; [] _ ReadShort[CarDragonStep]; IF which = half THEN RETURN[TRUE]; [] _ ReadShort[CasDragonStep]; [] _ ReadShort[CarDragonStep]; }; RETURN[TRUE]; }; DragonRun: PUBLIC PROC = { [] _ ReadShort[CasDragonRun] }; DragonStop: PUBLIC PROC = { [] _ ReadShort[CarDragonRun] }; ResetCounter: PUBLIC PROC = { [] _ ReadShort[CarNotResetCounter]; [] _ ReadShort[CasNotResetCounter]; }; <<***** ***** ***** ***** ***** ***** ***** ***** >> IsControl1: PROC[which: ControlBit] RETURNS[BOOL] = { SELECT which FROM iopIntToDragon, mesaIntToDragon, notResetCounter => RETURN[FALSE]; ENDCASE => RETURN[TRUE]; }; GetControlResetAddr: PROC[which: ControlBit] RETURNS[Addr] = { SELECT which FROM resetDragon => RETURN[CarDragon]; interruptDragonToIOP => RETURN[CarInterruptDragonToIOP]; interruptDragonToMesa => RETURN[CarInterruptDragonToMesa]; dragonRun => RETURN[CarDragonRun]; dragonStep => RETURN[CarDragonStep]; writeParity => RETURN[CarWriteParity]; virtualMemAccessIOP => RETURN[CarVirtualMemAccessIOP]; virtualMemAccessMesa => RETURN[CarVirtualMemAccessMesa]; virtualMemAccessIFU => RETURN[CarVirtualMemAccessIFU]; virtualMemAccessEU => RETURN[CarVirtualMemAccessEU]; resetIFUCacheStateMachine => RETURN[CarIFUCacheStateMachine]; notResetIFUCache => RETURN[CarNotResetIFUCache]; ifuBreakpointEnabled => RETURN[CarEnableIFUBkpt]; resetEUCacheStateMachine => RETURN[CarEUCacheStateMachine]; euBreakpointEnabled => RETURN[CarEnableEUBkpt]; notResetEUCache => RETURN[CarEnableEUBkpt]; iopIntToDragon => RETURN[CarIOPIntToDragon]; mesaIntToDragon => RETURN[CarMesaIntToDragon]; notResetCounter => RETURN[CarNotResetCounter]; ENDCASE => ERROR; }; ReturnBit: PROC[which: ControlBit, isControl1: BOOL, value: CARDINAL] RETURNS[BOOL] = { control1Bits: Control1Bits; control2Bits: Control2Bits; IF isControl1 THEN control1Bits _ LOOPHOLE[value] ELSE control2Bits _ LOOPHOLE[value]; SELECT which FROM resetDragon => RETURN[control1Bits.resetDragon]; interruptDragonToIOP => RETURN[control1Bits.interruptDragonToIOP]; interruptDragonToMesa => RETURN[control1Bits.interruptDragonToMesa]; dragonRun => RETURN[control1Bits.dragonRun]; dragonStep => RETURN[control1Bits.dragonStep]; writeParity => RETURN[control1Bits.writeParity]; virtualMemAccessIOP => RETURN[control1Bits.virtualMemAccessIOP]; virtualMemAccessMesa => RETURN[control1Bits.virtualMemAccessMesa]; virtualMemAccessIFU => RETURN[control1Bits.virtualMemAccessIFU]; resetIFUCacheStateMachine => RETURN[control1Bits.resetIFUCacheStateMachine]; notResetIFUCache => RETURN[control1Bits.notResetIFUCache]; ifuBreakpointEnabled => RETURN[control1Bits.enableIFUBkpt]; resetEUCacheStateMachine => RETURN[control1Bits.resetEUCacheStateMachine]; notResetEUCache => RETURN[control1Bits.notResetEUCache]; euBreakpointEnabled => RETURN[control1Bits.enableEUBkpt]; virtualMemAccessEU => RETURN[control1Bits.virtualMemAccessEU]; iopIntToDragon => RETURN[control2Bits.iopIntToDragon]; mesaIntToDragon => RETURN[control2Bits.mesaIntToDragon]; notResetCounter => RETURN[control2Bits.notResetCounter]; ENDCASE => ERROR; }; <<>> <<*************************>> ReadStatusBit: PUBLIC PROC[which: StatusBit] RETURNS[current: BOOL] = { all: StatusBits = LOOPHOLE[ReadShort[ConsultStatusAddr]]; RETURN[SelectStatusBit[which, all] ]; }; ResetStatusBit: PUBLIC PROC[which: StatusBit] RETURNS[previous: BOOL] = { all: StatusBits = LOOPHOLE[ReadShort[SelectStatusResetAddr[which]]]; RETURN[SelectStatusBit[which, all] ]; }; SelectStatusBit: PROC[which: StatusBit, all: StatusBits] RETURNS[BOOL] = { SELECT which FROM phaseA => RETURN[all.phaseA]; periodicIntToDragon => RETURN[all.periodicIntToDragon]; notMemoryError => RETURN[all.notMemoryError]; euBkptReached => RETURN[all.euBkptReached]; ifuBkptReached => RETURN[all.ifuBkptReached]; mapError => RETURN[all.mapError]; ENDCASE => ERROR; }; SelectStatusResetAddr: PROC[which: StatusBit] RETURNS[Addr] = { SELECT which FROM periodicIntToDragon => RETURN[Car1PeriodicIntToDragon]; notMemoryError => RETURN[Car1NotMemoryError]; euBkptReached => RETURN[Car1EUBrkptReached]; ifuBkptReached => RETURN[Car1IFUBrkptReached]; mapError => RETURN[Car1MapError]; ENDCASE => ERROR; }; <<>> <<*************************>> <> MesaMapIndex: TYPE = SoftcardOps.MesaMapIndex; MesaMapEntry: TYPE = SoftcardOps.MesaMapEntry; ReadMesaMap: PUBLIC PROC[index: MesaMapIndex] RETURNS[value: MesaMapEntry] = { RETURN[LOOPHOLE[ReadShort[MesaMapAddr + 2*LONG[index] + 1], MesaMapEntry] ] }; WriteMesaMap: PUBLIC PROC[index: MesaMapIndex, value: MesaMapEntry] = { WriteShort[MesaMapAddr+2*LONG[index]+1, LOOPHOLE[value, CARDINAL] ] }; <<>> <<*************************>> <> DragonMapIndex: TYPE = SoftcardOps.DragonMapIndex; DragonMapEntry: TYPE = SoftcardOps.DragonMapEntry; ReadDragonMap: PUBLIC PROC[index: DragonMapIndex] RETURNS[value: DragonMapEntry] = { RETURN[LOOPHOLE[ReadShort[DragonMapAddr+2*index+1], DragonMapEntry] ] }; WriteDragonMap: PUBLIC PROC[index: DragonMapIndex, value: DragonMapEntry] = { WriteShort[DragonMapAddr+2*index+1, LOOPHOLE[value, CARDINAL] ] }; <<*************************>> <> <<>> CarefullyApply: PROC[proc: PROC, nilHandleOK: BOOL _ FALSE] = { cText: ROPE; cAtom: ATOM; BEGIN ENABLE BEGIN CrRPC.Error => { cText _ text; cAtom _ $crRPCError; GOTO error; }; Rapunzel.Fault => { SELECT code FROM nonexistent => cText _ IO.PutFR[" Nonexistent address %g\n", IO.card[address] ]; protection => cText _ IO.PutFR[" Protection error for address %g\n", IO.card[address] ]; alignmentShort => cText _ IO.PutFR[" AlignmentShort error for address %g\n", IO.card[address] ]; alignmentLong => cText _ IO.PutFR["AlignmentLong error for addr: %g\n", IO.card[address] ]; ENDCASE => cText _ IO.PutFR["Unknown Rapunzel Fault code for address %g\n", IO.card[address] ]; cAtom _ $RapunzelFault; GOTO error; }; END; IF ~nilHandleOK AND crHandle = NIL THEN SIGNAL SoftcardOps.Error[$noConnection, "open a connection first"]; proc[]; EXITS error => SIGNAL SoftcardOps.Error[cAtom, cText]; END; }; <<>> ReadShort: PUBLIC PROC[addr: Addr] RETURNS[value: CARDINAL] = { Rs: PROC = { value _ Rapunzel.PeekShort[crHandle, addr] }; CarefullyApply[Rs]; }; WriteShort: PUBLIC PROC[addr: Addr, value: CARDINAL] = { Ws: PROC = { Rapunzel.PokeShort[crHandle, addr, value] }; CarefullyApply[Ws]; }; ReadLong: PUBLIC PROC[addr: Addr] RETURNS[value: LONG CARDINAL] = { Rl: PROC = { swappedVal: LONG CARDINAL = Rapunzel.PeekLong[crHandle, addr]; value _ LOOPHOLE[Basics.SwapHalves[LOOPHOLE[swappedVal]]]; }; CarefullyApply[Rl]; }; WriteLong: PUBLIC PROC[addr: Addr, value: LONG CARDINAL] = { Rl: PROC = { swappedVal: LONG CARDINAL = LOOPHOLE[Basics.SwapHalves[LOOPHOLE[value]]]; Rapunzel.PokeLong[crHandle, addr, swappedVal]; }; CarefullyApply[Rl]; }; DumpShort: PUBLIC PROC[addr: Addr, num: CARDINAL] RETURNS[ss: Rapunzel.SeqShort] = { Ds: PROC = { ss _ Rapunzel.PeekSeqShort[crHandle, addr, num] }; CarefullyApply[Ds]; }; ConstructReadSeq: PROC[isEU: BOOL] RETURNS[tSeq: Rapunzel.SeqCmd] = { <> psDragonRun: Rapunzel.PeekShortCmd = [CarDragonRun]; psConsultStatus: Rapunzel.PeekShortCmd = [ConsultStatusAddr]; drEU: Rapunzel.PeekShortCmd = [DebugReadEU]; drIFU: Rapunzel.PeekShortCmd = [DebugReadIFU]; seqLen: CARDINAL = IF isEU THEN 5 ELSE 4; -- magic here - overhead rlCmd: Rapunzel.ReturnLengthCmd; srCmd: Rapunzel.ShftReadCmd; srCmd.numRepeats _ IF isEU THEN numEUBits ELSE numIFUBits; rlCmd.returnLength _ IF isEU THEN numEUBits+3 ELSE numIFUBits+2; tSeq _ NEW[Rapunzel.SeqCmdObject[seqLen]]; TRUSTED { tSeq[0] _ [returnLength[rlCmd] ]; -- how long the result is tSeq[1] _ [peekShort[psDragonRun] ]; -- stop the Dragon first IF isEU THEN { <> tSeq[3] _ [peekShort[drEU] ]; tSeq[4] _ [shftRead[srCmd] ]; } ELSE { tSeq[2] _ [peekShort[drIFU] ]; tSeq[3] _ [shftRead[srCmd] ]; }; }; }; ConstructWriteSeq: PROC[isEU: BOOL] RETURNS[tSeq: Rapunzel.SeqCmd] = { <> psDragonRun: Rapunzel.PeekShortCmd = [CarDragonRun]; psConsultStatus: Rapunzel.PeekShortCmd = [ConsultStatusAddr]; dwEU: Rapunzel.PeekShortCmd = [DebugWriteEU]; dwIFU: Rapunzel.PeekShortCmd = [DebugWriteIFU]; seqLen: CARDINAL = IF isEU THEN 5+numEUBits ELSE 4+numEUBits; -- magic here rlCmd: Rapunzel.ReturnLengthCmd; swCmd: Rapunzel.ShftWriteCmd; swCmd.numRepeats _ IF isEU THEN numEUBits ELSE numIFUBits; rlCmd.returnLength _ IF isEU THEN 4 ELSE 3; tSeq _ NEW[Rapunzel.SeqCmdObject[seqLen]]; TRUSTED { tSeq[0] _ [returnLength[rlCmd] ];-- how long the result is IF isEU THEN tSeq[2] _ [shftWrite[swCmd] ] ELSE tSeq[1] _ [shftWrite[swCmd] ]; <> tSeq[seqLen-2] _ [peekShort[psDragonRun] ]; -- stop the Dragon before the write IF isEU THEN tSeq[seqLen-1] _ [peekShort[dwEU] ] ELSE tSeq[seqLen-1] _ [peekShort[dwIFU] ]; }; }; <<***********************************>> <<>> END.