 * $Revision Header *** Header built automatically - do not edit! **********
 *
 *	(C) Copyright 1991 by Torsten Jürgeleit
 *
 *	Name .....: gadgets4.asm
 *	Created ..: Thursday 19-Dec-91 21:34:12
 *	Revision .: 1
 *
 *	Date        Author                 Comment
 *	=========   ====================   ====================
 *	01-Jul-92   Torsten Jürgeleit      corrected slider bug -> sometimes
 *					   clicking inside of slider gadget
 *					   container don't move the knob
 *					   inside of slider gadget container
 *	19-Dec-91   Torsten Jürgeleit      Created this file!
 *
 ***************************************************************************
 *
 * Proportional gadget support routines (32 bit !!!)
 *
 * $Revision Header ********************************************************

*---------------------------------------------------------------------------
* USHORT calc_prop_body(ULONG max_num, ULONG size)
*  d0.w                         d0.l         d1.l
* Calculate the body value for the PropInfo structure
*---------------------------------------------------------------------------
	XDEF	_calc_prop_body
_calc_prop_body:
	movem.l	d2-d6,-(sp)

	; --- check max_num
	move.l	d0,d6		; save max_num in d6
	beq	cpb_maximum	; max_num == 0 ?
	cmp.l	d0,d1		; size >= max_num ?
	bhs	cpb_maximum

	; --- multiply size [32 bit] by MAXBODY ($ffff) [16 bit] with 48 bit arithmetic
	moveq	#0,d0		; clear shift out reg for size
	move.l	d1,d3		; init result by doing the first add
	moveq	#0,d2		; clear shift out reg of result
	moveq	#16-2,d4	; init shift count (MAXBODY has only 16 bits - one add already done)

cpb_mul_loop:
	; --- shift size
	add.l	d1,d1		; shift left of size
	addx.w	d0,d0		; save shift out

	; --- inc result
	add.l	d1,d3		; add shifted size to result
	addx.w	d0,d2		; add shift out and carry
	dbra	d4,cpb_mul_loop

	; --- divide result [48 bit] by max_num [32 bit] with 48 bit arithmetic
	moveq	#0,d0		; clear result
	moveq	#0,d1		; clear shift out reg for divident
	moveq	#0,d4		; clear sub divisor help reg
	moveq	#32-1,d5	; init shift count

cpb_div_loop:
	; --- shift result and divident
	add.l	d0,d0		; shift result
	add.l	d3,d3		; shift left of lower LONG of divident
	addx.l	d2,d2		; shift left of upper LONG of divident - add shift out
	addx.w	d1,d1		; save shift out

	; --- check if upper LONG of divident large enough to sub divisor from
	tst.w	d1		; any shift out ?
	bne	cpb_sub_divisor
	cmp.l	d2,d6		; upper LONG of divident > divisor ?
	bhi	cpb_next_div

cpb_sub_divisor:
	sub.l	d6,d2		; sub divisor from upper LONG of divident
	subx.w	d4,d1		; sub underflow (d4 = 0) from shift out of upper LONG of divident
	addq.l	#1,d0		; set bit 0 of result
	
cpb_next_div:
	dbra	d5,cpb_div_loop

	; --- don't return ZERO as prop_body
	tst.w	d0
	bne	cpb_exit
	moveq	#1,d0
	
cpb_exit:
	movem.l	(sp)+,d2-d6
	rts

cpb_maximum:
	move.l	#$ffff,d0	; prop_body := MAXBODY
	bra	cpb_exit


*---------------------------------------------------------------------------
* USHORT calc_prop_pot(ULONG max_num, ULONG size, ULONG num)
*  d0.w                        d0.l         d1.l        d2.l
* Calculate the prop value for the PropInfo structure
*---------------------------------------------------------------------------
	XDEF	_calc_prop_pot
_calc_prop_pot:
	movem.l	d3-d6,-(sp)

	; --- prepare max_num
	move.l	d0,d6		; save max_num
	beq	cpp_minimum
	sub.l	d1,d6		; max_num -:= size
	bcs	cpp_minimum

	; --- multiply num [32 bit] by MAXPOT ($ffff) [16 bit] with 48 bit arithmetic
	moveq	#0,d0		; clear shift out reg for size
	move.l	d2,d1		; init num
	move.l	d1,d3		; init result by doing the first add
	moveq	#0,d2		; clear shift out reg of result
	moveq	#16-2,d4	; init shift count (MAXPOT has only 16 bits - one add already done)

cpp_mul_loop:
	; --- shift num
	add.l	d1,d1		; shift left of num
	addx.w	d0,d0		; save shift out

	; --- inc result
	add.l	d1,d3		; add shifted num to result
	addx.w	d0,d2		; add shift out and carry
	dbra	d4,cpp_mul_loop
	ext.l	d2		; expand upper WORD to LONG

	; --- divide result [48 bit] by (max_num - size) [32 bit] with 48 bit arithmetic
	moveq	#0,d0		; clear result
	moveq	#0,d1		; clear shift out reg for divident
	moveq	#0,d4		; clear sub divisor help reg
	moveq	#32-1,d5	; init shift count

cpp_div_loop:
	; --- shift result and divident
	add.l	d0,d0		; shift result
	add.l	d3,d3		; shift left of lower LONG of divident
	addx.l	d2,d2		; shift left of upper LONG of divident - add shift out
	addx.w	d1,d1		; save shift out

	; --- check if upper LONG of divident large enough to sub divisor from
	tst.w	d1		; any shift out ?
	bne	cpp_sub_divisor
	cmp.l	d2,d6		; upper LONG of divident > divisor ?
	bhi	cpp_next_div

cpp_sub_divisor:
	sub.l	d6,d2		; sub divisor from upper LONG of divident
	subx.w	d4,d1		; sub underflow (d4 = 0) from shift out of upper LONG of divident
	addq.l	#1,d0		; set bit 0 of result
	
cpp_next_div:
	dbra	d5,cpp_div_loop

	; --- if pot_value > MAXPOT then return MAXPOT
	cmp.l	#$ffff,d0
	bls	cpp_exit
	move.l	#$ffff,d0	; prop_pot := MAXPOT

cpp_exit:
	movem.l	(sp)+,d3-d6
	rts

cpp_minimum:
	moveq	#0,d0		; prop_pot := 0
	bra	cpp_exit


*---------------------------------------------------------------------------
* ULONG get_prop_pos(ULONG max_num, ULONG size, UWORD pot_value)
*  d0.l                      d0.l         d1.l           d2.w
* Calculate the position of the knob of a proporitional gadget
*---------------------------------------------------------------------------
	XDEF	_get_prop_pos
_get_prop_pos:
	movem.l	d3-d6,-(sp)

	; --- prepare max_num
	sub.l	d1,d0		; max_num -:= size
	bcs	gpp_minimum

	; --- if pot_value ]0..MAXPOT[ then inc pot_value and max_num
	move.w	d2,d6		; save pot value
	beq	gpp_minimum	; pot_value == 0 ?
	addq.w	#1,d6		; inc pot_value
	bcs	gpp_exit	; if pot_value == MAXPOT then return (max_num - size)

	; --- multiply (max_num - size) [32 bit] by pot_value [16 bit] with 48 bit arithmetic
	moveq	#0,d1		; clear shift out reg for max_num
	moveq	#0,d3		; clear result
	moveq	#0,d2		; clear shift out reg of result
	moveq	#0,d4		; reset bit count
	moveq	#16-1,d5	; init shift count (16 bits from pot_value)
	bra	gpp_check_bit

gpp_mul_loop:
	add.l	d0,d0		; shift left of max_num
	addx.w	d1,d1		; save shift out

gpp_check_bit:
	; --- check bit of pot_value
	btst	d4,d6
	beq	gpp_next_mul	; bit set ?

	; --- if bit set then inc result
	add.l	d0,d3		; add shifted max_num to result
	addx.w	d1,d2		; add shift out and carry

gpp_next_mul:
	addq.w	#1,d4		; inc bit count
	dbra	d5,gpp_mul_loop
	ext.l	d2		; expand upper WORD to LONG

	; --- divide result [48 bit] by MAXPOT ($ffff) [16 bit] with 48 bit arithmetic
	moveq	#0,d0		; clear result
	moveq	#0,d1		; clear shift out reg for divident
	moveq	#0,d4		; clear sub divisor help reg
	moveq	#32-1,d5	; init shift count
	move.l	#$ffff,d6	; init divisor (MAXPOT)

gpp_div_loop:
	; --- shift result and divident
	add.l	d0,d0		; shift result
	add.l	d3,d3		; shift left of lower LONG of divident
	addx.l	d2,d2		; shift left of upper LONG of divident - add shift out
	addx.w	d1,d1		; save shift out

	; --- check if upper LONG of divident large enough to sub divisor from
	tst.w	d1		; any shift out ?
	bne	gpp_sub_divisor
	cmp.l	d2,d6		; upper LONG of divident > divisor ?
	bhi	gpp_next_div

gpp_sub_divisor:
	sub.l	d6,d2		; sub divisor from upper LONG of divident
	subx.w	d4,d1		; sub underflow (d4 = 0) from shift out of upper LONG of divident
	addq.l	#1,d0		; set bit 0 of result
	
gpp_next_div:
	dbra	d5,gpp_div_loop

gpp_exit:
	movem.l	(sp)+,d3-d6
	rts

gpp_minimum:
	moveq	#0,d0		; prop_pos := 0
	bra	gpp_exit


	END
