;--- HOW TO DO ARITHMETIC IN IKONAS MICROCODE, AND OTHER TRICKS ---;
;
; Paul Heckbert, NYIT

; CONSTANTS
	pr rlimm 0 b1 bd		; r1 = 0
; or
	aluz b1 bd			; r1 = 0

	ldudr 0xffff
	pr rimm 0xffff b1 bd		; r1 = -1
; or
	mr car0 rlimm 0 b1 bd		; r1 = -1
; or
	aluones b1 bd			; r1 = -1 (look Ma, no data field!)

	aluones b1 llfbd		; r1 = -2

	aluones b1 rlfbd		; r1 = 2147483647 (you get the idea)

; NEGATE
	mr car1 ra1 b2 bd		; r2 = -r1

; COMPLEMENT
	mr car0 ra1 b2 bd		; r2 = ~r1 = -r1-1

; EXTRACT LOW HALFWORD
	ras rlimm 0xffff b1 bd		; r1 &= 0x0000ffff

	pr rlmdr b1 bd			; r1 = LOW MDR = MDR&0x0000ffff

; EXTRACT HIGH HALFWORD
	nras rlimm 0xffff b1 bd		; r1 &= 0xffff0000

; ADD
	rps ra1 b2 alumdr		; mdr = r1+r2

; ADD TWO 16-BIT NUMBERS IN PARALLEL
	rps carh0 ra1 b2 qd		; Q = (hi(r1)+hi(r2):lo(r1)+lo(r2))

; SUBTRACT
	rms car1 ra1 b2 alumdr		; mdr = r1-r2

; DECREMENT (note: there's no way to decrement without using
;	     the data field or a second register)
	smr car1 rlimm 1 b2 bd		; r1 = r1-1
; or
	smr car0 rlimm 0 b2 bd		; r1 = r1-1

; INCREMENT
	incrs b2			; r2++
; or
	ps car1 b2 bd			; r2++
; or
	rps rlimm 1 b2 bd		; r2++

; STEP RIGHT ONE LORES PIXEL (assuming you've got address in a register)
	incrs car1 b2 alumar		; MAR=r2+=2 (no wasted data field!)

; IF (R1<=R2) R1++
	rms car1 ra2 b1			; r2-r1
	ps car31 b1 bd			; r1 = r1+car31 = r1+(r2>=r1)

; IF (R1>R2) R1++
	rms car1 ra2 b1			; r2-r1
	ps carn31 b1 bd			; r1 = r1+carn31 = r1+(r2<r1)

; MULTIPLY BY 2
	rps ra1 b1 bd
; or
	ps b1 llfbd			; logical shift
; or
	ps b1 lafbd			; arithmetic shift

; MULTIPLY BY 4
	rps ra1 b1 llfbd		; r1 = r1+r1<<1

; DIVIDE BY 2
	ps b1 rlfbd			; logical right-shift
; or
	ps b1 rafbd			; arithmetic (for sign/magnitude only)
; or
	ps b1 rlfbd ldudr 0x8000	; arithmetic (for + or - numbers)
	nccneg jmpdf skip		; note: tests sign of r1, not r1>>1
	rors rimm 0 b1 bd
skip:
; or
	smtc carz b1			; convert to sign/magnitude
	ps b1 rafbd			; shift right 1 arithmetic
	smtc carz b1			; convert back
; or
	ps b1 rlflqbd ls0		; logical shift (r1,Q) right 1 bit
;
; note on neg. numbers:
; on the vax: -1>>1 = -1, -2>>1 = -1, -3>>1 = -2
; with rafbd: -1>>1 = 0,  -2>>1 = -1, -3>>1 = -1

; 16-BIT MULTIPLY USING MULTIPLIER CHIP
	pr ra1 alumpx
	pr ra2 alumpy
	nanop				; necessary!
	b2 bd mpzbr			; r2 = r1*r2+32768
	smr car1 rlimm 32768 b2 bd	; subtract 32768

; CONVERT FROM SIGNED TO TWO'S COMPLEMENT OR VICE-VERSA
	smtc carz b2

; 32-BIT NORMALIZE
	pr ra1 qd			; load Q with # to be normalized
	aluz b2 bd			; initialize shift counter to 0
	slnml car1 b2 nccovr jmpdf .	; shift Q left, r2++ till normalized
					; when done, r2 contains # of shifts
					; works for numbers < 2^30

; 64-BIT NORMALIZE
	pr ra1 qd			; Q is low 32 bits, r2 high 32
	dlnml ls0 b2 nccovr jmpdf .	; shift r2,Q left till normalized
					; works for numbers < 2^62

; UNSIGNED 32-BIT MULTIPLY
	aluz b3 bd			; R3,Q = r1*r2
	pr ra1 qd  ldcnt -31		; Q = r1; set counter
	umpy ra2 b3 ls0 ncccntz jmpcnt .; 32 bit operands, 64 bit result

; TWO'S COMPLEMENT 32-BIT MULTIPLY
	aluz b3 bd			; R3,Q = r1*r2
	pr ra1 qd  ldcnt -30		; Q = r1; set counter
	tcmpy ra2 b3 ls0 ncccntz jmpcnt .; 32 bit operands, 64 bit result
	tcmpl ra2 b3 carz ls0

; TWO'S COMPLEMENT DIVISION, method 1 (positive operands only)
	dlnml ra2 b1 lr  ldcnt -30	; Q = r1,Q / r2;  r1 = r1,Q % r2
	tcdiv ra2 b1 lr carz  ncccntz jmpcnt . ; shift and subtract in loop
	tcdivc ra2 b1 ss0 carz		; divide correction
	rps ra2 b1 bd			; fix remainder
; note: low bit of quotient is always 0, so it should not be trusted

; TWO'S COMPLEMENT DIVISION, method 2 (positive operands only)
	dlnml ra2 b1 lr  ldcnt -31	; Q = r1,Q / r2;  r1 = r1,Q % r2
	tcdiv ra2 b1 lr carz  ncccntz jmpcnt . ; shift and subtract in loop
	tcdivc ra2 b1 ss1 carz		; divide correction
	rps ra2 b1 rlflqbd		; fix quotient and remainder

; TRICKS:
	ikmdr  pr rbhs b1 qd		; MDR = BUS; Q = r1>>16

	rps ra1 b2 bdqd alumar		; MAR = Q = r2 += r1

	rps car1 rbhs b1 sq llfbd	; r1 = ((r1>>16)+Q+1)<<1

	ikrd b1 ikbr  rps ra2 bdqd	; read; r1 = BUS; Q = r1+r2

	ldudr 0xf			; clears hires image
	pr rimm 0xffff qd alumar napush	; nalup doesn't use data field
	hreswr  smr rlimm car0 0 sq qd alumar  ccgtz nalup  dfikd
					; note: rlimm implies dfikd

	ras rlimm 255 b1 bd		; copy low byte of r1 into all 4 bytes
	rors rbbr b1 bd
	rors rbhr b1 bd
