;==========================================================
;
; x51 math library 
; 
; (C) HELIUM  
; http://helium.webz.cz/
;
; compiled with MetaLink 8051 Cross-Assembler, Version 1.2k
;==========================================================

$MOD51

;==========================================================
; reservovane registry v bance 0 :   R0 - R3
; organizace dat  [Lo - Hi] 

cytmp	BIT	0H		; zaloha CY		 1 bit
adrm	DATA	030H		; vysledek nasobeni      2*R2 bytes
adrmp	DATA	038H		; mezivysledek nasobeni  R2+1 bytes 
adrmi	DATA	03FH		; pomocny index	         1 byte

;==========================================================

; podprogram pro vymazani pameti
; R0 adresa, R2 pocet bytes
;
clear0:	push	ACC		;
	push	0		;
	push	2		;
	clr	A		;
	
clear00:mov	@R0, A		;
	inc	R0		;
	djnz	R2, clear00	;
	
	pop	2		;
 	pop	0		;
	pop	ACC		;
	RET			;

;==========================================================

; podprogram pro vymazani pameti
; R1 adresa, R3 pocet bytes
;
clear1:	push	ACC		;
	push	1		;
	push	3		;
	clr	A		;
	
clear10:mov	@R1, A		;
	inc	R1		;
	djnz	R3, clear10	;
	
	pop	3		;
 	pop	1		;
	pop	ACC		;
	RET			;

;==========================================================

; podprogram pro zkopirovani pameti  [@R1]:=[@R0]
; z [@R0] adresy na [@R1] adresu, R2 pocet bytes
;
copy:	push	ACC		;
	push	0		;
	push	1		;
	push	2		;
	
copy_0:	mov	A, @R0		;
	inc	R0		;
	mov	@R1, A		;
	inc	R1		;
 	djnz	R2, copy_0	;
	
	pop	2		;
	pop	1		;
	pop	0		;
	pop	ACC		;
	RET			;

;==========================================================

; podpogram na porovnani dvou cisel
; adresy v @R0, @R1,  R2 pocet bytes
;
; @R0 => @R1  CY=1
; @R0 <  @R1  CY=0
; @R0 =  @R1  CY=1 & ACC=0
;
cmp:	push	0		;
	push	1		;
	push	2		;

	mov	A, R0		;
	add	A, R2		;
	mov	R0, A		;
	mov	A, R1		;
	add	A, R2		;
	mov	R1, A		;

cmp_0:	dec	R0		;
	dec	R1		;
	mov	A, @R1		;
	cpl	A		; dvojkovy doplnek
	add	A, @R0		; porovnani cislic 
	cpl	A		;
	jnz 	cmp_2		; ACC=0, rovnost
	djnz	R2, cmp_0	; ??
		
	clr	C		; nastaveni CY pri ACC=0, rovnost
	cpl	C		;
cmp_2:	pop	2		;
	pop	1		;
	pop	0		;
	RET			; 

;==========================================================

; podpogram na posun doleva od CY, pres CY 
; adresa v @R0,  R2 pocet bytes
;
rot_L:	push	ACC		;
	push	0		;
	push	2		;

rot_L1:	mov	A, @R0		;
	rlc	A		;
	mov	@R0, A		;
	inc	R0		; 
	djnz	R2, rot_L1	;
	
	pop	2		;
	pop	0		;
	pop	ACC		;
	RET			;

;==========================================================

; podpogram na posun doprava od CY, pres CY
; adresa v @R0,  R2 pocet bytes
;
rot_R:	push	ACC		;
	push	0		;
	push	2		;
	mov	A, R0		;
	add	A, R2		;
	mov	R0, A		;

rot_R1:	dec	R0		; 
	mov	A, @R0		;
	rrc	A		;
	mov	@R0, A		;
	djnz	R2, rot_R1	;
	
	pop	2		;
	pop	0		;
	pop	ACC		;
	RET			;

;==========================================================

; podpogram na SOUCET dvou cisel [@R0]:=[@R0]+[@R1]
; v R2 pocet bytes, vysledek je dlouhy R2+1
;
addm:	push	0		;
	push	1		;
	push	2		;
	clr	C		;
	
addm_0:	mov	A, @R0		;
	addc	A, @R1		;
	mov	@R0, A		; 
	inc	R0		;
	inc	R1		;
	djnz	R2, addm_0	;

	clr	A		;	
	addc	A, #0		; priznak preteceni
	mov	@R0, A		; 

	pop	2		;
	pop	1		;
	pop	0		;
	RET			;

;==========================================================

; podpogram na ROZDIL dvou cisel [@R0]:=[@R0]-[@R1]
; v R2 pocet bytes
;
subbm:	push	0		;
	push	1		;
	push	2		;
	clr	C		;
	
subbm_0:mov	A, @R0		;
	subb	A, @R1		;
	mov	@R0, A		; 
	inc	R0		;
	inc	R1		;
	djnz	R2, subbm_0	;
	
	pop	2		;
	pop	1		;
	pop	0		;
	RET			;

;==========================================================

; podprogram soucinu 1B x xB
; [@R1] := [@R0] * R3
; R2 pocet bytes, vysledek R2+1 bytes
;
mul8b:	push	0		;
	push	1		;
	push	2		;
	clr	A		;
	mov	@R1, A		;
	
mul8b_0:mov	A,@R0		;
	inc	R0		;
 	mov	B, R3		;
  	mul	AB		;
   	add	A, @R1		;
	mov	@R1, A		;
	inc	R1		;
	mov	A, B		;
	addc	A, #0		;
	mov	@R1, A		;
	djnz	R2, mul8b_0	;
	
	pop	2		;
	pop	1		;
	pop	0		;
	RET			;

;==========================================================	

; podprogram soucinu xB x xB
; [adrm] := [@R0] * [@R1]
; R2 pocet bytes
; R3, R4 - pomocne
; adrm, adrmp, adrmi - vysledek, pomocny mezivysledek a index
;
mulm:	push	0		;
	push	2		;
	mov	adrmi, #0	; vynulovani indexeru
	mov	A, R2		;
	mov	R4, A		; 
	add	A, R2		; vysledek byde dlouhy 2*R2
	mov	R2, A		;
	mov	R0, #adrm	;
	call	clear0		; vynulovani pameti pro vysledek
	pop	2		; znovuobnoveni R0, R2
	pop	0		;
	push	0		;
	push	1		;
	push	2		;
	
mulm_0:	mov	A, @R1		;
	mov	R3, A		; nasobitel
	inc	R1		;
	push	1		;
	mov	R1, #adrmp	; adresa mezivysledku 1B x R2 bytes
	call	mul8b		;
	push 	0		;
	mov	A, adrmi	;
	inc	adrmi		; zvyseni indexu pro pricitani mezivysledku
	add	A, #adrm	; vypocet adresy pro pricteni mezivysledku
	mov	R0, A		;
	inc	R2		; pomocny mezivysledek je R2+1
	call	addm		; pricteni mezivseldku k vysledku
	dec	R2		;
	pop	0		;
	pop	1		;
	djnz	R4, mulm_0	;
	
	pop	2		;
	pop	1		;
	pop	0		;
	RET			;
	
;==========================================================	

; podprogram soucinu 16b x 16b
; [adrm] := [@R0] * [@R1]
;
mul16:	
; 1-1
	mov	A, @R0		;
	mov	B, @R1		;
	mul	AB		;
	mov	adrm, A		;
	mov	adrm+1, B	;
; 1-2
	inc	R0		;
	mov	A, @R0		;
	mov	B, @R1		;
	mul	AB		;
	add	A, adrm+1	;
	mov	adrm+1, A	;	
 	mov	A, B		;
  	addc	A, #0		;
	mov	adrm+2, A	;
 	dec	R0		;	  	
; 2-1	
	inc	R1		;
	mov	A, @R0		;
	mov	B, @R1		;
	mul	AB		;
	add	A, adrm+1	;
	mov	adrm+1, A	;	
 	mov	A, B		;
  	addc	A, adrm+2	;
	mov	adrm+2, A	;
	clr	A		;
  	addc	A, #0		;
	mov	adrm+3, A	;
; 2-2
	inc	R0		;
	mov	A, @R0		;
	mov	B, @R1		;
	mul	AB		;
	add	A, adrm+2	;
	mov	adrm+2, A	;	
 	mov	A, B		;
  	addc	A, adrm+3	;
	mov	adrm+3, A	;
 	dec	R1		;	  	
 	dec	R0		;	  	  	
	RET			;
	
;==========================================================	

; podprogram podilu dvou cisel o delce R2 bytes  [adrm] := [@R0] div [@R1]
; delka R2 bytes, R4 pocitadlo  
; adrmp - pomocny delenec
; casti //* lze zakomentovat pokud neni potreba zachovat obsah [@R0]
;
divm:	push	0	
	mov	R0, #adrmp	;
	call	clear0		; vynulovani adrmp
	pop	0		;
	push	0		;
	push	1		;
	push	2		;
	mov	A, R2		;
	mov	B, #8		;
	mul	AB		; pocet delenych bits
	mov	R4, A		;

divm_0:	call	rot_L		; ziskani nejvyssiho bitu delence do CY
	mov	cytmp, C	; ulozeni bitu CY pro obnovu	//*
	push	0		;
	mov	R0, #adrmp	; adresa pomocneho delence
	call	rot_L		; bit co je vyse v CY do pomocneho delence
	call	cmp		; porovnani
	jnc	divm_1		; pokud delenec<delitel skok
	mov	R0, #adrm	; pokud delenec>=delitel, 
	call	rot_L		; subpodil CY=1  do vysledku
	mov	R0, #adrmp	;
	call    subbm		; jinak odecist, pdelenec:=pdelenec-delitel
	jmp	divm_2		;
	
divm_1:	mov	R0, #adrm	; 
	call 	rot_L		; subpodil  CY=0 do vysledku
divm_2:	pop	0		;
	mov	C, cytmp	; obnoveni CY			//*
	djnz	R4, divm_0	;

	call	rot_L		;				//*
	pop	2		;
	pop	1		;
	pop	0		;
	RET			;

;==========================================================	

; podprogram na prevod BIN->BCD [@R0] -> [@R1] ;   [@R1] := f( [@R0] )
; [@R0], R2 - pocet bin bytes
; [@R1], R3 - pocet bcd bytes
; R4 - pocet bits
; casti //* lze zakomentovat pokud neni potreba zachovat obsah [@R0]

bin2bcd:call	clear1		; vymazani pameti vysledku
	push	0		;
	push	1		;
	push	2		;
	mov	A, R2		;
	mov	B, #8		;
	mul	AB		; pocet prevadenych bits
	mov	R4, A		;

b2bcd_0:call	rot_L		; ziskani horniho bitu z [@R0]	
	mov	cytmp, C	; ulozeni bitu CY pro obnovu	//*
	
	push	1		;
	push	3		;
b2bcd_2:mov	A, @R1		;
	addc	A, @R1		; [@R1] := [@R1] + [@R1] + CY 
	da	A		; BCD korekce
	mov	@R1, A		;
	inc	R1		;
	djnz	R3, b2bcd_2	; provest se vsemi BCD cislicemi
	pop	3		;
	pop	1		;

	mov	C, cytmp	; obnoveni CY			//*
	djnz	R4, b2bcd_0	;
	
	call	rot_L		;				//*
 	pop	2		;
	pop	1		;
	pop	0		;
	RET			;

;==========================================================	

; podprogram na prevod BCD->BIN [@R1] -> [@R0] ;   [@R0] := f( [@R1] )
; [@R1], R3 - pocet bcd bytes
; [@R0], R2 - pocet bin bytes
; adrm      - pomocna promenna

bcd2bin:call	clear0		; vymazani pameti vysledku
	push	0		;
	push	1		;
	push	2		;
	push	3		;	
	mov	A, R1		; vypocet vrsku BCD cisla
	add	A, R3		; zacina se nejvyssim radem
	mov	R1, A		;
	
b2bin_0:dec	R1		;
	push	3		;
	mov	R3, #100	; vynasobime x100
	push	1		;
	mov	R1, #adrm	; pom. prom. vypoctu
	call	mul8b		;
	pop	1		;
	pop	3		;
	
	call	clear0		; cil vynulovat
b2bin_1:mov	A, @R1		; pricteme [4Hi*10+4Lo] , 0-99
	swap	A		;
	anl	A, #0Fh		;
	mov	B, #10		;
	mul	AB		;
	mov	@R0, A		;
	mov	A, @R1		;
	anl	A, #0Fh		;
	add	A, @R0		;
	mov	@R0, A		;
	
	push	1		;
 	mov	R1, #adrm	;
 	call	addm		;
 	pop	1		;
	djnz	R3, b2bin_0	;
	
	pop	3		;
	pop	2		;
	pop	1		;
	pop	0		;
	RET			;

;==========================================================	

;	END