SoftcardOpsImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Willie-Sue, October 13, 1986 3:02:58 pm PDT
DIRECTORY
CrRPC USING [Error, Handle, CreateClientHandle, DestroyClientHandle],
HostNickNameTable USING [LookUp],
DragOpsCross,
DragOpsCrossUtils,
RapunzelP2200V1,
Rope USING [ROPE],
SoftcardOps,
SoftcardPrivate,
XNS USING [unknownSocket],
XNSName USING [Address, AddressFromRope];
SoftcardOpsImpl: CEDAR PROGRAM
IMPORTS
CrRPC, DragOpsCrossUtils, HostNickNameTable,
Rapunzel: RapunzelP2200V1,
XNSName,
SoftcardOps
EXPORTS SoftcardOps
= BEGIN OPEN SoftcardPrivate;
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): BOOLFALSE,
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: ROPENIL] = CODE;
EstablishConnection: PUBLIC PROC[host: ROPE] RETURNS[ok: BOOL] = {
Ec: PROC = {
netAddr: ROPE = HostNickNameTable.LookUp[host];
socket: XNSName.Address = XNSName.AddressFromRope[netAddr, XNS.unknownSocket];
crHandle ← CrRPC.CreateClientHandle[$SPP, socket, 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];
};
*************************
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[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: 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];
};
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[indexindex + 1] ← [peekShort[psShiftA]];
tSeq[indexindex + 1] ← [peekShort[psShiftB]];
tSeq[indexindex + 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[indexindex + 1] ← [peekShort[psShiftA]];
tSeq[indexindex + 1] ← [peekShort[psShiftB]];
indexindex + 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
};
};
***********************************
END.