-- RapunzelServiceImpl.mesa
	-- Copyright (C) 1986 by Xerox Corporation.  All rights reserved.
	-- Bill Jackson (bj) September 22, 1986 6:31:14 pm PDT
	-- Willie-Sue, September 23, 1986 11:03:56 am PDT

DIRECTORY
	ESCAlpha USING [alpha],
	Heap USING [systemZone],
	Inline USING [HighHalf, LowHalf, LongNumber],
	Mopcodes USING [zESC],
	Put USING [LongNumber, Text],
	System USING [NetworkAddress],
	Rapunzel;

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;
	
-- Global State
	
	mem: Mem;
	nilHandle: BindHandle;
	simulation: BOOLEAN ← TRUE;
	debugging: BOOLEAN ← TRUE;
	

Fault: PUBLIC ERROR [bH: BindHandle, code: Rapunzel.FaultCode, address: Rapunzel.Address] = CODE;
	

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 (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];
	
	IF (simulation)
		THEN {
			IF NOT (phys IN [lowerBound..upperBound])
				THEN ERROR Fault[bH, nonexistent, addr];
			word ← mem[phys];
			}
		ELSE {
			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];
	
	IF (simulation)
		THEN {
			IF NOT (phys IN [lowerBound..upperBound])
				THEN ERROR Fault[bH, nonexistent, addr];
			mem[phys] ← word;
			}
		ELSE {
			IF NOT (addr IN [lowestGuarded..lastPhysical])
				THEN ERROR Fault[bH, IF (addr < lowestGuarded) THEN protection ELSE nonexistent, addr];
			MemSmash[addr, word];
			};
	};
	

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.low ← PeekOpCode[bH, address];
	xx.high ← 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.LowHalf[value]];
	PokeOpCode[bH, (address+1), Inline.HighHalf[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;
	};
	
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 = zone.NEW [Chunk[cmdSeq↑.LENGTH]];
	resultSeq ← zone.NEW [Rapunzel.SeqResult ← DESCRIPTOR[chunk, cmdSeq↑.LENGTH]];
	
	Display["DoCmds -- count: ", cmdSeq↑.LENGTH];
	FOR i: CARDINAL IN [0..cmdSeq↑.LENGTH) DO
		this: Rapunzel.Cmd = cmdSeq[i];
		WITH this: this SELECT FROM
			peekShort => {
				address: Rapunzel.Address = this.peekShort.address;
				res: Rapunzel.PeekShortResult ← NULL;
				Display["	address: ", address];
				res ← [PeekOpCode[bH, address]];
				Display["	peekShort: ", res];
				resultSeq[i] ← [peekShort[res]];
				};
			pokeShort => {
				address: Rapunzel.Address = this.pokeShort.address;
				res: pokeShort Rapunzel.Result = NULL;
				Display["	address: ", address];
				Display["	pokeShort: ", this.pokeShort.value];
				PokeOpCode[bH, address, this.pokeShort.value];
				resultSeq[i] ← res;
				};
			ENDCASE => ERROR Fault[bH, nonexistent, 0];
		ENDLOOP;
	};
	

FreePeekSeqShortResults: PUBLIC PROC [bH: BindHandle, resultSeq: LONG POINTER TO SeqShort] = {
	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[];

}...