; BcplEmuEIA.mu -- Top-level microcode source for Alto EIA driver--
;			this version does EIA processing in the Emulator task

;	Last modified September 23, 1978  4:18 PM

#AltoConsts23.mu;


; Reset locations of the tasks to be started in the Ram (Emulator, MRT,
; and one extra Ethernet).  Extra Ethernet is assumed to be run by task 2.

!17, 20, Emulator, , EREST, , , , , , MRT;



; Ram entry point for fielding undefined opcodes.

!37, 1, TRAP1;



; Reserve 774-1003 for Ram Utility Area.

%7, 1777, 774, RU774, RU775, RU776, RU777, RU1000, RU1001, RU1002, RU1003;

; For the moment, just throw these locations away.  This is done only
; to squelch the "unused predef" warnings that would otherwise occur.
; If we ever run short of Ram, assign these to real instructions somewhere
; in microcode executed only by the Emulator.

RU774:	NOP;
RU775:	NOP;
RU776:	NOP;
RU777:	NOP;
RU1000:	NOP;
RU1001:	NOP;
RU1002:	NOP;
RU1003:	NOP;


; **** Modified Memory Refresh Task ****

#EmuEIAMRT.mu;


; **** EIA microcode ****

#AltoEIA1.mu;
#AltoEIA2.mu;


; **** Extra Ethernet microcode ****

$ECNTR	$R11;		Same as CLOCKTEMP, which has been abolished
$EPNTR	$R14;		Not used by Nova emulator

#ExtraEther1.mu;


; Nova emulator conventions

$START	$L 4020, 0, 0;		Emulator entry point

$AC0	$R3;
$AC1	$R2;
$AC2	$R1;
$AC3	$R0;
$XREG	$R7;

; **** Emulator Task ****
; Degenerate -- just returns control to emulator in Rom0 (for silent boot).

Emulator:
	SWMODE;				Switch to Rom1
	:START;				Nova emulator entry point


; Trap handler and dispatcher for instructions that trap into
; the RAM.  In the following predefinition, the tags correspond
; to opcodes 60000, 60400, 61000, 61400, ... 77400.
; Note that opcodes 60000, 60400, 61000, 64400, 65000, 67000, and 77400
; cannot be used since control never gets to the RAM for these.

; 61400, 62000, and 62400 are reserved for the Bcpl Runtime package,
; should it ever be included.

; 63000	SilentBoot
; 63400	EnableEIA
; 64000	PupChecksum
; 65400	ProcessEIA

!37,40, TrapDispatch, , , , , , SilentBoot, EnableEIA, PupChecksum, , ,
	ProcessEIA;


; Control comes here with the instruction LCY 8 in XREG
TRAP1:	T← 37;
	L← XREG AND T;
TrapDispatch:
	SINK← M, BUS, TASK;
	:TrapDispatch;


; Microcode subroutines are defined and called from Bcpl programs
; by loading arguments into AC0, AC1, and AC3 and executing the
; appropriate trap opcode.  The return value, if any, is in AC0.

; A Bcpl-callable subroutine is available to do this (in CallRam.asm):
;	result = CallRam(opcode, ac0, ac1, ac3)


; SilentBoot subroutine:
;	CallRam(#63000, bootLocusVector)
; Sets the Boot Locus Vector and does a silent boot.

SilentBoot:
	RMR← AC0;			Set BLV from arg
	SINK← 100000, STARTF, :Emulator;  Boot the machine, resume emulator


; EnableEIA subroutine:
;	CallRam(#63400, lineTab)
; If lineTab is nonzero, specifies the address of the Line Table (LINTAB)
; and enables the EIA microcode.
; If lineTab is zero, disables the EIA microcode.

!1, 2, EIAOn, EIAOff;

EnableEIA:
	L← AC0;				Get arg
	LINTAB← L, SH=0;		Set LINTAB, test for zero
EIAExit: T← 1, :EIAOn;			[EIAOn, EIAOff]
EIAOn:	L← R37 OR T, TASK, :UpdR37;	Nonzero, turn on R37[15]
EIAOff:	L← R37 AND NOT T, TASK;		Zero, turn off R37[15]
UpdR37:	R37← L, :Emulator;		Update R37, resume emulator

; PupChecksum subroutine:
;	result = CallRam(#64000, 0, address, count)
; AC0: 0 initially
; AC1: address of block
; AC3: length of block (words)
; Computes the ones-complement add-and-cycle checksum over the block.
; This instruction is interruptible.  If an interrupt occurs, intermediate
; state is stored in the ACs and the PC is backed up so the instruction will
; start over when the interrupt is dismissed.
; Timing: 9 cycles/word
; 2484 cycles (= 422 microseconds) per maximum-length Pup

$AC3	$R0;
$AC1	$R2;
$AC0	$R3;
$NWW	$R4;
$PC	$R6;

!1,2,PCMayI,PCNoI;
!1,2,PCDoI,PCDisI;
!1,2,PCNoCy,PCCy;
!1,2,PCLoop,PCDone;
!1,2,PCNoMZ,PCMinZ;

PupChecksum:
	MAR← L← AC1, :PCLp1;		Start fetch of first word

; Top of main loop
PCLoop:	MAR← L← AC1+1;			Start fetch of next word
PCLp1:	AC1← L;				Update pointer
	L← NWW, BUS=0;			Test for interrupts
	T← AC0, SH<0, :PCMayI;		[PCMayI, PCNoI] Get partial sum
PCNoI:	L← MD+T, :PCDisI;		Add new word
PCDisI:	T← M, ALUCY;			Test for carry out
	L← AC3-1, :PCNoCy;		[PCNoCy, PCCy] Decrement count
PCNoCy:	AC3← L, L← T, SH=0, TASK, :PCLast;  No carry
PCCy:	AC3← L, L← T← 0+T+1, SH=0, TASK;  Do end-around carry
PCLast:	AC0← L MLSH 1, :PCLoop;	[PCLoop, PCDone] Left cycle 1

; Here when done
PCDone:	L← AC0+1;			Test for minus zero (ones-complement)
	L← PC, SH=0;
PCDn1:	PC← L, L← 0, TASK, :PCNoMZ;	[PCNoMZ, PCMinZ]
PCNoMZ:	:Emulator;
PCMinZ:	AC0← L, :Emulator;		Minus zero, change to plus zero

; Here when have potential interrupt;  branch pending on disable bit.
PCMayI:	L← MD+T, :PCDoI;		[PCDoI, PCDisI]
PCDoI:	L← PC-1, :PCDn1;		Back up PC


; ProcessEIA instruction.
; Executed as the only instruction of the interrupt routine invoked
; by MRT when it finds that EIA processing is required.

ProcessEIA:
	L← R37, :CheckEIA;		CheckEIA does R37← L

; CheckEIA goes to EIAExit (above) when done.
; EIAExit turns MRT polling back on.