; BcplGateCP.mu -- Top-level microcode source for Alto Gateway running
;			Bcpl and using CommProc.

;	Last modified September 23, 1978  3:58 PM

#AltoConsts23.mu;


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

!17, 20, Emulator, IntTimerTask, EREST, , , , CommProcTask, , 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 ****

#CPMRT.mu;


; **** CommProc microcode ****

#CommProc1.mu;
#CommProc2.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	SetLineTab
; 64000	PupChecksum
; 65400	ChangeControlReg

!37,40, TrapDispatch, , , , , , SilentBoot, SetLineTab, PupChecksum, , ,
	ChangeControlReg;


; 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


; SetLineTab subroutine:
;	CallRam(#63400, lineTab)
; Specifies the address of the Line Table (LINTAB).

SetLineTab:
	L← AC0, TASK;			LINTAB← AC0
	LINTAB← L, :Emulator;

; ChangeControlReg subroutine:
;	CallRam(#65400, lineTimes4, changeMask)
; Changes (sets or resets) bits in the control word for a line.
; The change is atomic with respect to CommProc task execution.
; lineTimes4: 4 times the line number to be affected.
; changeMask: Bits 4:15 are a mask of bits to be affected and bit 0 is
;	the desired new value of those bits.

ChangeControlReg:
	L← AC0;				lineTimes4
	LINE*4← L;
	T← AC1;				T← changeMask
	L← LCRetX#, :LIMCon0;		L← LIMCon0 return index
LCRetX:	: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