SoftcardOpsImpl.Mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Willie-Sue, October 13, 1986 3:02:58 pm PDT
Bill Jackson (bj) February 3, 1987 7:01:49 pm PST
DIRECTORY
CrRPC USING [Error, Handle, CreateClientHandle, DestroyClientHandle],
DragOpsCross,
DragOpsCrossUtils,
RapunzelP2200V2,
Rope USING [ROPE],
SoftcardOps,
SoftcardPrivate,
XNS USING [Address, unknownSocket],
XNSCH USING [LookupAddressFromRope];
SoftcardOpsImpl:
CEDAR
PROGRAM
IMPORTS CrRPC, DragOpsCrossUtils, RapunzelP2200V2, SoftcardOps, 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; -- tbd
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;
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
read32BitsSeq: Rapunzel.SeqCmd; -- for some eu registers
write32BitsSeq: Rapunzel.SeqCmd;
Error: PUBLIC SIGNAL[code: ATOM, explanation: ROPE ← NIL] = CODE;
EstablishConnection:
PUBLIC
PROC[host:
ROPE]
RETURNS[ok:
BOOL] = {
Ec:
PROC = {
netAddr: XNS.Address ← 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: DragOpsCross.Word] = {
Reup:
PROC =
{ value ← DragOpsCrossUtils.CardToWord[Rapunzel.PeekLong[crHandle, SpyEUDataH] ] };
CarefullyApply[Reup];
};
ReadIFUPBusData:
PUBLIC
PROC
RETURNS[value: DragOpsCross.Word] = {
Rifup:
PROC =
{ value ← DragOpsCrossUtils.CardToWord[Rapunzel.PeekLong[crHandle, SpyEUDataH] ] };
CarefullyApply[Rifup];
};
ReadClock:
PUBLIC
PROC
RETURNS[value:
LONG
CARDINAL] = {
this may be good enough
Rc:
PROC =
{ value ← Rapunzel.PeekLong[crHandle, ClockH] };
CarefullyApply[Rc];
};
*************************
ReadEUInternalRegsiter:
PUBLIC
PROC[which: EUInternal]
RETURNS[value, extra: DragOpsCross.Word] = {
not all the internal registers are 32-bits long
RETURN[DragOpsCross.ZerosWord, DragOpsCross.ZerosWord]
};
WriteEUInternalRegsiter:
PUBLIC
PROC[
which: EUInternal, value, extra: DragOpsCross.Word] = {
not all the internal registers are 32-bits long
};
ReadIFUInternalState:
PUBLIC
PROC
RETURNS[ifuState: IFUInternalState] = {
the IFU has only one internal state register format tbd
Rifui: PROC = {
resultSeq: Rapunzel.SeqResult;
psReadIFU: Rapunzel.PeekShortCmd = [DebugReadIFU];
IF read32BitsSeq = NIL THEN read32BitsSeq ← ConstructReadnBitSeq[32];
TRUSTED { read32BitsSeq[1] ← [peekShort[psReadIFU]] };
resultSeq ← Rapunzel.DoCmds[crHandle, read32BitsSeq];
value ← DragOpsCross.ZerosWord;
don't ask why the following numbers are used - just believe
FOR i: CARDINAL ← 4, i+3 UNTIL i>=resultSeq.length DO
res: Rapunzel.Result = resultSeq.body[i];
WITH res: res SELECT FROM
peekShort => {
read: StatusBits = LOOPHOLE[res.peekShort.value];
value ← DragOpsCrossUtils.SingleWordShiftLeft[value, 1];
value ← DragOpsCrossUtils.AddDelta[read.dOutIFU, value];
};
pokeShort => ERROR;
ENDCASE => ERROR;
ENDLOOP;
};
CarefullyApply[Rifui];
};
WriteIFUInternalState:
PUBLIC
PROC[ifuState: IFUInternalState] = {
the IFU has only one internal state register - format tbd
Wifui: PROC = {
resultSeq: Rapunzel.SeqResult;
psWriteIFU: Rapunzel.PeekShortCmd = [DebugWriteIFU];
inInfo: DebugInfoEntry;
eachBit: Rapunzel.PokeShortCmd;
eachBit.address ← DebugInfo;
IF write32BitsSeq = NIL THEN write32BitsSeq ← ConstructWritenBitSeq[32];
TRUSTED { write32BitsSeq[1+3*32] ← [peekShort[psWriteIFU]] };
don't ask why the following numbers are used - just believe
FOR i: CARDINAL ← 1, i+3 UNTIL i>=write32BitsSeq.length DO
inInfo.debugInIFU ← value[0];
eachBit.value ← LOOPHOLE[inInfo, CARDINAL];
value ← DragOpsCrossUtils.SingleWordShiftLeft[value, 1];
ENDLOOP;
resultSeq ← Rapunzel.DoCmds[crHandle, write32BitsSeq];
};
CarefullyApply[Wifui];
};
*************************
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: 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 = {};
ResetEUCacheStateMachine: PUBLIC PROC = {};
DisableIFUCache:
PUBLIC
PROC =
{ [] ← ReadShort[CarIFUCache] };
DisableEUCache:
PUBLIC
PROC =
{ [] ← ReadShort[CarEUCache] };
FlushIFUCache:
PUBLIC
PROC =
{ [] ← ReadShort[CarIFUCache]; [] ← ReadShort[CasIFUCache] };
FlushEUCache:
PUBLIC
PROC =
{ [] ← ReadShort[CarEUCache]; [] ← ReadShort[CasEUCache] };
DragonHaltOrStep:
PUBLIC
PROC[phase: SoftcardOps.DragonPhase ← phaseA] =
{ };
DragonRun:
PUBLIC
PROC =
{ [] ← ReadShort[CarDragonRun+2] };
ResetCounter:
PUBLIC
PROC =
{ [] ← ReadShort[CarCounter] };
***** ***** ***** ***** ***** ***** ***** *****
IsControl1:
PROC[which: ControlBit]
RETURNS[
BOOL] = {
SELECT which
FROM
iopIntToDragon, mesaIntToDragon => RETURN[FALSE];
ENDCASE => RETURN[TRUE];
};
GetControlResetAddr:
PROC[which: ControlBit]
RETURNS[Addr] = {
SELECT which
FROM
interruptDragonToIOP => RETURN[CarInterrurptDragonToIOP];
interruptDragonToMesa => RETURN[CarInterruptDragonToMesa];
writeParity => RETURN[CarWriteParity];
virtualMemAccessIOP => RETURN[CarVirtualMemAccessIOP];
virtualMemAccessMesa => RETURN[CarVirtualMemAccessMesa];
virtualMemAccessIFU => RETURN[CarVirtualMemAccessIFU];
virtualMemAccessEU => RETURN[CarVirtualMemAccessEU];
ifuBreakpointEnabled => RETURN[CarEnableIFUBkpt];
euBreakpointEnabled => RETURN[CarEnableEUBkpt];
iopIntToDragon => RETURN[CarIOPIntToDragon];
mesaIntToDragon => RETURN[CarMesaIntToDragon];
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
interruptDragonToIOP => RETURN[control1Bits.interrurptDragonToIOP];
interruptDragonToMesa => RETURN[control1Bits.interrurptDragonToMesa];
writeParity => RETURN[control1Bits.writeParity];
virtualMemAccessIOP => RETURN[control1Bits.virtualMemAccessIOP];
virtualMemAccessMesa => RETURN[control1Bits.virtualMemAccessMesa];
virtualMemAccessIFU => RETURN[control1Bits.virtualMemAccessIFU];
virtualMemAccessEU => RETURN[control1Bits.virtualMemAccessEU];
ifuBreakpointEnabled => RETURN[control1Bits.enableIFUBkpt];
euBreakpointEnabled => RETURN[control1Bits.enableEUBkpt];
iopIntToDragon => RETURN[control2Bits.iopIntToDragon];
mesaIntToDragon => RETURN[control2Bits.mesaIntToDragon];
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
periodicIntToDragon => RETURN[all.periodicIntToDragon];
memoryError => RETURN[all.memoryError];
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[CarPeriodicIntToDragon];
memoryError => RETURN[CarMemoryError];
euBkptReached => RETURN[CarEUBrkptReached];
ifuBkptReached => RETURN[CarIFUBrkptReached];
mapError => RETURN[CarMapError];
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 + 2*LONG[index] + 1], MesaMapEntry] ] };
WriteMesaMap:
PUBLIC
PROC[index: MesaMapIndex, value: MesaMapEntry] =
{ WriteShort[MesaMapAddr+2*LONG[index]+1, LOOPHOLE[value, CARDINAL] ] };
*************************
Access to the Dragon Map
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] ] };
*************************
Utilities
CarefullyApply:
PROC[proc:
PROC, nilHandleOK:
BOOL ←
FALSE] = {
cText: ROPE;
BEGIN
ENABLE CrRPC.Error => {
cText ← text;
GOTO error;
};
IF ~nilHandleOK
AND crHandle =
NIL
THEN
SIGNAL SoftcardOps.Error[$noConnection, "open a connection first"];
proc[];
EXITS
error => SIGNAL SoftcardOps.Error[$crRPCError, cText];
END;
};
ReadShort:
PROC[addr: Addr]
RETURNS[value:
CARDINAL] = {
Rs:
PROC =
{ value ← Rapunzel.PeekShort[crHandle, addr] };
CarefullyApply[Rs];
};
WriteShort:
PROC[addr: Addr, value:
CARDINAL] = {
Ws:
PROC =
{ Rapunzel.PokeShort[crHandle, addr, value] };
CarefullyApply[Ws];
};
ConstructReadnBitSeq:
PROC[num:
CARDINAL]
RETURNS[tSeq: Rapunzel.SeqCmd] = {
construct a CmdSeq of PeekShorts to read n-bits of internal state
index: CARDINAL ← 1;
psDragonRun: Rapunzel.PeekShortCmd = [CarDragonRun];
psShiftA: Rapunzel.PeekShortCmd = [DebugShiftA];
psShiftB: Rapunzel.PeekShortCmd = [DebugShiftB];
psConsultStatus: Rapunzel.PeekShortCmd = [ConsultStatusAddr];
tSeq ← NEW[Rapunzel.SeqCmdObject[1+1+3*num]];
TRUSTED {
tSeq[0] ← [peekShort[psDragonRun]]; -- stop the Dragon first
tSeq[1] ← [peekShort[DebugReadIFU/DebugReadEU]]; -- filled in by caller
shift and read 32 bits of an ifu/eu shift register
FOR i:
CARDINAL
IN [0..num)
DO
tSeq[index ← index + 1] ← [peekShort[psShiftA]];
tSeq[index ← index + 1] ← [peekShort[psShiftB]];
tSeq[index ← index + 1] ← [peekShort[psConsultStatus]]; -- read the bit
ENDLOOP;
};
};
ConstructWritenBitSeq:
PROC[num:
CARDINAL]
RETURNS[tSeq: Rapunzel.SeqCmd] = {
construct a CmdSeq of PokeShorts to write n-bits of internal state
index: CARDINAL ← 0;
psDragonRun: Rapunzel.PeekShortCmd = [CarDragonRun];
psShiftA: Rapunzel.PeekShortCmd = [DebugShiftA];
psShiftB: Rapunzel.PeekShortCmd = [DebugShiftB];
tSeq ← NEW[Rapunzel.SeqCmdObject[1+1+3*num]];
TRUSTED {
shift and read 32 bits of an ifu/eu shift register
FOR i:
CARDINAL
IN [0..num)
DO
tSeq[index ← index + 1] ← [peekShort[psShiftA]];
tSeq[index ← index + 1] ← [peekShort[psShiftB]];
index ← index + 1; -- write the bit goes here
ENDLOOP;
tSeq[1+1+3*num-1-1] ← [peekShort[psDragonRun]]; -- stop the Dragon before the write
tSeq[1+1+3*num-1] ← [peekShort[DebugWriteIFU/DebugWriteEU]]; -- filled in by caller
};
};