		include	inc:lvo/exec_lib.i
		include	inc:lvo/dos_lib.i
		include inc:exec/memory.i

		section	code,code

divide32	MACRO
		; dividend in d0
		; divisor in d1
		; result in d2
		; remainder in d0
		move.w	d0,d3	; copy low word of dividend to d3
		clr.w	d0		; prepare high word of
		swap	d0		; dividend for divu.w
		divu.w	d1,d0	; divide highword of dividend by divisor
		move.w	d0,d2	; set high word of result
		swap	d2		; to result
		move.w	d3,d0	; add low word of dividend to remainder of high word
		divu.w	d1,d0	; divide low word of dividend by divisor
		move.w	d0,d2	; add low word of result
		clr.w	d0		; return remainder
		swap	d0		; in d0
		ENDM
		
mul3216	MACRO
		; source operand 1 (32 bit) in d0
		; source operand 2 (16 bit) in d1
		; result (32 bit) in d0
		move.w	d0,d3	; copy low word of operand 1 to d3
		swap	d0		; prepare high word of operand 1 for mulu.w
		mulu.w	d1,d3	; multiply low word with operand 2
		mulu.w	d1,d0	; multiply high word with operand 2
		swap	d0		; set high word of result to high part of register
		clr.w	d0		; clear low word (overflow)
		add.l	d3,d0	; add low word to high word, to complete the result
		ENDM
		
mul6432	MACRO
		; source operand 1 (32 bit) in d0
		; source operand 2 (32 bit) in d1
		; result in d1:d2
		move.l	d0,d2	; copy operand 1 to d2
		move.w	d0,d4	; copy low word of operand 1 to d4
		swap	d2		; prepare high word of operand 1 for mulu.w
		mulu.w	d1,d4	; multiply low word of operand 1 with low word of operand 2
		mulu.w	d1,d2	; multiply high word of operand 1 with low word of operand 2
		swap	d2		; swap words to ease adding the result to the 2 result registers
		swap	d1		; prepare high word of operand 2 for mulu.w
		move.w	d0,d3	; copy low word of operand 1 to d3
		swap	d0		; prepare high word of operand 1 for mulu.w
		mulu.w	d1,d3	; multiply low word of operand 1 with high word of operand 2
		mulu.w	d0,d1	; multiply high word of operand 1 with high word of operand 2
		clr.l	d0		; Clear registers for
		clr.l	d5		; adding the low parts
		swap	d3		; swap words to ease adding the result to the 2 result registers
		move.w	d2,d0	; set low words of partial result to the
		move.w	d3,d5	; cleared registers
		clr.w	d2		; remove low words from
		clr.w	d3		; partial results
		add.l	d4,d2	; add first low lword results
		addx.l	d0,d1	; add first high lword results
		add.l	d3,d2	; add second low lword results
		addx.l	d5,d1	; add second high lword results
		ENDM

Exec_Base EQU $4

Start
		moveq	#25,d0
		moveq	#MEMF_ANY,d1
		movea.l	Exec_Base.w,a6
		jsr		_LVOAllocMem(a6)
		move.l	d0,bitStream
		
		moveq	#$15,d0
		moveq	#5,d1
		bsr		.SetBits
		move.l	#$AAAAAAAA,d0
		moveq	#32,d1
		bsr		.SetBits

		moveq	#$FFFFFFFF,d0
		moveq	#$FFFFFFFF,d1
		mul6432

		move.l	blah,d0
		moveq	#16,d1
		mul3216
		movea.l	#buffer+10,a0
		move.b	#0,-(a0)
		move.b	#$A,-(a0)
		bsr.s	.printHEX
		movea.l	Exec_Base.w,a6
		
		lea		DOSName,a1	; Library name
		moveq	#37,d0		; Library version (v37 == OS2.04?)
		jsr		_LVOOpenLibrary(a6)
		move.l	d0,DOSBase
		beq.s	.error		; Unable to open library?

		movea.l	d0,a6		; Print "hello world"
		move.l	#HelloMessage,d1
		jsr		_LVOPutStr(a6)
		
		move.l	#buffer,d1
		jsr		_LVOPutStr(a6)

		move.l	#string,a0
		bsr		.strLen
		
		movea.l	#string,a0
		moveq	#16,d1
		bsr		.parseRadixSigned
		movea.l	#buffer,a0
		moveq	#10,d1
		bsr		.printRadixSigned
		move.l	#buffer,d1
		jsr		_LVOPutStr(a6)		

.error
		move.l	DOSBase,d0
		beq.s	.nclosedos	; dos.library is not open?
		move.l	d0,a1
		move.l	Exec_Base.w,a6
		jsr		_LVOCloseLibrary(a6)
.nclosedos
		moveq	#0,d0		; Returncode 0
		rts

.printHEX
		moveq	#7,d2

.hexLoop
		move.b	d0,d1
		andi.b	#$F,d1
		addi.b	#$30,d1
		cmpi.b	#$39,d1
		bls.s	.noChar
		addq.b	#7,d1
.noChar
		move.b	d1,-(a0)
		lsr.l	#4,d0
		;dbra	d2,.hexLoop
		bne.s	.hexLoop
		rts
		
.parseRadix
		; input: radix in d1, ASCIZ string in a0
		; output: parsed number in d0
		clr.l	d4
		clr.l	d0
		move.b	(a0)+,d0
		beq.s	.endOfParsing
		subi.b	#$30,d0
		cmpi.b	#9,d0
		bls.s	.noChar00
		subi.b	#7,d0
.noChar00		
		move.b	(a0)+,d4
		beq.s	.endOfParsing
		
.smallParseLoop
		subi.b	#$30,d4
		cmpi.b	#9,d4
		bls.s	.noChar0
		subi.b	#7,d4
.noChar0
		mulu.w	d1,d0
		add.l	d4,d0
		move.b	(a0)+,d4
		beq.s	.endOfParsing
		cmpi.l	#$FFFF,d0
		bls.s	.smallParseLoop

.bigParseLoop
		subi.b	#$30,d4
		cmpi.b	#9,d4
		bls.s	.noChar1
		subi.b	#7,d4
.noChar1
		mul3216
		add.l	d4,d0
		move.b	(a0)+,d4
		bne.s	.bigParseLoop

.endOfParsing
		rts
		
.parseRadixSigned
		cmpi.b	#'-',(a0)
		bne.s	.parseRadix
		adda.l	#1,a0
		bsr.s	.parseRadix
		neg.l	d0
		rts
		
.printRadix
		; input: number in d0, radix in d1, output buffer in a0
		; output: number in ASCII string in buffer, length in d0
		move.l	#$FF,d4	; stringlength counter

		; if (dividend-highword)<divisor, then do a normal division
		move.l	d0,d2
		clr.w	d2
		swap	d2
		cmp.w	d1,d2
		bcs.s	.radixLoopShort
		
.radixLoopLong
		divide32
		addi.b	#$30,d0
		cmp.b	#$39,d0
		bls.s	.noChar3
		addq.b	#7,d0
.noChar3
		move.b	d0,-(sp)
		addq.b	#1,d4
		move.l	d2,d0		; Check if next division is to be short or long
		beq.s	.endLoop
		clr.w	d2
		swap	d2
		cmp.w	d1,d2
		bcc.s	.radixLoopLong
		
.radixLoopShort
		divu.w	d1,d0
		swap	d0
		addi.b	#$30,d0
		cmp.b	#$39,d0
		bls.s	.noChar2
		addq.b	#7,d0
.noChar2
		move.b	d0,-(sp)
		clr.w	d0
		addq.b	#1,d4
		swap	d0
		bne.s	.radixLoopShort
		
.endLoop
		move.b	d4,d0
		addq.b	#1,d0
										
.copyLoop				
		move.b	(sp)+,(a0)+
		dbra	d4,.copyLoop
		
		move.b	#0,(a0)
						
		rts
		
.printRadixSigned
		tst.l	d0
		bpl.s	.printRadix
		move.b	#'-',(a0)+
		neg.l	d0
		bsr.s	.printRadix
		addq.b	#1,d0
		rts
	
.strLen
		moveq	#-1,d0
.strLenLoop
		tst.b	(a0)+
		dbeq	d0,.strLenLoop
		not.l	d0
		rts
		
;void SetBits(unsigned int bits, unsigned int n)
;{
;	while ((cacheBits + n) > CACHESIZE)
;	{
;		bitCache <<= (CACHESIZE - cacheBits);
;		bitCache |= (bits >> (n -= (CACHESIZE - cacheBits));
;		*bitStream++ = bitCache;
;		/*bits &= (1 << n) - 1);*/
;		cacheBits = 0;
;	}
;
;	bitCache <<= n;
;	bitCache |= bits;
;
;	cacheBits += n;
;}

CACHESIZE equ 32
		
.SetBits
; bits in d0, length in d1
	move.b	cacheBits,d2
	move.b	d2,d4
	add.b	d1,d2
	move.l	bitCache,d3
	cmpi.b	#CACHESIZE,d2
	bls.s	.noOverflow
	
	movea.l	bitStream,a0
		
.overflowLoop	
	move.b	#CACHESIZE,d2
	sub.b	d4,d2
	move.l	d0,d4
	lsl.l	d2,d3
	sub.b	d2,d1
	lsr.l	d1,d4
	or.l	d4,d3
	
	move.l	d3,(a0)+
	
	clr.b	d2
	;cmpi.b	#CACHESIZE,d1
	;bhi.s	.overflowLoop
	
	move.l	a0,bitStream	
	
.noOverflow
	lsl.l	d1,d3
	move.b	d2,cacheBits
	or.l	d0,d3
	move.l	d3,bitCache

	rts

		section	data,data

cacheBits	dc.b	0

DOSName		dc.b	"dos.library",0
;EXECName	dc.b	"exec.library",0

HelloMessage	dc.b	"All that remains now, is Death",$A,0

blah		dc.l	$1F2E3C4D
bleh		dc.l	$FFFFFFFF
string		dc.b	"FFFFFFFF",0
signedString	dc.b	"-12345678",0

		section bss,bss
DOSBase		ds.l	1
;EXECBase	ds.l	1
buffer		ds.b	512
bitCache	ds.l	1
bitStream	ds.l	1