; Bináris BCD konvertáló funkció pic mikrovezérlokhöz
; Készítette:feki00 2ezer9 augusztus 15, optimalizálta: mateakos 2ezer9 augusztus 16
; eddig kipróbálva: 16F877, 16F877a (MPLAB SIM szimulátorban)
; Változtatható hosszúságú bináris számot alakítunk BCD számmá
; A módszer leírása a következo cím alatt található:
; http://www.engr.udayton.edu/faculty/jloomis/ece314/notes/devices/binary_to_BCD/bin_to_BCD.html
; magyarul: A bináris érték utolsó bitjét betoljuk a bcd regiszter
; elso bitjébe(1), ha ez volt az utolsó bináris szám akkor a bcd regiszter
; tartalmazza a kész konvertált bcd értéket, ha nem akkor továbblépünk: 
; Ha a bcd regiszter egy egy nibbleje nagyobb mint 5
; akkor hozzáadunk a nibblehez 3at, ha ezzel végeztünk akkor
; ugrunk az elejére(1)

; A bcd regiszter a tizes számrendszer helyi értékei szerint csökkenve 
; tartalmazza az értékeket egy egy nibbleben.

;	   bájt		|      bájt	 	 |    bájt	  |  bájt  |
;...(REG_X+N)...|   (REG_X+2)    | (REG_X+1)  |(REG_X) |
;... (BCD+N)....|    (BCD+2)     |  (BCD+1)   | (BCD)  |
;helyiértékek:	| 100000 | 10000 | 1000 | 100 | 10 | 1 |

;A több bájtos konverzió ötletét ez a nagyon hasznos oldal adta:
;http://avtanski.net/projects/math/ 
;A kódban fel lett használva belole pár változó és
;rutin  is (M_CLR) 

	list        p=16f877a   ; list directive to define processor
    #include    <p16f877a.inc>  ; processor specific variable definitions
    
    __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _RC_OSC & _WRT_OFF & _LVP_ON & _CPD_OFF

PRECISION	EQU	4	;Hány bájtos a bináris érték

    cblock 0x20

	REG_X:PRECISION		;konvertálandó bináris érték
	;REG_X és BCD között (azaz itt) nem szabad rekisztert deklarálni, mert egymás mellett kell maradniuk
	BCD:PRECISION*2		; A bcd konvertálóhoz plusszban
    REG_Y:PRECISION		;segéd regiszter
    REG_COUNTER			 
    REG_STATUS			
    REG_T1				
    REG_T2				

;A keletkezett BCD érték hosszabb mint a bináris amibol
;konvertálunk, 2szer negyobb regiszter boven elég lesz.
;Azt hogy hány helyiérttékkel no a decimális szám egy egy bit
;hozzáadásával sajnos nem tudom.
	BCD_COUNTER			;szükséges regiszterek
	BCD_T1
    endc

	org 0
	goto start

M_INC:						; bináris érték növeléséhez kell
    movwf   FSR				; csak a bemutatás kedvért van rá
    movlw   PRECISION		; szükség, a konvertáláshoz nem kell
    movwf   REG_COUNTER		
M_INC_loop:
    incfsz	INDF,f
    return
    incf	FSR,f
    decfsz	REG_COUNTER,f
    goto	M_INC_loop
    return

M_BCD:						; REG_X bol konvertál a BCD be
	movlw	BCD
; bcd regiszter törlése
    movwf   FSR
    movlw   PRECISION*2
    movwf   REG_COUNTER
M_CLR_loop:
    clrf    INDF
    incf    FSR,f
    decfsz	REG_COUNTER,f
    goto    M_CLR_loop
    
	movlw 	8*PRECISION	; 1bájt=8bit, a shifteléshez kell
	movwf 	REG_T1		;shiftelések száma

M_BCD_loop:
							;eltoljuk a BCD regisztert 1el balra
	bcf 	STATUS,C		;carry=0 biztonság képpen
	movlw 	REG_X			;w=REG_X címe
	movwf 	FSR				;FSR=BCD címe
	movlw 	PRECISION*2+PRECISION		;összesen ennyi bájtot kell shiftelni
							;REG_X és BCD egymás mellett vannak a memóriában, a REG_X-bol
							;kicsúszó bit BCD regiszterbe kerül
	movwf 	BCD_COUNTER		;beállítjuk hány bájt van
SHIFTBCD_loop:
	rlf 	INDF,f			; eltoljuk, a kitolt bit a carryba kerül
							; a betolt pedig a carryból jön
	incf 	FSR,f			; következo bytera mutatunk
	decfsz 	BCD_COUNTER,f	; számoljuk
	goto 	SHIFTBCD_loop	; van még ezért újra

	decfsz 	REG_T1,f		; csökkentjük a bitszmálálót
	goto 	ADD3			; megyünk a következo ciklusba
	return				; REG_X végére értünk a konverziót befejeztük

ADD3:				;3at adunk a nibblehez ha több mint 5
	movlw 	PRECISION*2	;becélozzuk a BCD regiszter elejét
	movwf 	REG_COUNTER	
	movlw 	BCD+PRECISION*2-1
	movwf 	FSR			;rámutatunk
ADD3_loop:			
	movf 	INDF,w			;kivesszük az értéket
	addlw 	.11				;hozzáadunk 11-et (16-5), ha az alsó 4 bit nagyobb vagy egyenlo volt mint 5
							;akkor az összeadás miatt digitcarry=1
	btfss	STATUS,DC		;ha digitcarry=1 akkor kihagyjuk a következo utasítást
	goto 	$+4				;4sort ugrunk mert 5nél kisebb
	movf 	INDF,w			;kivesszük
	addlw 	3				;hozzáadunk 3at
	movwf 	INDF			;visszatesszük a növelt értéket
	;ha nem volt digitcarry, akkor a felso nibble sértetlen (nem kell INDF-et újra w-be tölteni)
	;ha meg volt digitcarry, akkor épp most mentettük w-t INDF-be tehát ugyancsak fülösleges újra betölteni
	addlw 	0xB0			;hozzáadunk 0xB0-t (0x100-0x50)	(ha a felso nibble nagyobb vagy egyenlo volt mint 5, akkor carry=1)
	btfss	STATUS,C		;döntés
	goto 	$+3				;3sort ugrunk ha kisebb 5nél
	movlw 	0x30			
	addwf 	INDF,f			;3 hozzáadása a felso nibble-hez
;done count up
	decf 	FSR,f			;következo bájtra mutatunk
	decfsz 	REG_COUNTER,f	;következo byte
	goto 	ADD3_loop			;ha van még bájt, akkor vissza megyünk
	goto 	M_BCD_loop		; újraújraújra

start:
	movlw 	b'00000000'	; 0áról számolunk felfelé
	movwf 	REG_Y			; Y regiszterben számolunk
	movwf 	REG_Y+1		; mert a konverzió után az Xregiszter
	movwf 	REG_Y+2		; tartalma "megsemmisül"
	movwf 	REG_Y+3

loop:				
	movf 	REG_Y,w			;Y regisztert betesszük X be
	movwf 	REG_X
	movf 	REG_Y+1,w
	movwf 	REG_X+1
	movf 	REG_Y+2,w
	movwf 	REG_X+2
	movf 	REG_Y+3,w
	movwf 	REG_X+3
	call 	M_BCD			;varázslat
	movlw 	REG_Y			;Y címe
	call 	M_INC			; növeljük
	goto 	loop
	END