SoftcardOpsImpl.Mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Willie-Sue, April 2, 1987 10:01:15 am PST
Bill Jackson (bj) February 3, 1987 7:01:49 pm PST
Christophe Cuenod March 23, 1987 12:35:48 pm PST
DIRECTORY
Basics USING [LongNumber, SwapHalves],
CrRPC USING [Error, Handle, CreateClientHandle, DestroyClientHandle],
IO,
RapunzelP2200V3,
Rope USING [Equal, ROPE],
SoftcardOps,
SoftcardPrivate,
XNS USING [Address, GetThisHost, unknownSocket],
XNSCH USING [LookupAddressFromRope];
SoftcardOpsImpl:
CEDAR
MONITOR
IMPORTS
Basics, CrRPC, IO, RapunzelP2200V3, Rope, XNS, XNSCH
= BEGIN OPEN SoftcardPrivate, Rapunzel: RapunzelP2200V3;
ROPE: TYPE = Rope.ROPE;
Addr: TYPE = SoftcardOps.Addr;
Rcmo: TYPE = Rapunzel.CmdObject;
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;
DragonPhase: TYPE = SoftcardOps.DragonPhase;
ControlBit: TYPE = SoftcardOps.ControlBit;
StatusBit: TYPE = SoftcardOps.StatusBit;
OneBit: TYPE = SoftcardPrivate.OneBit;
Control1Bits: TYPE = SoftcardPrivate.Control1Bits;
Control2Bits: TYPE = SoftcardPrivate.Control2Bits;
StatusBits: TYPE = SoftcardPrivate.StatusBits;
for compiling purposes
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: CARD16 = 32;
readEUSeq: Rapunzel.SeqCmd;
writeEUSeq: Rapunzel.SeqCmd;
numIFUBits: CARD16 = 488;
readIFUSeq: Rapunzel.SeqCmd;
writeIFUSeq: Rapunzel.SeqCmd;
resetBoardSeq: Rapunzel.SeqCmd;
SCError: PUBLIC SIGNAL[code: ATOM, explanation: ROPE ← NIL] = CODE;
EstablishConnection:
PUBLIC
PROC[host:
ROPE]
RETURNS[ok:
BOOL] = {
Ec:
PROC = {
netAddr: XNS.Address;
refNet: REF 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;
};
refNet ← NEW[ XNS.Address ← [netAddr.net, netAddr.host, netAddr.socket] ];
crHandle ← CrRPC.CreateClientHandle[$SPP, refNet];
Rapunzel.SetShftAddrs[crHandle, DebugShiftA, DebugShiftB];
};
CarefullyApply[proc: Ec, nilHandleOK: TRUE];
RETURN[crHandle # NIL];
};
CloseConnection:
PUBLIC
PROC = {
IF crHandle = NIL THEN RETURN;
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] = {
user: FullWordifuPBusCmd = LOOPHOLE[ReadShort[SpyCmd2]];
most: FullWordeuPBusCmd = LOOPHOLE[ReadShort[SpyCmd1]];
euPBusCmd.userMode ← user.userMode;
euPBusCmd.unspecifiedAsYet ← most.unspecifiedAsYet;
};
ReadIFUCmd:
PUBLIC
PROC
RETURNS[ifuPBusCmd: IFUPBusCmd] = {
ifuPBusCmd ← LOOPHOLE[ReadShort[SpyCmd2], FullWordifuPBusCmd].ifuPBusCmd
};
ReadEUPBusData:
PUBLIC
PROC
RETURNS[value:
CARD32] = {
value ← ReadLong[SpyEUDataH]
};
ReadIFUPBusData:
PUBLIC
PROC
RETURNS[value:
CARD32] = {
value ← ReadLong[SpyIFUDataH]
};
ReadClock:
PUBLIC
PROC
RETURNS[value:
CARD32] = {
value ← ReadLong[ClockH]
};
*************************
ReadEURegister:
PUBLIC
PROC[which: EUInternal]
RETURNS[value:
CARD32] = {
resultSeq: Rapunzel.SeqResult;
theBits: PACKED ARRAY [0..32) OF OneBit;
seqIndex: CARD16 ← 0;
resIndex: CARD16 ← 0;
debugInfo: DebugInfoEntry;
setEUAddr: Rapunzel.PokeShortCmd;
Reur:
PROC =
{ resultSeq ← Rapunzel.DoCmds[crHandle, readEUSeq] };
debugInfo.debugEUAddr ←
ORD[which];
setEUAddr.address ← SoftcardPrivate.DebugInfo;
setEUAddr.value ← LOOPHOLE[debugInfo];
IF readEUSeq = NIL THEN readEUSeq ← ConstructReadSeq[isEU: TRUE];
TRUSTED { readEUSeq[2] ← NEW[ Rcmo ← [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[Basics.SwapHalves[LOOPHOLE[theBits]]];
TRUSTED { SELECT which FROM
kReg => value ← [kReg [kVal: LOOPHOLE[theBits]]];
field => value ← [field [fVal: LOOPHOLE[theBits]]];
ENDCASE => value ← [regular [rVal: LOOPHOLE[theBits]]];
};
};
WriteEURegister:
PUBLIC
PROC[which: EUInternal, value:
CARD32] = {
theBits: PACKED ARRAY [0..32) OF OneBit;
seqIndex: CARD16 ← 0;
debugInfo: DebugInfoEntry;
setEUAddr: Rapunzel.PokeShortCmd;
one: Rapunzel.PokeShortCmd;
Weur:
PROC =
{ [] ← Rapunzel.DoCmds[crHandle, writeEUSeq] };
TRUSTED { WITH value: value SELECT FROM
kReg => theBits ← LOOPHOLE[value.kVal];
field => theBits ← LOOPHOLE[value.fVal];
regular => theBits ← LOOPHOLE[value.rVal];
ENDCASE;
};
theBits ← LOOPHOLE[Basics.SwapHalves[LOOPHOLE[value]]];
debugInfo.debugEUAddr ←
ORD[which];
setEUAddr.address ← SoftcardPrivate.DebugInfo;
setEUAddr.value ← LOOPHOLE[debugInfo];
one.address ← DebugWriteEU;
IF writeEUSeq = NIL THEN writeEUSeq ← ConstructWriteSeq[isEU: TRUE];
TRUSTED { writeEUSeq[1] ← NEW[ Rcmo ← [pokeShort[setEUAddr] ]] };
WHILE seqIndex < writeEUSeq.length
DO
this: Rapunzel.Cmd = writeEUSeq.body[seqIndex];
one: Rapunzel.PokeShortCmd;
WITH this: this
SELECT
FROM
shftWrite => {
FOR valIndex:
CARD16
IN [0..this.shftWrite.numRepeats)
DO
seqIndex ← seqIndex + 1;
debugInfo.debugInEU ← theBits[valIndex];
one.value ← LOOPHOLE[debugInfo];
TRUSTED { writeEUSeq.body[seqIndex] ←
NEW[ Rcmo ← [pokeShort[one]] ] };
ENDLOOP;
};
ENDCASE => seqIndex ← seqIndex + 1;
ENDLOOP;
CarefullyApply[Weur];
};
ReadIFUState:
PUBLIC
PROC
RETURNS[ifuState: IFUInternalState] = {
the IFU has only one internal state register format tbd
resultSeq: Rapunzel.SeqResult;
seqIndex: CARD16 ← 0;
resIndex: CARD16 ← 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 => ifuState[resIndex] ← one.peekShort.value;
ENDCASE => NULL;
ENDLOOP;
};
ENDCASE => seqIndex ← seqIndex + 1;
ENDLOOP;
};
WriteIFUState:
PUBLIC
PROC[ifuState: IFUInternalState] = {
seqIndex: CARD16 ← 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:
CARD16
IN [0..this.shftWrite.numRepeats)
DO
seqIndex ← seqIndex + 1;
one.value ← ifuState[valIndex];
TRUSTED { writeEUSeq.body[seqIndex] ←
NEW[Rcmo ← [pokeShort[one]] ] };
ENDLOOP;
};
ENDCASE => seqIndex ← seqIndex + 1;
ENDLOOP;
CarefullyApply[Wifu];
};
*************************
Control and status bits. These are accessed only through Read operations. Some locations allow one to read a word of (up to) 16 of those bits without changing any of the bits. Reading other locations allows one to set or reset one particular bit, while still returning the previous value of all the bits.
ReadControlBit:
PUBLIC
PROC[which: ControlBit]
RETURNS[current:
BOOL] = {
isControl1: BOOL = IsControl1[which];
value: CARD16 = ReadShort[IF isControl1 THEN Consult1 ELSE Consult2];
RETURN[ReturnBit[which, isControl1, value]];
};
SetControlBit:
PUBLIC
PROC[which: ControlBit]
RETURNS[previous:
BOOL] = {
value: CARD16 = ReadShort[GetControlResetAddr[which] + 2];
RETURN[ReturnBit[which, IsControl1[which], value]];
};
ResetControlBit:
PUBLIC
PROC[which: ControlBit]
RETURNS[previous:
BOOL] = {
value: CARD16 = 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: DragonPhase ← phaseA] = {
isBetween: BOOL;
currentPhase: DragonPhase ← phaseA;
NextOf:
PROC[current: DragonPhase]
RETURNS[DragonPhase] = {
IF current = LAST[DragonPhase] THEN RETURN[FIRST[DragonPhase]];
RETURN[SUCC[current]];
};
[] ← ReadShort[CarDragonRun]; -- stop if running, noop if stopped
IF (currentPhase ← CurrentDragonPhase[].phase) = phase THEN RETURN; -- we got lucky
IF (isBetween ← ReadControlBit[dragonStep])
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];
};
CurrentDragonPhase:
PUBLIC
PROC
RETURNS[phase: DragonPhase, ok:
BOOL] = {
isPhaseA: BOOL;
isBetween: BOOL;
IF ReadControlBit[dragonRun] THEN RETURN[phaseA, FALSE]; -- dragon is running
isBetween ← ReadControlBit[dragonStep];
isPhaseA ← ReadStatusBit[phaseA];
SELECT
TRUE
FROM
isPhaseA AND ~isBetween => phase ← phaseA;
isPhaseA AND isBetween => phase ← betweenAandB;
~isPhaseA AND ~isBetween => phase ← phaseB;
~isPhaseA AND isBetween => phase ← betweenBandA;
ENDCASE => RETURN[phaseA, FALSE];
RETURN[phase, TRUE];
};
DragonRun:
PUBLIC
PROC = {
[] ← ReadShort[CasDragonRun]
};
DragonStop:
PUBLIC
PROC = {
[] ← ReadShort[CarDragonRun]
};
ResetClock:
PUBLIC
PROC = {
[] ← ReadShort[CarNotResetClock];
[] ← ReadShort[CasNotResetClock];
};
ResetBoard:
PUBLIC
PROC = {
cc: ClockControl = [reserved: 0, freqSelect: 3, phaseAdjust: 7, delay: 7];
Rb:
PROC = {
[] ← Rapunzel.DoCmds[crHandle, resetBoardSeq];
Rapunzel.PokeShort[crHandle, ClockControlAddr, LOOPHOLE[cc, CARD16]];
};
IF resetBoardSeq =
NIL
THEN {
psCmd: Rapunzel.PeekShortCmd ← [CarDragonRun];
resetBoardSeq ← NEW[Rapunzel.SeqCmdObject[18]];
stop the dragon
resetBoardSeq[0] ← NEW[Rcmo ← [peekShort[psCmd]] ];
resetBoardSeq[1] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarDragon+2]] ] ];
disable the CacheStateMachines
resetBoardSeq[2] ←
NEW[Rcmo ← [peekShort[psCmd ← [CasIFUCacheStateMachine]] ] ];
resetBoardSeq[3] ←
NEW[Rcmo ← [peekShort[psCmd ← [CasEUCacheStateMachine]] ] ];
disable caches
resetBoardSeq[4] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarNotResetIFUCache]] ] ];
resetBoardSeq[5] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarNotResetEUCache]] ] ];
enable the CacheStateMachines
resetBoardSeq[6] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarIFUCacheStateMachine]] ] ];
resetBoardSeq[7] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarEUCacheStateMachine]] ] ];
reset interrupts
resetBoardSeq[8] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarInterruptDragonToIOP]] ] ];
resetBoardSeq[9] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarInterruptDragonToMesa]] ] ];
resetBoardSeq[10] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarIOPIntToDragon]] ] ];
resetBoardSeq[11] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarMesaIntToDragon]] ] ];
reset breakpoints, virtualmemory access
resetBoardSeq[12] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarEnableIFUBkpt]] ] ];
resetBoardSeq[13] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarEnableEUBkpt]] ] ];
resetBoardSeq[14] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarVirtualMemAccessIFU]] ] ];
resetBoardSeq[15] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarVirtualMemAccessEU]] ] ];
resetBoardSeq[16] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarVirtualMemAccessIOP]] ] ];
resetBoardSeq[17] ←
NEW[Rcmo ← [peekShort[psCmd ← [CarVirtualMemAccessMesa]] ] ];
};
CarefullyApply[Rb];
};
***** ***** ***** ***** ***** ***** ***** *****
IsControl1:
PROC[which: ControlBit]
RETURNS[
BOOL] = {
SELECT which
FROM
iopIntToDragon, mesaIntToDragon, notResetClock => 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];
notResetClock => RETURN[CarNotResetClock];
ENDCASE => ERROR;
};
ReturnBit:
PROC[which: ControlBit, isControl1:
BOOL, value:
CARD16]
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];
notResetClock => RETURN[control2Bits.notResetClock];
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;
};
*************************
The mapping between 2 megabytes of daybreak physical address space and Dragon memory
MesaMapIndex: TYPE = SoftcardOps.MesaMapIndex;
MesaMapEntry: TYPE = SoftcardOps.MesaMapEntry;
ReadMesaMap:
PUBLIC
PROC[index: MesaMapIndex]
RETURNS[value: MesaMapEntry] = {
RETURN[
LOOPHOLE[ReadShort[MesaMapAddr + 4*LONG[index] + 1], MesaMapEntry] ]
};
WriteMesaMap:
PUBLIC
PROC[index: MesaMapIndex, value: MesaMapEntry] = {
WriteShort[MesaMapAddr+4*LONG[index]+1, LOOPHOLE[value, CARD16] ]
};
*************************
Utilities
CarefullyApply is an entry proc to limit access to crHandle - only one call at a time allowed
CarefullyApply:
ENTRY
PROC[proc:
PROC, nilHandleOK:
BOOL ←
FALSE] = {
ENABLE UNWIND => NULL;
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;
};
IF ~nilHandleOK
AND crHandle =
NIL
THEN
SIGNAL SCError[$noConnection, "open a connection first"];
proc[];
EXITS
error => SIGNAL SCError[cAtom, cText];
END;
};
ReadShort:
PUBLIC
PROC[addr: Addr]
RETURNS[value:
CARD16] = {
Rs:
PROC =
{ value ← Rapunzel.PeekShort[crHandle, addr] };
CarefullyApply[Rs];
};
WriteShort:
PUBLIC
PROC[addr: Addr, value:
CARD16] = {
Ws:
PROC =
{ Rapunzel.PokeShort[crHandle, addr, value] };
CarefullyApply[Ws];
};
ReadLong:
PUBLIC
PROC[addr: Addr]
RETURNS[value:
CARD32] = {
Rl:
PROC = {
swappedVal: CARD32 = Rapunzel.PeekLong[crHandle, addr];
value ← LOOPHOLE[Basics.SwapHalves[LOOPHOLE[swappedVal]]];
value ← Rapunzel.PeekLong[crHandle, addr];
};
IF AddrIsOdd[addr] THEN SIGNAL SCError[$RapunzelFault, "alignmentLong"];
CarefullyApply[Rl];
};
WriteLong:
PUBLIC
PROC[addr: Addr, value:
CARD32] = {
Wl:
PROC = {
swappedVal: CARD32 = LOOPHOLE[Basics.SwapHalves[LOOPHOLE[value]]];
Rapunzel.PokeLong[crHandle, addr, value];
};
IF AddrIsOdd[addr] THEN SIGNAL SCError[$RapunzelFault, "alignmentLong"];
CarefullyApply[Wl];
};
wmlSeq: Rapunzel.SeqCmd;
rl0Cmd: Rapunzel.ReturnLengthCmd = [0];
WriteMultipleLong:
PUBLIC
PROC[
num: CARD16, proc: PROC RETURNS[addr: Addr, value: CARD32]] = {
Wml:
PROC = {
[] ← Rapunzel.DoCmds[crHandle, wmlSeq];
};
plCmd: Rapunzel.PokeLongCmd;
IF wmlSeq =
NIL
OR wmlSeq.length # num
THEN {
wmlSeq ← NEW[Rapunzel.SeqCmdObject[num]];
};
FOR i:
CARD16
IN [0..num)
DO
[addr: plCmd.address, value: plCmd.value] ← proc[];
wmlSeq[i] ← NEW[Rcmo ← [pokeLong[plCmd]] ];
ENDLOOP;
CarefullyApply[Wml];
};
DumpShort:
PUBLIC
PROC[addr: Addr, num:
CARD16]
RETURNS[ss: Rapunzel.SeqShort] = {
Ds:
PROC =
{ ss ← Rapunzel.PeekSeqShort[crHandle, addr, num] };
CarefullyApply[Ds];
};
DumpLong:
PUBLIC
PROC[addr: Addr, num:
CARD16]
RETURNS[sl: Rapunzel.SeqLong] = {
Dl:
PROC = {
sl ← Rapunzel.PeekSeqLong[crHandle, addr, num];
};
IF AddrIsOdd[addr] THEN SIGNAL SCError[$RapunzelFault, "alignmentLong"];
CarefullyApply[Dl];
};
AddrIsOdd:
PROC[addr: Addr]
RETURNS[
BOOL] = {
ln: Basics.LongNumber = LOOPHOLE[addr];
RETURN[ln.bits[15]];
};
ConstructReadSeq:
PROC[isEU:
BOOL]
RETURNS[tSeq: Rapunzel.SeqCmd] = {
construct a CmdSeq ending with a ShftReadCmd to read n-bits of internal state
psDragonRun: Rapunzel.PeekShortCmd = [CarDragonRun];
drEU: Rapunzel.PeekShortCmd = [DebugReadEU];
drIFU: Rapunzel.PeekShortCmd = [DebugReadIFU];
seqLen: CARD16 = IF isEU THEN 5 ELSE 4; -- magic here - overhead
rlCmd: Rapunzel.ReturnLengthCmd;
srCmd: Rapunzel.ShftReadCmd;
IF isEU
THEN {
srCmd.numRepeats ← numEUBits;
rlCmd.returnLength ← numEUBits+4
}
ELSE {
srCmd.numRepeats ← numIFUBits;
rlCmd.returnLength ← numIFUBits+3;
};
srCmd.address ← ConsultStatusAddr;
tSeq ← NEW[Rapunzel.SeqCmdObject[seqLen]];
TRUSTED {
tSeq[0] ← NEW[Rcmo ← [returnLength[rlCmd]] ]; -- how long the result is
tSeq[1] ← NEW[Rcmo ← [peekShort[psDragonRun]] ]; -- stop the Dragon first
IF isEU
THEN {
for EU, tSeq[2] sets the euAddr to read
tSeq[3] ← NEW[Rcmo ← [peekShort[drEU]] ];
tSeq[4] ← NEW[Rcmo ← [shftRead[srCmd]] ];
}
ELSE {
tSeq[2] ← NEW[Rcmo ← [peekShort[drIFU]] ];
tSeq[3] ← NEW[Rcmo ← [shftRead[srCmd]] ];
};
};
};
ConstructWriteSeq:
PROC[isEU:
BOOL]
RETURNS[tSeq: Rapunzel.SeqCmd] = {
construct a CmdSeq using a ShftWriteCmd to write n-bits of internal state
psDragonRun: Rapunzel.PeekShortCmd = [CarDragonRun];
dwEU: Rapunzel.PeekShortCmd = [DebugWriteEU];
dwIFU: Rapunzel.PeekShortCmd = [DebugWriteIFU];
seqLen: CARD16 = IF isEU THEN 5+numEUBits ELSE 4+numEUBits; -- magic here
rlCmd: Rapunzel.ReturnLengthCmd;
swCmd: Rapunzel.ShftWriteCmd;
IF isEU
THEN {
swCmd.numRepeats ← numEUBits;
rlCmd.returnLength ← 4;
}
ELSE {
swCmd.numRepeats ← numIFUBits;
rlCmd.returnLength ← 3;
};
swCmd.address ← DebugInfo;
tSeq ← NEW[Rapunzel.SeqCmdObject[seqLen]];
TRUSTED {
tSeq[0] ← NEW[Rcmo ← [returnLength[rlCmd]] ];-- how long the result is
IF isEU
THEN tSeq[2] ←
NEW[Rcmo ← [shftWrite[swCmd]] ]
ELSE tSeq[1] ← NEW[Rcmo ← [shftWrite[swCmd]] ];
the bits go in the middle
tSeq[seqLen-2] ←
NEW[Rcmo ← [peekShort[psDragonRun]] ]; -- stop the Dragon before the write
IF isEU
THEN tSeq[seqLen-1] ←
NEW[Rcmo ← [peekShort[dwEU]] ]
ELSE tSeq[seqLen-1] ← NEW[Rcmo ← [peekShort[dwIFU]] ];
};
};