-- RapunzelServiceImpl.mesa
	-- Copyright (C) 1986 by Xerox Corporation.  All rights reserved.
	-- Bill Jackson (bj) September 22, 1986 6:31:14 pm PDT
	-- Willie-Sue, January 16, 1987 2:48:17 pm PST

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;
	shftAAddr: Rapunzel.Address;
	shftBAddr: Rapunzel.Address;
	

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 (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];
	
	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];
			};
	};
	

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.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;
	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;
				};
			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;
	};
	

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[];

}...