RapunzelServiceImpl:
PROGRAM
IMPORTS Heap, Inline, Put, Rapunzel
EXPORTS Rapunzel = {
OPEN Rapunzel;
Types & Magic #'s
pMemFetch: ESCAlpha.alpha = 3EH;
pMemSmash: ESCAlpha.alpha = 3FH;
firstPhysical: Rapunzel.Address = 0;
lowestGuarded: Rapunzel.Address = (LONG[12]*256*256); -- 1.5MB
lastPhysical: Rapunzel.Address = ((
LONG[32]*256*256)-1);
-- 2^(5+8+8) words = 4MB
lowerBound: CARDINAL = 0;
upperBound:
CARDINAL = 1023;
Mem: TYPE = ARRAY [lowerBound..upperBound] OF WORD;
memMod: CARDINAL = 1024;
Global State
mem: Mem;
nilHandle: BindHandle;
simulation: BOOLEAN ← FALSE;
historyBuffer: BOOLEAN ← FALSE;
debugging: BOOLEAN ← FALSE;
shftAAddr: Rapunzel.Address;
shftBAddr: Rapunzel.Address;
Fault:
PUBLIC
ERROR [ bH: BindHandle, code: Rapunzel.FaultCode, address: Rapunzel.Address ] =
CODE;
HistoryBufferFetch:
PROC [ p:
LONG
CARDINAL ]
RETURNS [ b:
WORD ] =
MACHINE
CODE {
b ← IOPOps.GetByte[p ! IOPOps.Error => { Fault[bH, xx, xx] } ];
};
HistoryBufferSmash:
PROC [ p:
LONG
CARDINAL, b:
WORD ] =
MACHINE
CODE {
IOPOps.PutByte[p, b ! IOPOps.Error => { Fault[bH, xx, xx] } ];
};
MemFetch:
PROC [
LONG
CARDINAL ]
RETURNS [
WORD ] =
MACHINE
CODE {
Mopcodes.zESC, pMemFetch
};
MemSmash:
PROC [
LONG
CARDINAL,
WORD ] =
MACHINE
CODE {
Mopcodes.zESC, pMemSmash
};
Display:
PROC [ lead:
LONG
STRING, value:
LONG
CARDINAL ] = {
IF ( NOT debugging ) THEN RETURN;
Put.Text[NIL, lead];
Put.LongNumber[NIL, value, [base: 8]];
Put.Text[NIL, "B\n"];
};
PeekOpCode:
PROC [
bH: BindHandle, addr:
LONG
CARDINAL ]
RETURNS [
word:
WORD ] =
INLINE {
phys: CARDINAL = Inline.LowHalf[addr];
SELECT TRUE FROM
( simulation ) => {
IF NOT (phys IN [lowerBound..upperBound]) THEN ERROR Fault[bH, nonexistent, addr];
word ← mem[phys MOD memMod];
}
( historyBuffer ) => {
word ← HistoryBufferFetch[addr];
}
ENDCASE => {
IF
NOT ( addr
IN [lowestGuarded..lastPhysical] )
THEN ERROR Fault[bH, IF ( addr < lowestGuarded )
THEN protection ELSE nonexistent, addr];
word ← MemFetch[addr];
};
};
PokeOpCode:
PROC [ bH: BindHandle, addr:
LONG
CARDINAL, word:
WORD ] =
INLINE {
phys: CARDINAL = Inline.LowHalf[addr];
SELECT TRUE FROM
( simulation ) => {
IF NOT (phys IN [lowerBound..upperBound]) THEN ERROR Fault[bH, nonexistent, addr];
mem[phys MOD memMod] ← word;
}
( historyBuffer ) => {
HistoryBufferSmash[addr, word];
}
ENDCASE => {
IF
NOT ( addr
IN [lowestGuarded..lastPhysical] )
THEN ERROR Fault[bH, IF ( addr < lowestGuarded )
THEN protection ELSE nonexistent, addr];
MemSmash[addr, word];
};
};
SetShftAddrs:
PUBLIC
PROC [ bH: BindHandle, shftA, shftB: Rapunzel.Address ] = {
shftAAddr ← shftA;
shftBAddr ← shftB;
};
PeekShort:
PUBLIC
PROC [ bH: BindHandle, address: Rapunzel.Address ]
RETURNS [ result: Rapunzel.Short ] = {
Display["PeekShort - address: ", address];
result ← PeekOpCode[bH, address];
Display[" result: ", result];
};
PokeShort:
PUBLIC
PROC [ bH: BindHandle, address: Rapunzel.Address, value: Rapunzel.Short ] = {
Display["PokeShort - address: ", address];
Display[" value: ", value];
PokeOpCode[bH, address, value];
};
PeekLong:
PUBLIC
PROC [ bH: BindHandle, address: Rapunzel.Address ]
RETURNS [ result: Rapunzel.Long ] = {
xx: Inline.LongNumber;
Display["PeekLong - address: ", address];
xx.high ← PeekOpCode[bH, address];
xx.low ← PeekOpCode[bH, (address+1)];
result ← xx.lc;
Display[" result: ", result];
};
PokeLong:
PUBLIC
PROC [ bH: BindHandle, address: Rapunzel.Address, value: Rapunzel.Long ] = {
Display["PokeLong - address: ", address];
Display[" value: ", value];
PokeOpCode[bH, address, Inline.HighHalf[value]];
PokeOpCode[bH, (address+1), Inline.LowHalf[value]];
};
PeekSeqShort:
PUBLIC
PROC [ bH: BindHandle, address: Rapunzel.Address, count:
CARDINAL ]
RETURNS [ results: LONG POINTER TO Rapunzel.SeqShort ] = {
Chunk: TYPE = RECORD [ SEQUENCE COMPUTED Rapunzel.SeqShortIndex OF Rapunzel.Short ];
zone: UNCOUNTED ZONE = Heap.systemZone;
chunk: LONG POINTER = zone.NEW [Chunk[count]];
Display["PeekSeqShort - address: ", address];
Display[" count: ", count];
results ← zone.NEW [Rapunzel.SeqShort ← DESCRIPTOR[chunk, count]];
FOR i:
CARDINAL
IN [0..count)
DO
results[i] ← PeekOpCode[bH, (address+i)];
Display[" ", results[i]];
ENDLOOP;
};
PeekSeqLong:
PUBLIC
PROC [ bH: BindHandle, address: Rapunzel.Address, count:
CARDINAL ]
RETURNS [ results: LONG POINTER TO Rapunzel.SeqLong ] = {
Chunk: TYPE = RECORD [ SEQUENCE COMPUTED Rapunzel.SeqShortIndex OF Rapunzel.Long ];
zone: UNCOUNTED ZONE = Heap.systemZone;
chunk: LONG POINTER = zone.NEW [Chunk[count]];
Display["PeekSeqLong - address: ", address];
Display[" count: ", count];
results ← zone.NEW [Rapunzel.SeqLong ← DESCRIPTOR[chunk, count]];
FOR i:
CARDINAL
IN [0..count)
DO
xx: Inline.LongNumber;
xx.high ← PeekOpCode[bH, address+2*i];
xx.low ← PeekOpCode[bH, (address+2*i+1)];
results[i] ← xx.lc;
Display[" ", results[i]];
ENDLOOP;
};
PokeSeqShort:
PUBLIC
PROC [
bH: BindHandle, address: Rapunzel.Address, valueSeq:
LONG
POINTER
TO Rapunzel.SeqShort
] = {
Display["PokeSeqShort - address: ", address];
Display[" count: ", LENGTH[valueSeq^]];
FOR i:
CARDINAL
IN [0..
LENGTH[valueSeq^])
DO
Display[" ", valueSeq[i]];
PokeOpCode[bH, (address+i), valueSeq[i]];
ENDLOOP;
};
DoCmds:
PUBLIC
PROC [ bH: BindHandle, cmdSeq:
LONG
POINTER
TO Rapunzel.SeqCmd ]
RETURNS [ resultSeq: LONG POINTER TO Rapunzel.SeqResult ] = {
Chunk: TYPE = RECORD [SEQUENCE COMPUTED Rapunzel.SeqResultIndex OF Rapunzel.Result];
zone: UNCOUNTED ZONE = Heap.systemZone;
chunk: LONG POINTER;
resLength: CARDINAL;
resIndex: CARDINAL ← 0;
cmdIndex: CARDINAL ← 0;
BEGIN
this: Rapunzel.Cmd = cmdSeq[0];
WITH this: this
SELECT
FROM
returnLength => resLength ← this.returnLength.returnLength * SIZE[Rapunzel.Result];
returnLength => resLength ← this.returnLength.returnLength;
ENDCASE => resLength ← cmdSeq^.LENGTH;
END;
chunk ← zone.NEW [Chunk[resLength]];
resultSeq ← zone.NEW [Rapunzel.SeqResult ← DESCRIPTOR[chunk, resLength]];
Display["DoCmds -- count: ", cmdSeq^.LENGTH];
WHILE
( cmdIndex < cmdSeq^.
LENGTH )
DO
this: Rapunzel.Cmd = cmdSeq[cmdIndex];
cmdIndex ← cmdIndex + 1;
WITH this: this
SELECT
FROM
peekShort => {
address: Rapunzel.Address = this.peekShort.address;
res: Rapunzel.PeekShortResult ¬ NULL;
res ← [PeekOpCode[bH, address]];
IF ( debugging )
THEN {
Display[" address: ", address];
Display[" peekShort: ", res];
};
resultSeq[resIndex] ← [peekShort[res]];
resIndex ← resIndex + 1;
};
pokeShort => {
address: Rapunzel.Address = this.pokeShort.address;
res: Rapunzel.PokeShortResult ¬ NULL;
IF ( debugging )
THEN {
Display[" address: ", address];
Display[" pokeShort: ", this.pokeShort.value];
};
PokeOpCode[bH, address, this.pokeShort.value];
resultSeq[resIndex] ← [pokeShort[NULL]];
resIndex ← resIndex + 1;
};
pokeLong => {
address: Rapunzel.Address = this.pokeLong.address;
res: Rapunzel.PokeShortResult ¬ NULL;
IF ( debugging )
THEN {
Display[" address: ", address];
Display[" pokeShort: ", this.pokeLong.value];
};
PokeOpCode[bH, address, Inline.HighHalf[this.pokeLong.value]];
PokeOpCode[bH, address+1, Inline.LowHalf[this.pokeLong.value]];
resultSeq[resIndex] ← [pokeLong[NULL]];
resIndex ← resIndex + 1;
};
shftRead => {
address: Rapunzel.Address = this.shftRead.address;
numRepeats: Rapunzel.Short = this.shftRead.numRepeats;
res: Rapunzel.ShftReadResult = [numRepeats];
IF ( debugging )
THEN {
Display[" address: ", address];
Display[" shiftRead - numRepeats: ", numRepeats];
};
resultSeq[resIndex] ← [shftRead[res]];
resIndex ← resIndex + 1;
FOR j:
CARDINAL
IN [0..numRepeats)
DO
res: Rapunzel.PeekShortResult ¬ NULL;
[] ← PeekOpCode[bH, shftAAddr];
[] ← PeekOpCode[bH, shftBAddr];
res ← [PeekOpCode[bH, address]];
resultSeq[resIndex] ← [peekShort[res]];
resIndex ← resIndex + 1;
ENDLOOP;
};
shftWrite => {
address: Rapunzel.Address = this.shftWrite.address;
numRepeats: Rapunzel.Short = this.shftWrite.numRepeats;
res: Rapunzel.ShftWriteResult = [numRepeats];
IF ( debugging )
THEN {
Display[" address: ", address];
Display[" shiftWrite - numRepeats: ", numRepeats];
};
resultSeq[resIndex] ← [shftWrite[res]];
resIndex ← resIndex + 1;
FOR j:
CARDINAL
IN [0..numRepeats)
DO
writeVal: Rapunzel.Cmd = cmdSeq[cmdIndex];
cmdIndex ← cmdIndex + 1;
WITH writeVal: writeVal
SELECT
FROM
pokeShort => {
PokeOpCode[bH, address, writeVal.pokeShort.value];
[] ← PeekOpCode[bH, shftAAddr];
[] ← PeekOpCode[bH, shftBAddr];
};
ENDCASE => ERROR Fault[bH, nonexistent, 0];
ENDLOOP;
};
returnLength => NULL;
ENDCASE => ERROR Fault[bH, nonexistent, 0];
ENDLOOP;
};
WriteSequential:
PUBLIC
PROC [ bH: BindHandle, startingAddress: Address, count:
CARDINAL, seq:
LONG
POINTER
TO Rapunzel.SeqLong ] = {
FOR i:
CARDINAL
IN [0..count)
DO
address: Rapunzel.Address = startingAddress + 2*i;
value: Long = seq[i];
PokeOpCode[bH, address, Inline.HighHalf[value]];
PokeOpCode[bH, address+1, Inline.LowHalf[value]];
ENDLOOP;
};
FreePeekSeqShortResults:
PUBLIC
PROC [ bH: BindHandle, resultSeq:
LONG
POINTER
TO SeqShort ] = {
zone: UNCOUNTED ZONE = Heap.systemZone;
zone.FREE [@(resultSeq^.BASE)];
zone.FREE [@(resultSeq)];
};
FreePeekSeqLongResults:
PUBLIC
PROC [ bH: BindHandle, resultSeq:
LONG
POINTER
TO SeqLong ] = {
zone: UNCOUNTED ZONE = Heap.systemZone;
zone.FREE [@(resultSeq^.BASE)];
zone.FREE [@(resultSeq)];
};
FreeDoCmdsResults:
PUBLIC
PROC [ bH: BindHandle, resultSeq:
LONG
POINTER
TO SeqResult ] = {
zone: UNCOUNTED ZONE = Heap.systemZone;
zone.FREE [@(resultSeq^.BASE)];
zone.FREE [@(resultSeq)];
};
Init:
PROC = {
trash: System.NetworkAddress ← TRASH;
mem ← ALL[0];
nilHandle ← Rapunzel.RemoteBind[trash, NIL];
IF ( nilHandle # NIL ) THEN ERROR;
};
Shutdown:
PROC = {
nilHandle ← Rapunzel.RemoteUnbind[nilHandle];
IF ( nilHandle # NIL ) THEN ERROR;
};
Init[];
}.