;-----------------------------------------------------------------
; MesaXRAM.Mu - Overflow XMesa microcode from ROM1
; Last modified by Levin - February 27, 1979  5:41 PM
;-----------------------------------------------------------------

; Separate assembly requires...

#MesabROM.mu;

;-----------------------------------------------------------------
; Entry Point Definitions:
;
;  The definitions below must correspond to those in MesabROM.
;-----------------------------------------------------------------


%1,1777,402,BLTintpend,BLTloop;					BLTloop must match ramBLTloop
%1,1777,404,BLTnoint,BLTint;					BLTint must match ramBLTint

%1,1777,410,Overflow;						must correspond to ramOverflow

!7,10,RR,BLTL,WR,,DADD,DSUB,DCOMP,DUCOMP;			dispatched in ROM

;-----------------------------------------------------------------
; D o u b l e - P r e c i s i o n   A r i t h m e t i c
;-----------------------------------------------------------------

; !1,1,DSUBsub;							shake B/A dispatch
!3,4,DAStail,,,DCOMPr;						returns from DSUBsub
!1,1,Dsetstkp;							shake ALUCY dispatch
!1,1,Setstkp;							shake IDISP from BLTnoint

Overflow:	:RR;						dispatch pending
;								TASK pending for doubles

;-----------------------------------------------------------------
; DADD - add two double-word quantities, assuming:
;	stack contains precisely 4 elements
;-----------------------------------------------------------------
; !1,1,DADDx;							shake B/A dispatch
!1,2,DADDnocarry,DADDcarry;

DADD:		T←stk2, :DADDx;					T:low bits of right operand
DADDx:		L←stk0+T;					L:low half of sum
		stk0←L, ALUCY;					stash, test carry
		T←stk3, :DADDnocarry;				T:high bits of right operand

DADDnocarry:	L←stk1+T, :DASCtail;				L:high half of sum
DADDcarry:	L←stk1+T+1, :DASCtail;				L:high half of sum


;-----------------------------------------------------------------
; DSUB - subtract two double-word quantities, assuming:
;	stack contains precisely 4 elements
;-----------------------------------------------------------------

DSUB:		IR←msr0, :DSUBsub;


;-----------------------------------------------------------------
; Double-precision subtract subroutine
;-----------------------------------------------------------------
!1,2,DSUBborrow,DSUBnoborrow;
!7,1,DSUBx;							shake IR← dispatch

DSUBsub:	T←stk2, :DSUBx;					T:low bits of right operand
DSUBx:		L←stk0-T;					L:low half of difference
		stk0←L, ALUCY;					borrow = ~carry
		T←stk3, :DSUBborrow;				T:high bits of right operand

DSUBborrow:	L←stk1-T-1, IDISP, :DASCtail;			L:high half of difference
DSUBnoborrow:	L←stk1-T, IDISP, :DASCtail;			L:high half of difference


;-----------------------------------------------------------------
; Common exit code
;-----------------------------------------------------------------

DASCtail:	stk1←L, ALUCY, :DAStail;			carry used by double compares
DAStail:	T←2, :Dsetstkp;					adjust stack pointer

Dsetstkp:	L←stkp-T, SWMODE, :Setstkp;
Setstkp:	stkp←L, :romnext;				'next' has proper SWMODE bit

;-----------------------------------------------------------------
; DCOMP - compare two long integers, assuming:
;	stack contains precisely 4 elements
;	result left on stack is -1, 0, or +1 (single-precision)
;	  (i.e. result = sign(stk1,,stk0 DSUB stk3,,stk2) )
;-----------------------------------------------------------------
; !1,1,DCOMPxa;							shake B/A dispatch
!10,1,DCOMPxb;							shake IR← dispatch
!1,2,DCOMPnocarry,DCOMPcarry;
!1,2,DCOMPgtr,DCOMPequal;

DCOMP:		IR←T←100000, :DCOMPxa;				IR←msr0, must shake dispatch
DCOMPxa:	L←stk1+T, :DCOMPxb;				scale left operand
DCOMPxb:	stk1←L;
		L←stk3+T, TASK;					scale right operand
		stk3←L, :DSUBsub;				do DSUB, return to DCOMPr

DCOMPr:		T←stk0, :DCOMPnocarry;				L: stk1, ALUCY pending

DCOMPnocarry:	L←0-1, BUS=0, :DCOMPsetT;			left opnd < right opnd
DCOMPcarry:	L←M OR T;					L: stk0 OR stk1
		SH=0;
DCOMPsetT:	T←3, :DCOMPgtr;					T: amount to adjust stack

DCOMPgtr:	L←0+1, :DCOMPequal;				left opnd > right opnd
DCOMPequal:	stk0←L, :Dsetstkp;				stash result


;-----------------------------------------------------------------
; DUCOMP - compare two long cardinals, assuming:
;	stack contains precisely 4 elements
;	result left on stack is -1, 0, or +1 (single-precision)
;	  (i.e. result = sign(stk1,,stk0 DSUB stk3,,stk2) )
;-----------------------------------------------------------------

DUCOMP:		IR←sr3, :DSUBsub;				returns to DCOMPr

;-----------------------------------------------------------------
; E m u l a t o r   A c c e s s
;-----------------------------------------------------------------


;-----------------------------------------------------------------
; RR - push <emulator register alpha>, where:
;	RR is A-aligned (also ensures no pending branch at entry)
;	alpha:	1 => wdc, 2 => XTSreg, 3 => XTPreg, 4 => ATPreg,
;		5 => OTPreg
;-----------------------------------------------------------------
!7,10,RR0,RR1,RR2,RR3,RR4,RR5,,;

RR:		SINK←ib, BUS;					dispatch on alpha
RR0:		L←0, SWMODE, :RR0;				(so SH=0 below will branch)

RR1:		L←wdc, SH=0, :romUntail;			will go to pushTA
RR2:		L←XTSreg, SH=0, :romUntail;			will go to pushTA
RR3:		L←XTPreg, SH=0, :romUntail;			will go to pushTA
RR4:		L←ATPreg, SH=0, :romUntail;			will go to pushTA
RR5:		L←OTPreg, SH=0, :romUntail;			will go to pushTA


;-----------------------------------------------------------------
; WR - emulator register alpha ← <TOS> (popped), where:
;	WR is A-aligned (also ensures no pending branch at entry)
;	alpha: 1 => wdc, 2 => XTSreg
;-----------------------------------------------------------------
!7,10,WR0,WR1,WR2,,,,,;

; WR:		L←ret3, TASK, :Xpopsub;				performed in ROM

WR:		SINK←ib, BUS;					dispatch on alpha
WR0:		SWMODE, :WR0;

WR1:		wdc←L, :romnextA;
WR2:		XTSreg←L, :romnextA;

;-----------------------------------------------------------------
; BLT - block transfer
;	assumes stack has precisely three elements:
;	  stk0 - address of first word to read
;	  stk1 - count of words to move
;	  stk2 - address of first word to write
;	the instruction is interruptible and leaves a state suitable
;	  for re-execution if an interrupt must be honored.
;-----------------------------------------------------------------
!1,2,BLTmore,BLTdone;
!1,2,BLTsource,BLTCsource;
!1,2,BLTeven,BLTodd;
!1,1,BLTintx;							shake branch from BLTloop

;  Entry sequence in ROM1; actual entry is at BLTloop

;BLT:		stk7←L, SWMODE, :BLTx;				stk7=0 <=> branch pending
;BLTx:		IR←msr0, :ramBLTloop;				IR← is harmless


BLTloop:	L←T←stk1-1, BUS=0, :BLTnoint;
BLTnoint:	stk1←L, L←BUS AND ~T, IDISP, :BLTmore;		L←0 on last iteration (value
;								on bus is irrelevant, since T
;								will be -1).  IDISP on last
;								cycle requires that Setstkp
;								be odd.

BLTmore:	T←cp, :BLTsource;

BLTsource:	MAR←stk0, :BLTupdate;				start data source fetch
BLTCsource:	XMAR←stk0+T, :BLTupdate;			start code source fetch

BLTupdate:	L←stk0+1;
		stk0←L;						update source pointer
		L←stk2+1;
		T←MD;						source data
		MAR←stk2;					start dest. write
		stk2←L, L←T;					update dest. pointer
		SINK←NWW, BUS=0, TASK;				check pending interrupts
		MD←M, :BLTintpend;				loop or check further

BLTintpend:	SINK←wdc, BUS=0, :BLTloop;			check if interrupts enabled

;	Must take an interrupt if here (via BLT or BITBLT)

BLTint:		SINK←stk7, BUS=0, :BLTintx;			test even/odd pc
BLTintx:	L←mpc-1, :BLTeven;				prepare to back up

BLTeven:	mpc←L, L←0, :BLTodd;				even - back up pc, clear ib
BLTodd:		ib←L, SWMODE;					odd - set ib non-zero
		:romIntstop;

;	BLT completed

BLTdone:	SINK←stk7, BUS=0, SWMODE, :Setstkp;		stk7=0 => return to 'nextA'