*-----------------------------------------------------------
Title[Various.mc...June 12, 1982  3:15 PM...Taft];
*-----------------------------------------------------------
%
Miscellaneous subroutines that various emulators may want to use.
Contents, by order of appearance:

	MulSub		unsigned 16-bit by 16-bit multiply
	DivSub		unsigned 32-bit by 16-bit divide
	RequestAUT	request action by Asynchronous Utility Task
	SetDMuxAddress	set DMux address and read muffler
%

* Relative register declarations
	RVRel[XTemp17, 17];
	RVRel[XTemp17, 17];
	RVRel[XTemp16, 16];

DontKnowRBase;

*-----------------------------------------------------------
MulSub: *   unsigned 16-bit by 16-bit multiply
* Entry conditions:
*	T = multiplicand
*	Q = multiplier
* Exit conditions:
*	T = high-order 16 bits of product
*	Q = low-order 16 bits of product
* Clobbers XTemp17
*-----------------------------------------------------------
Subroutine;

	XTemp17← Q;
	XTemp17, Cnt← 16S, Branch[.+2, R odd];
	XTemp17← A0, Multiply, Branch[M0];
	XTemp17← A0, Multiply, Branch[M1];

*-----------------------------------------------------------
DispTable[4];

* here after Q[14] was 0 (no add) and continue
M0:	XTemp17← (A← XTemp17), Multiply, DblBranch[M0E, M0, Cnt=0&-1];
* here after Q[14] was 0 (no add) and exit
M0E:	XTemp17← (A← XTemp17), Multiply, Branch[MXIT0];

* here after Q[14] was 1 (add) and continue
M1:	XTemp17← (XTemp17)+T, Multiply, DblBranch[M0E, M0, Cnt=0&-1];
* here after Q[14] was 1 (add) and exit
	XTemp17← (XTemp17)+T, Multiply, Branch[MXIT0];
*-----------------------------------------------------------

* Must squash pending Multiply dispatches before returning.
MXIT0:	T← XTemp17, DispTable[1, 2, 2];
	Return, DispTable[1, 2, 2];

*-----------------------------------------------------------
DivSub: * unsigned 32-bit by 16-bit divide
* Entry conditions:
*	T,,Q = dividend
*	XTemp17 = divisor
* Call by: SCall[DivSub]
* Exit conditions:
*	+1 return: normal: T=remainder, Q=quotient 
*	+2 return: divide check: T=trap code
* Clobbers XTemp16
*-----------------------------------------------------------
Subroutine;

	PD← T-(XTemp17);		* Trap if T >= XTemp17 (unsigned)
	PD← XTemp17, Branch[DivTrap, Carry];
	Cnt← 17S, PD← T, Branch[Dneg, ALU<0];
	T← T-(XTemp17), Divide, DblBranch[NormalExit, D3, Cnt=0&-1];
D2:
	T← T+(XTemp17), Divide, Branch[NormalExit, Cnt=0&-1];
D3:
	Branch[D2, Carry'];
	T← T-(XTemp17), Divide, Branch[D3, Cnt#0&-1];
NormalExit:
	Branch[DaddLabel, Carry'];
	T-(XTemp17), Divide;
	T← T-(XTemp17), DblBranch[FinalAdd, OKExit, ALU<0];
DaddLabel:
	T+(XTemp17), Divide;
	T← T+(XTemp17), Branch[FinalAdd, ALU<0];
OKExit:
	Return;
FinalAdd:
	T← T+(XTemp17), Return;
Dneg:
	XTemp16← T+T, Branch[Dneg1, ALU<0];
Dneg0:
	T← A← T, Divide, Branch[Fudge2, Cnt=0&-1];
	XTemp16← T+T, DblBranch[Dneg1, Dneg0, R<0];
Dneg1:
	T← T-(XTemp17), Divide, Branch[Fudge3, Cnt=0&-1];
Dneg3:
	PD← T, Branch[.+2, Carry'];
	XTemp16← T+T, DblBranch[Dneg1, Dneg0, ALU<0];
	T← T+(XTemp17), Divide, Branch[Fudge4, Cnt=0&-1];
DnegG:
	PD← T, Branch[.+2, ALU>=0];
	T← T-(XTemp17), CDivide, DblBranch[Fudge4, DnegG, Cnt=0&-1];
	XTemp16← T+T, DblBranch[Dneg1, Dneg0, ALU<0];
Fudge2:
	PD← T-(XTemp17);
Fudge21:
	Branch[F23, Carry];
F22:
	PD← A← T, Divide, Return;
F23:
	PD← T-(XTemp17), Divide, Branch[Fudge42];
Fudge3:
	PD← T-(XTemp17), Branch[Fudge21, Carry];
	PD← A← T, CDivide, Branch[FinalAdd];
Fudge4:
	PD← T-(XTemp17), Branch[.+2, ALU<0];
	DblBranch[F23, F22, Carry];
	PD← T-(XTemp17), CDivide;
Fudge42:
	T← T-(XTemp17), Return;

DivTrap:
	T← 14S, Branch[.+2, ALU#0];	* Carry← 0
	Return[Carry'];			* Mesa sZeroDivisor (=14B), return +2
	T← T+1, Return[Carry'];		* Mesa sDivideCheck (=15B), return +2

*-----------------------------------------------------------
RequestAUT:
* Request action by Asynchronous Utility Task.
* Entry: T = desired starting PC
* Exit:	T = ALU = 0 if failed to submit request because one was
*		already pending; # 0 if succeeded.
*	RBase clobbered.
* Note: the code beginning at the specified PC will execute as AUT,
* and should finish by branching to AUTStart.  The state of task-specific
* registers is undefined at start and finish.
* Note: RequestAUT will never fail when called by the Emulator, assuming
* all emulator calls are with TaskingOn.
*-----------------------------------------------------------
Subroutine;

	RBase← RBase[AUTPC];
	AUTPC← (AUTPC) OR (100000C), Branch[.+2, R>=0]; * Test and set flag

* AUT request already pending.  Return with ALU=0.
	T← A0, Return;

* AUT is free, and we have now locked out further requests.
* Set the desired starting PC, awaken the task, and return with ALU#0.
* Note that AUTPC = 100000 here.
	AUTPC← T← T OR (AUTPC), Wakeup[AUT], Return;


*-----------------------------------------------------------
* The AUT code itself.
* AUTPC = 0 => no request is pending.
* AUTPC = 100000 + starting PC => request is pending.
*-----------------------------------------------------------
Subroutine;
DontKnowRBase;
Set[XTask, IP[AUT]];

AUTInitPC:
	AUTPC← A0;			* Task initialization
AUTDispatch:
	T← AUT, CoReturn;

TopLevel;

* Microcode routines started by AUT finish by branching here, or by returning.
* AUTPC[0]=1 => new request is pending.
AUTStart:
	RBase← RBase[AUTPC];
	T← AUTPC← A0, Link← AUTPC, Branch[AUTDispatch, R<0];
	TIOA← T, Block, Branch[AUTStart]; * Nothing to do


*-----------------------------------------------------------
SetDMuxAddress:	* Load DMux address and read muffler.
* Enter: T[4:15] = DMux address
* Exit:	T[0] = XTemp17[0] = muffler data
* Clobbers T and XTemp17.
*-----------------------------------------------------------
Subroutine;

	XTemp17← 13C;
SetDLp:	T← T+(MidasStrobe← T);		* Shift address bit from B[4]
	XTemp17← NOT (XTemp17), Branch[., R>=0]; * Delay 2 cycles
	XTemp17← (XTemp17)-1, Branch[SetDLp, ALU#0];
	T← XTemp17← ALUFMem, Return;