SoftcardOpsImpl.Mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Willie-Sue, February 9, 1987 5:36:26 pm PST
Bill Jackson (bj) February 3, 1987 7:01:49 pm PST
DIRECTORY
Basics USING [SwapHalves],
CrRPC USING [Error, Handle, CreateClientHandle, DestroyClientHandle],
RapunzelP2200V2,
Rope USING [ROPE],
SoftcardOps,
SoftcardPrivate,
XNS USING [Address, unknownSocket],
XNSCH USING [LookupAddressFromRope];
SoftcardOpsImpl: CEDAR PROGRAM
IMPORTS
Basics, CrRPC, 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;
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;
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): BOOLFALSE,
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: ROPENIL] = 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: LONG CARDINAL] =
{ value ← ReadLong[SpyEUDataH] };
ReadIFUPBusData: PUBLIC PROC RETURNS[value: LONG CARDINAL] =
{ value ← ReadLong[SpyEUDataH] };
ReadClock: PUBLIC PROC RETURNS[value: LONG CARDINAL] =
this may be good enough
{ value ← ReadLong[ClockH] };
*************************
ReadEURegsiter: 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 => theBits[resIndex] ← one.peekShort.value;
ENDCASE => NULL;
ENDLOOP;
};
ENDCASE => seqIndex ← seqIndex + 1;
ENDLOOP;
value ← LOOPHOLE[theBits];
TRUSTED { SELECT which FROM
kReg => value ← [kReg [kVal: LOOPHOLE[theBits]]];
field => value ← [field [fVal: LOOPHOLE[theBits]]];
ENDCASE => value ← [regular [rVal: LOOPHOLE[theBits]]];
};
};
WriteEURegsiter: 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] };
TRUSTED { WITH value: value SELECT FROM
kReg => theBits ← LOOPHOLE[value.kVal];
field => theBits ← LOOPHOLE[value.fVal];
regular => theBits ← LOOPHOLE[value.rVal];
ENDCASE;
};
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] = {
the IFU has only one internal state register format tbd
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 => ifuState[resIndex] ← one.peekShort.value;
ENDCASE => NULL;
ENDLOOP;
};
ENDCASE => seqIndex ← seqIndex + 1;
ENDLOOP;
};
WriteIFUInternalState: 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];
};
*************************
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[CarNotResetIFUCache] };
DisableEUCache: PUBLIC PROC =
{ [] ← ReadShort[CarNotResetEUCache] };
FlushIFUCache: PUBLIC PROC =
{ [] ← ReadShort[CarNotResetIFUCache]; [] ← ReadShort[CasNotResetIFUCache] };
FlushEUCache: PUBLIC PROC =
{ [] ← ReadShort[CarNotResetEUCache]; [] ← ReadShort[CasNotResetEUCache] };
DragonHaltOrStep: PUBLIC PROC[phase: SoftcardOps.DragonPhase ← phaseA] =
{ };
DragonRun: PUBLIC PROC =
{ [] ← ReadShort[CarDragonRun+2] };
DragonStop: PUBLIC PROC =
{ [] ← ReadShort[CarDragonRun] };
ResetCounter: PUBLIC PROC =
{ [] ← ReadShort[CarNotResetCounter] };
***** ***** ***** ***** ***** ***** ***** *****
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];
notInterruptDragonToIOP => RETURN[CarNotInterruptDragonToIOP];
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];
notInterruptDragonToIOP => RETURN[control1Bits.notInterruptDragonToIOP];
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
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 + 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: BOOLFALSE] = {
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];
};
ReadLong: PROC[addr: Addr] RETURNS[value: LONG CARDINAL] = {
Rl: PROC = {
swappedVal: LONG CARDINAL = Rapunzel.PeekLong[crHandle, addr];
value ← LOOPHOLE[Basics.SwapHalves[LOOPHOLE[swappedVal]]];
};
CarefullyApply[Rl];
};
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];
psConsultStatus: Rapunzel.PeekShortCmd = [ConsultStatusAddr];
drEU: Rapunzel.PeekShortCmd = [DebugReadEU];
drIFU: Rapunzel.PeekShortCmd = [DebugReadIFU];
seqLen: CARDINAL = IF isEU THEN 5 ELSE 4; -- magic here
rlCmd: Rapunzel.ReturnLengthCmd;
srCmd: Rapunzel.ShftReadCmd;
srCmd.numRepeats ← IF isEU THEN numEUBits ELSE numIFUBits;
rlCmd.returnLength ← IF isEU THEN numEUBits+4 ELSE numIFUBits+3;
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 {
for EU, tSeq[2] sets the euAddr to read
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] = {
construct a CmdSeq using a ShftWriteCmd to write n-bits of internal state
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]];
the bits go in the middle
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.