*------------------------------------------
 DEF ASM_DIV
 DEF ASM_MOD
*------------------------------------------
*               register usage
*               d0 - return address
*               d1 - divisor
*               d2 - dividend and quotient
*               d3 - remainder
*               d4 - loop counter
*               d5 - sign of remainder
*               d6 - sign of quotent
*               d7 - mod/div flag
*
ovflow          trap            #4
valrange        trap            #7
asm_mod         moveq           #1,d7           set mod flag
		movem.l         (sp)+,d0/d1/d2  read return addr and operands
		tst.l           d1              divide by zero?
		bpl.s           d_start         for mod?
		bra.s           valrange
asm_div         moveq           #0,d7           clear mod flag
		movem.l         (sp)+,d0/d1/d2  read return addr and operands
		tst.l           d1              divide by zero?
d_start         beq.s           zerodiv
		movea.w         d1,a0           is divisor a
		cmp.l           a0,d1           16 bit integer?
		bne.s           do_full
		move.l          d2,d3           try signed divide
		divs            d1,d3
		bvs.s           do_full         did it work?
		tst.w           d7              mod or div?
		beq.s           div_1
		swap            d3
		tst.w           d3              if mod is negative
		bpl.s           div_1           teen
		add.w           d1,d3           add back divisor
div_1           ext.l           d3
dm_out          move.l          d3,-(sp)        push result
		movea.l         d0,a0
		jmp             (a0)            fake return
zerodiv         trap            #5
*
*               convert divisor and dividend to sign magnitude
*
do_full         moveq           #15,d4          loop count - 1
		moveq           #0,d6           sign of quotient
		moveq           #0,d5           sign of remainder
		tst.l           d1              divisor negative?
		bpl.s           divend
		neg.l           d1
		bvs.s           max_neg_dvsr
		not.w           d6              set sign flag
divend          tst.l           d2              dividend negative
		bpl.s           rmndr
		neg.l           d2              complement quotient sign
		bvc.s           not_special
		cmp.l           #1,d1           test for minint div -1
		bne.s           not_special
		tst.w           d6
		bne.s           ovflow
not_special     not             d6              flag
		not             d5              negative remainder
rmndr           moveq           #0,d3           clear remainder
		swap            d1              is divisor <= 16 bits
		tst.w           d1
		bne.s           big_div
		swap            d2
		swap            d1
		move.w          d2,d3           get high order dividend
		divu            d1,d3           high part of divide
		move.w          d3,d2           high quotient to d2
		swap            d2
		move.w          d2,d3           divide low order
		divu            d1,d3           dividend by divisor
		move.w          d3,d2           quotient in d2
		clr.w           d3
		swap            d3              remainder in d3
*               put in correct sign for quotient and remainder
dm_fixup        tst.w           d6
		bpl.s           chk_rem
		neg.l           d2
chk_rem         tst.w           d5
		bpl.s           dm_store
		neg.l           d3
dm_store        tst.w           d7              div or mod?
		bne.s           mod_out
		move.l          d2,d3
		bra.s           dm_out
mod_out         tst.l           d3              if negative mod
		bpl.s           dm_out          then
		add.l           d1,d3           then add back divisor
		bra.s           dm_out
*
*               handle maximum negative divisor
*
max_neg_dvsr    neg.l           d2
		bvs.s           max_max         test for max neg dividend
		move.l          d2,d3
		neg.l           d3
		moveq           #0,d2
		bra.s           dm_store
max_max         moveq           #1,d2
		moveq           #0,d3
		bra.s           dm_store
*
*               32 bit divisor
*
big_div         swap            d1              restore divisor
		swap            d2              move high order
		move.w          d2,d3           dividend to remainder
		clr.w           d2              shift dividend 16 bits left
		sub.l           d1,d3           subtract divisor from rem.
		movea.l         d1,a0           divisor in d1
		neg.l           d1              minus divisor in a0
		exg             d1,a0
*
*               co-routine for negative remainder
*
m_top           add.l           d2,d2           shift dividend and quotient
		addx.l          d3,d3           shift remainder
		add.l           d1,d3           add divisor
		bpl.s           p_bottom        remainder positive?
m_bottom        dbra            d4,m_top        loop 16 times
		add.l           d1,d3           restore remainder
		add.l           d2,d2           shift in last bit of quotient
		bra.s           dm_fixup
*
*               co-routine for positive remainder
*
p_top           addx.l          d2,d2           shift dividend and quotient
		addx.l          d3,d3           shift remainder
		add.l           a0,d3           subtract divisor
		bmi.s           m_bottom        remainder negative?
p_bottom        dbra            d4,p_top        loop 16 times
		addx.l          d2,d2           shift in last bit of quotient
		bra.s           dm_fixup
	end
