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
EXPORTS
SoftcardOps

= 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;


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;

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]]];
 
};

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] };


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] = {
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];
};

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, CARD16]] };
CarefullyApply[Wcc];
};


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]];
resetBoardSeq[0] _ NEW[Rcmo _ [peekShort[psCmd]] ];
resetBoardSeq[1] _
NEW[Rcmo _ [peekShort[psCmd _ [CarDragon+2]] ] ];
resetBoardSeq[2] _
NEW[Rcmo _ [peekShort[psCmd _ [CasIFUCacheStateMachine]] ] ];
resetBoardSeq[3] _
NEW[Rcmo _ [peekShort[psCmd _ [CasEUCacheStateMachine]] ] ];

resetBoardSeq[4] _
NEW[Rcmo _ [peekShort[psCmd _ [CarNotResetIFUCache]] ] ];
resetBoardSeq[5] _
NEW[Rcmo _ [peekShort[psCmd _ [CarNotResetEUCache]] ] ];
resetBoardSeq[6] _
NEW[Rcmo _ [peekShort[psCmd _ [CarIFUCacheStateMachine]] ] ];
resetBoardSeq[7] _
NEW[Rcmo _ [peekShort[psCmd _ [CarEUCacheStateMachine]] ] ];

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]] ] ];
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;
};


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] ]
};

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, CARD16] ]
};


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;
};
END;

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 = {
value _ Rapunzel.PeekLong[crHandle, addr];
};
IF AddrIsOdd[addr] THEN SIGNAL SCError[$RapunzelFault, "alignmentLong"];
CarefullyApply[Rl];
};

WriteLong: PUBLIC PROC[addr: Addr, value: CARD32] = {
Wl: PROC = {
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]  = {
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 {
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]  = {
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]] ];
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]] ];
};
};


END.


�����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

for compiling purposes
-- various CmdSeqences to be shared
*************************

TRUSTED { SELECT which FROM
kReg => value _ [kReg [kVal: LOOPHOLE[theBits]]];
field => value _ [field [fVal: LOOPHOLE[theBits]]];
ENDCASE => value _ [regular [rVal: LOOPHOLE[theBits]]];
};
TRUSTED { WITH value: value SELECT FROM
kReg => theBits _ LOOPHOLE[value.kVal];
field => theBits _ LOOPHOLE[value.fVal];
regular => theBits _ LOOPHOLE[value.rVal];
ENDCASE;
};

the IFU has only one internal state register format tbd

*************************
*************************
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.
stop the dragon

disable the CacheStateMachines
disable caches
enable the CacheStateMachines
reset interrupts

reset breakpoints, virtualmemory access
***** ***** ***** ***** ***** ***** ***** ***** 

*************************

*************************
The mapping between 2 megabytes of daybreak physical address space and Dragon memory

*************************
Access to the Dragon Map
*************************
Utilities

CarefullyApply is an entry proc to limit access to crHandle - only one call at a time allowed

swappedVal: CARD32 = Rapunzel.PeekLong[crHandle, addr];
value _ LOOPHOLE[Basics.SwapHalves[LOOPHOLE[swappedVal]]];
swappedVal: CARD32 = LOOPHOLE[Basics.SwapHalves[LOOPHOLE[value]]];
construct a CmdSeq ending with a ShftReadCmd to read n-bits of internal state
for EU, tSeq[2] sets the euAddr to read
construct a CmdSeq using a ShftWriteCmd to write n-bits of internal state
the bits go in the middle
***********************************

�ÊM��˜�codešœ™KšœB™BKšœ)™)K™1K™0—K™�šÏk	˜	Kšœœ˜&Kšœœ:˜EKšœ˜Kšœ˜Kšœœ	œ˜Kšœ˜Kšœ˜Kšœœ'˜0Jšœœ˜$—K˜�šÏnœœ˜š˜Kšœœœ˜4—š˜Kšœ˜—K˜�Kšœ
œžœ˜8K˜�Kšœœœ˜Kšœœ˜K˜�Kšœœ˜ K˜�KšœœÏc˜/Kšœœ˜*Kšœœ˜*Kšœœ˜*Kšœœ!Ÿ˜=Kšœœ˜.Kšœ
œ˜,K˜�Kšœœ˜*Kšœœ˜(K˜�Kšœœ˜&Kšœœ ˜2Kšœœ ˜2Kšœœ˜.K˜�Kšœ™K˜�š	œœœ	œœ˜4K˜*K˜ K˜—K˜�š	œœœ	œœ˜5K˜ Kšœ,˜,K˜Kšœœœ˜!Kšœ˜K˜—K˜�Kšœ˜K˜�KšŸ#™#Kšœœ˜Kšœ˜Kšœ˜K˜�Kšœœ˜Kšœ˜Kšœ˜Kšœ˜K˜�Kšžœœœœœœœ˜CK˜�šžœœœœœœ˜Bšžœœ˜Kšœ	œ	˜Kšœœœ	˜šœ˜Kšœ&œœ˜Tšœ˜Kšœ
œ%˜4Jšœœ˜#J˜——Jšœ	œœ<˜JJšœ2˜2Jšœ:˜:J˜—Jšœ&œ˜,Jšœœ˜J˜—K˜�šžœœœ˜ Kšœœœœ˜Kšœ$˜$Kšœœ˜K˜—K˜�šžœœœ˜+šžœœ˜Kšœ5˜5—Kšœ˜K˜K˜�—šžœœœ˜,šžœœ˜Kšœ5˜5—Kšœ˜K˜K˜�—šž	œœœœ˜8Kšœœ˜8Kšœœ˜7Kšœ#˜#Kšœ3˜3K˜K˜�—šž
œœœœ˜;Kšœ
œ3˜HKšœ˜K˜�—š
žœœœœœ˜6Kšœ˜Kšœ˜—K˜�š
žœœœœœ˜7Kšœ˜Kšœ˜—K˜�š
ž	œœœœœ˜1Kšœ˜Kšœ˜—K˜�—™K™�š
žœœœœœ˜IKšœ˜Kšœ	œœ	œ˜(Kšœ
œ˜Kšœ
œ˜Kšœ˜Kšœ!˜!šžœœ˜Kšœ5˜5K˜�—šœœ˜#Kšœ.˜.Kšœœ˜&—Kšœ
œœ$œ˜AKšœœ$˜@K˜�Kšœ˜K˜�šœ˜$Kšœ0˜0Kšœ˜šœ
œ˜šœ
˜
šœ
œ˜/Kšœ˜Kšœ$˜+šœ
œ˜šœ˜Kšœœ˜/Kšœ˜K˜—Kšœœ˜—Kšœ˜—K˜—Kšœ˜#—Kšœ˜—Kšœœœ˜7K˜šœœ™Kšœœ™1Kšœœ™3Kšœœ™7K™—Kšœ˜K˜�—šžœœœœ˜BKšœ	œœ	œ˜(Kšœ
œ˜Kšœ˜Kšœ!˜!Kšœ˜šžœœ˜Kšœ/˜/—K˜�šœœœ™'Kšœœ
™'Kšœœ
™(Kšœœ
™*Kšœ™K™—K˜�Kšœ
œœ
˜7šœœ˜#Kšœ.˜.Kšœœ˜&—Kšœ˜Kšœœœ&œ˜DKšœœ$˜Ašœ˜%Kšœ/˜/Kšœ˜šœœ˜šœ˜šœœœ ˜9Kšœ˜Kšœ(˜(Kšœœ˜ šœ˜%Kšœœ˜"—Kšœ˜—K˜—Kšœ˜#—Kšœ˜—Kšœ˜Kšœ˜—K™�šžœœœœ ˜AKšœœ0™7Kšœ˜Kšœ
œ˜Kšœ
œ˜šžœœ˜Kšœ6˜6K˜�—Kšœœœ%œ˜DK˜�Kšœ˜K˜�šœ˜$Kšœ0˜0Kšœ˜šœ
œ˜šœ
˜
šœ
œ˜/Kšœ˜Kšœ$˜+šœ
œ˜Kšœ6˜6Kšœœ˜—Kšœ˜—K˜—Kšœ˜#—Kšœ˜—K˜—K˜�šž
œœœ ˜:Kšœ
œ˜Kšœ˜šžœœ˜Kšœ0˜0—K˜�Kšœ˜Kšœœœ'œ˜GK˜�šœ˜%Kšœ0˜0Kšœ˜šœœ˜šœ˜šœœœ ˜9Kšœ˜Kšœ˜šœ˜%Kšœœ˜!—Kšœ˜—K˜—Kšœ˜#—Kšœ˜—Kšœ˜K˜—K™�—™J˜�šžœœœœ ˜Ešžœœ˜Kšœœ3˜L—K˜K˜—K˜�šžœœœ ˜>šžœœ˜Kšœ1œœ˜S—K˜K˜—J˜�—™Kšœ:Ïbœõ™³K˜�š
žœœœœ
œ˜IKšœœ˜%Kš	œœ
œœ
œ˜EKšœ&˜,K˜K˜�—š
ž
œœœœœ˜IKšœœ-˜:Kšœ-˜3K˜K˜�—š
žœœœœœ˜KKšœœ)˜6Kšœ-˜3K˜—K˜�šžœœœ˜*Kšœ(˜(Kšœ(˜(Kšœ˜—K˜�šžÏtœœ˜)Kšœ'˜'Kšœ'˜'Kšœ˜—K˜�šžœœœ˜ Kšœ#˜#Kšœ˜—K˜�šžœœœ˜Kšœ"˜"Kšœ˜—K˜�šž
œœœ˜Kšœ$˜$Kšœ#˜#Kšœ˜—K˜�šžœœœ˜Kšœ#˜#Kšœ"˜"Kšœ˜—K˜�šžœœœ!˜?Kšœœ˜Kšœ#˜#šžœœœ˜;Kš
œœœœœ˜?Kšœœ˜K˜—KšœŸ#˜AKšœ5œœŸ˜Sšœ*œ˜2Kšœ˜Kšœ/œœ˜=Kšœ˜Kšœ/œœ˜=Kšœ˜K˜šœ˜Kšœ˜Kšœ/œœ˜=Kšœ˜Kšœ/œœ˜=Kšœ˜K˜——Kšœ˜K˜�—š
ž
œœœ$œœ˜PKš	œœœœŸ˜Ešœœ˜$Kšœ˜Kšœœœœ˜%Kšœ˜Kšœœœœ˜"Kšœ˜Kšœ˜K˜šœ˜Kšœ˜Kšœœœœ˜%Kšœ˜Kšœœœœ˜"Kšœ˜Kšœ˜K˜——Kšœœ˜
Kšœ˜K˜�—š
žœœœœœ˜IKšœ
œ˜Kšœœ˜Kš	œœœ	œŸ˜NKšœ'˜'Kšœ!˜!šœœ˜Kšœ	œ˜*Kšœ	œ#˜/Kšœ
œ˜+Kšœ
œ#˜0Kšœœ	œ˜!—Kšœœ˜K˜K˜�—šž	œœœ˜Kšœ˜Kšœ˜K˜�—šž
œœœ˜Kšœ˜Kšœ˜K˜�—šž
œœœ˜Kšœ!˜!Kšœ!˜!Kšœ˜K˜�—šž
œœœ˜KšœJ˜Jšžœœ˜Kšœ.˜.Kšœ/œœ˜EKšœ˜—šœœœ˜Kšœ.˜.Kšœœ˜/KšŸ™Kšœœ˜3šœ˜Kšœ.˜1—K™�KšŸ™šœ˜Kšœ:˜=—šœ˜Kšœ9˜<K˜�—KšŸ™šœ˜Kšœ6˜9—šœ˜Kšœ5˜8—KšŸ™šœ˜Kšœ:˜=—šœ˜Kšœ9˜<—K˜�K™šœ˜Kšœ:˜=—šœ˜Kšœ;˜>—šœ˜Kšœ4˜7—šœ˜Kšœ5˜8—K™�K™'šœ˜Kšœ3˜6—šœ˜Kšœ2˜5—šœ˜Kšœ9˜<—šœ˜Kšœ8˜;—šœ˜Kšœ9˜<—šœ˜Kšœ:˜=—K˜—K˜K˜—K˜�K™0K˜�šž
œœœœ˜5šœœ˜Kšœ2œœ˜@Kšœœœ˜—K˜—K˜�šžœœœ
˜>šœ˜Kšœœ
¡˜!Kšœœ˜8Kšœœ¡˜:Kšœ
œ
¡˜"Kšœœ¡˜$Kšœœ¡œ˜&Kšœœ¡œ˜6Kšœœ¡œ˜8Kšœœ¡œ˜6Kšœœ¡œ˜4Kšœœ¡˜=Kšœœ¡˜0Kšœœ¡œ˜1Kšœœ¡˜;Kšœœ¡œ˜/Kšœœ¡œ˜+Kšœœ¡œ˜,Kšœœ¡œ˜.Kšœœ¡œ˜*Kšœœ˜—K˜—K˜�šž	œœ œ	œœœ˜UK˜K˜Kš
œœœœœ˜Všœ˜Kšœœ˜0Kšœœ$˜BKšœœ#¡˜DKšœ
œ˜,Kšœœ˜.Kšœœ¡œ˜0Kšœœ!¡œ˜@Kšœœ"¡œ˜BKšœœ!¡œ˜@Kšœœ)˜LKšœœ ˜:Kšœœ¡œ˜;Kšœœ(˜JKšœœ˜8Kšœœ¡œ˜9Kšœœ ¡œ˜>Kšœœ¡œ˜6Kšœœ¡œ˜8Kšœœ˜4Kšœœ˜—K˜—K™�K™K˜�š
ž
œœœœ
œ˜GKšœœ˜9Kšœ˜%Kšœ˜—K˜�š
žœœœœœ˜IKšœœ*˜DKšœ˜%K˜K˜�—šžœœ$œœ˜Jšœ˜Kšœ
¡œ
¡˜Kšœ¡œ¡˜7Kšœ¡œ¡˜-Kšœ¡œ¡˜+Kšœ¡œ¡˜-Kšœ¡œ¡˜!Kšœœ˜—K˜K˜�—šžœœœ
˜?šœ˜Kšœ¡œ¡˜7Kšœ¡œ¡˜-Kšœ¡œ¡˜,Kšœ¡œ¡˜.Kšœ¡œ¡˜!Kšœœ˜—K˜K˜�—K™�—™K™TK˜�Kšœœ˜.Kšœœ˜.K˜�šžœœœ˜-Kšœœ˜!šœ˜Kšœœ˜D—Kšœ˜—K˜�šžœœœ.˜GKšœœœœ˜AKšœ˜—K™�—™K™K˜�Kšœœ˜2Kšœœ˜2K˜�šž
œœœ˜1Kšœœ˜#Kšœœ6˜EKšœ˜—K˜�šžœœœ2˜MKšœ$œœ˜=Kšœ˜——K˜�™K™	K™�Kšœ]™]K˜�šžœœœœœœ˜EKšœœœ˜Kšœœ˜Kšœœ˜šœœ˜šœ˜Kšœ
˜
Kšœœ
˜Kšœ˜K˜—˜šœ˜šœ˜Jšœ$œ˜9—šœ˜Jšœ-œ˜B—šœ˜Jšœ1œ˜F—šœ˜Jšœ-œ˜B—šœ˜JšœJ˜L——Kšœœ˜Jšœ˜J˜—šœ˜K˜�—šœœœ˜'Kšœ3˜9—˜K˜�š˜Kšœ	œ˜&——Kšœ˜—K˜—K™�š
ž	œœœ
œœ˜=šžœœ˜
Kšœ/˜/—K˜K˜K˜�—šž
œœœœ˜6šžœœ˜
Kšœ.˜.—K˜K˜K˜�—š
žœœœ
œœ˜<šžœœ˜Kšœœ%™7Kšœœœ™:Kšœ*˜*K˜—Kšœœœ*˜HK˜K˜—K˜�šž	œœœœ˜5šžœœ˜Kšœœœœ
™BKšœ)˜)K˜—Kšœœœ*˜HK˜K˜K˜�—Kšœ˜šœ'˜'K˜�—šžœœœ˜Kš	œœœœœ˜@šžœœ˜
Kšœ'˜'K˜—K˜šœ
œœœ˜-Kšœ	œ˜)K˜—šœœœ
˜K˜3Kšœœ˜+Kšœ˜—K˜K˜K˜�—šž	œœœœ˜/Kšœœ˜#šžœœ˜
Kšœ4˜4—K˜K˜K˜�—šžœœœœ˜.Kšœœ˜"šžœœ˜Kšœ/˜/K˜—Kšœœœ*˜HK˜K˜K˜�—šž	œœ
œœ˜-Kšœœ˜'Kšœ˜K˜K˜�—šžœœœœ˜FK™MKšœ4˜4Kšœ,˜,Kšœ.˜.Kš
œœœœœŸ˜@Kšœ ˜ šœ˜šœœ˜Kšœ˜Kšœ ˜ K˜šœ˜Kšœ˜Kšœ"˜"K˜——Kšœ"˜"—K˜�Kšœœ ˜*šœ˜	Kšœ
œ"Ÿ˜HKšœ
œ$Ÿ˜Išœœ˜Kšœ'™'Kšœ
œ˜)Kšœ
œ˜)K˜šœ˜Kšœ
œ˜*Kšœ
œ˜)Kšœ˜——K˜—K˜K˜�—šžœœœœ˜GK™IKšœ4˜4Kšœ-˜-Kšœ/˜/Kš
œœœœ
œŸ
˜IKšœ ˜ šœ˜šœœ˜Kšœ˜Kšœ˜K˜šœ˜Kšœ˜Kšœ˜K˜——Kšœ˜—Kšœœ ˜*šœ˜	Kšœ
œ Ÿ˜Fšœœœ˜6Kšœœ˜/—K™šœ˜Kšœ$Ÿ#˜J—šœœœ˜<Kšœœ˜6—K˜—K˜——K˜�™#K˜�K™�Kšœ˜K˜�—J˜�—�…—����Tð��zO��