AVR Assembler Source Blog

Ремонт частотных преобразователей AVR Assembler Source Blog: BCD_Arithmetics_AVR204_appnote

Monday, October 7, 2013

BCD_Arithmetics_AVR204_appnote

починка частотного преобразователя
                              ;**** A P P L I C A T I O N   N O T E   A V R 2 0 4 ************************
                              ;*
                              ;* Title:  BCD Arithmetics
                              ;* Version:  1.1
                                                            ;* Last updated: 97.07.04
                              ;* Target:  AT90Sxxxx (All AVR Devices)
                              ;*
                              ;* Support E-mail: avr@atmel.com
                              ;* 

                              ;* DESCRIPTION
                              ;* This Application Note lists subroutines for the following Binary Coded
                              ;* Decimal arithmetic applications:
                              ;*
                              ;* Binary 16 to BCD Conversion (special considerations for AT90Sxx0x)
                              ;* Binary 8 to BCD Conversion
                              ;* BCD to Binary 16 Conversion
                              ;* BCD to Binary 8 Conversion
                              ;* 2-Digit BCD Addition
                              ;* 2-Digit BCD Subtraction
                              ;*

                              ;***************************************************************************


.include "8515def.inc"

 rjmp RESET                   ;reset handle

                              ;***************************************************************************
                              ;*
                              ;* "bin2BCD16" - 16-bit Binary to BCD conversion
                              ;*
                              ;* This subroutine converts a 16-bit number (fbinH:fbinL) to a 5-digit 
                              ;* packed BCD number represented by 3 bytes (tBCD2:tBCD1:tBCD0).
                              ;* MSD of the 5-digit number is placed in the lowermost nibble of tBCD2.
                              ;*  
                              ;* Number of words :25
                              ;* Number of cycles :751/768 (Min/Max)
                              ;* Low registers used :3 (tBCD0,tBCD1,tBCD2) 
                              ;* High registers used  :4(fbinL,fbinH,cnt16a,tmp16a) 
                              ;* Pointers used :Z
                              ;*
                              ;***************************************************************************

                              ;***** Subroutine Register Variables

.equ AtBCD0=13                ;address of tBCD0
.equ AtBCD2=15                ;address of tBCD1

.def tBCD0=r13                ;BCD value digits 1 and 0
.def tBCD1=r14                ;BCD value digits 3 and 2
.def tBCD2=r15                ;BCD value digit 4
.def fbinL=r16                ;binary value Low byte
.def fbinH=r17                ;binary value High byte
.def cnt16a=r18               ;loop counter
.def tmp16a=r19               ;temporary value

                              ;***** Code

bin2BCD16:
       ldi cnt16a,16          ;Init loop counter 
       clr tBCD2              ;clear result (3 bytes)
       clr tBCD1  
       clr tBCD0  
       clr ZH                 ;clear ZH (not needed for AT90Sxx0x)
bBCDx_1:
       lsl fbinL              ;shift input value
       rol fbinH              ;through all bytes
       rol tBCD0               
       rol tBCD1
       rol tBCD2
       dec cnt16a             ;decrement loop counter
       brne bBCDx_2           ;if counter not zero
       ret                    ;return

bBCDx_2:
       ldi r30,AtBCD2+1       ;Z points to result MSB + 1
bBCDx_3:
       ld tmp16a,-Z           ;get (Z) with pre-decrement
                              ;----------------------------------------------------------------
                              ;For AT90Sxx0x, substitute the above line with:
                              ;
                              ; dec ZL
                              ; ld tmp16a,Z
                              ;
                              ;----------------------------------------------------------------
       subi tmp16a,-$03       ;add 0x03
       sbrc tmp16a,3          ;if bit 3 not clear
       st Z,tmp16a            ;store back
       ld tmp16a,Z            ;get (Z)
       subi tmp16a,-$30       ;add 0x30
       sbrc tmp16a,7          ;if bit 7 not clear
       st Z,tmp16a            ;store back
       cpi ZL,AtBCD0          ;done all three?
       brne bBCDx_3           ;loop again if not
       rjmp bBCDx_1  



                              ;***************************************************************************
                              ;*
                              ;* "bin2BCD8" - 8-bit Binary to BCD conversion
                              ;*
                              ;* This subroutine converts an 8-bit number (fbin) to a 2-digit 
                              ;* BCD number (tBCDH:tBCDL).
                              ;*  
                              ;* Number of words :6 + return
                              ;* Number of cycles :5/50 (Min/Max) + return
                              ;* Low registers used :None
                              ;* High registers used  :2 (fbin/tBCDL,tBCDH)
                              ;*
                              ;* Included in the code are lines to add/replace for packed BCD output. 
                              ;*
                              ;***************************************************************************

                              ;***** Subroutine Register Variables

.def fbin=r16                 ;8-bit binary value
.def tBCDL=r16                ;BCD result MSD
.def tBCDH=r17                ;BCD result LSD

                              ;***** Code

bin2bcd8:
       clr tBCDH              ;clear result MSD
bBCD8_1:
       subi fbin,10           ;input = input - 10
       brcs bBCD8_2           ;abort if carry set
       inc tBCDH              ;inc MSD
                              ;---------------------------------------------------------------------------
                              ;    ;Replace the above line with this one
                              ;    ;for packed BCD output    
                              ; subi tBCDH,-$10  ;tBCDH = tBCDH + 10
                              ;---------------------------------------------------------------------------
       rjmp bBCD8_1           ;loop again
bBCD8_2:
       subi fbin,-10          ;compensate extra subtraction
                              ;---------------------------------------------------------------------------
                              ;    ;Add this line for packed BCD output
                              ; add fbin,tBCDH 
                              ;--------------------------------------------------------------------------- 
       ret

                              ;***************************************************************************
                              ;*
                              ;* "BCD2bin16" - BCD to 16-Bit Binary Conversion
                              ;*
                              ;* This subroutine converts a 5-digit packed BCD number represented by 
                              ;* 3 bytes (fBCD2:fBCD1:fBCD0) to a 16-bit number (tbinH:tbinL).
                              ;* MSD of the 5-digit number must be placed in the lowermost nibble of fBCD2.
                              ;* 
                              ;* Let "abcde" denote the 5-digit number. The conversion is done by
                              ;* computing the formula: 10(10(10(10a+b)+c)+d)+e.
                              ;* The subroutine "mul10a"/"mul10b" does the multiply-and-add operation 
                              ;* which is repeated four times during the computation.
                              ;*  
                              ;* Number of words :30 
                              ;* Number of cycles :108 
                              ;* Low registers used :4 (copyL,copyH,mp10L/tbinL,mp10H/tbinH)
                              ;* High registers used  :4 (fBCD0,fBCD1,fBCD2,adder) 
                              ;*
                              ;***************************************************************************

                              ;***** "mul10a"/"mul10b" Subroutine Register Variables

.def copyL=r12                ;temporary register
.def copyH=r13                ;temporary register
.def mp10L=r14                ;Low byte of number to be multiplied by 10
.def mp10H=r15                ;High byte of number to be multiplied by 10
.def adder=r19                ;value to add after multiplication 

                              ;***** Code

mul10a:                       ;***** multiplies "mp10H:mp10L" with 10 and adds "adder" high nibble 
       swap adder
mul10b:                       ;***** multiplies "mp10H:mp10L" with 10 and adds "adder" low nibble 
       mov copyL,mp10L        ;make copy
       mov copyH,mp10H
       lsl mp10L              ;multiply original by 2
       rol mp10H
       lsl copyL              ;multiply copy by 2
       rol copyH  
       lsl copyL              ;multiply copy by 2 (4)
       rol copyH  
       lsl copyL              ;multiply copy by 2 (8)
       rol copyH  
       add mp10L,copyL        ;add copy to original
       adc mp10H,copyH 
       andi adder,0x0f        ;mask away upper nibble of adder
       add mp10L,adder        ;add lower nibble of adder
       brcc m10_1             ;if carry not cleared
       inc mp10H              ;inc high byte
m10_1: 
       ret 

                              ;***** Main Routine Register Variables

.def tbinL=r14                ;Low byte of binary result (same as mp10L)
.def tbinH=r15                ;High byte of binary result (same as mp10H)
.def fBCD0=r16                ;BCD value digits 1 and 0
.def fBCD1=r17                ;BCD value digits 2 and 3
.def fBCD2=r18                ;BCD value digit 5

                              ;***** Code

BCD2bin16:
       andi fBCD2,0x0f        ;mask away upper nibble of fBCD2
       clr mp10H  
       mov mp10L,fBCD2        ;mp10H:mp10L=a
       mov adder,fBCD1
       rcall mul10a           ;mp10H:mp10L=10a+b
       mov adder,fBCD1
       rcall mul10b           ;mp10H:mp10L=10(10a+b)+c
       mov adder,fBCD0  
       rcall mul10a           ;mp10H:mp10L=10(10(10a+b)+c)+d
       mov adder,fBCD0
       rcall mul10b           ;mp10H:mp10L=10(10(10(10a+b)+c)+d)+e
       ret

                              ;***************************************************************************
                              ;*
                              ;* "BCD2bin8" - BCD to 8-bit binary conversion
                              ;*
                              ;* This subroutine converts a 2-digit BCD number (fBCDH:fBCDL) to an 
                              ;* 8-bit number (tbin).
                              ;*  
                              ;* Number of words :4 + return
                              ;* Number of cycles :3/48 (Min/Max) + return
                              ;* Low registers used :None
                              ;* High registers used  :2 (tbin/fBCDL,fBCDH) 
                              ;*
                              ;* Modifications to make the routine accept a packed BCD number is indicated
                              ;* as comments in the code. If the modifications are used, fBCDH shall be
                              ;* loaded with the BCD number to convert prior to calling the routine.
                              ;*
                              ;***************************************************************************

                              ;***** Subroutine Register Variables

.def tbin=r16                 ;binary result
.def fBCDL=r16                ;lower digit of BCD input
.def fBCDH=r17                ;higher digit of BCD input

                              ;***** Code

BCD2bin8:
                              ;--------------------------------------------------------------------------
                              ;|    ;For packed BCD input, add these two lines
                              ;| mov tbin,fBCDH ;copy input to result
                              ;| andi tbin,$0f ;clear higher nibble of result
                              ;--------------------------------------------------------------------------

BCDb8_0:
       subi fBCDH,1           ;fBCDH = fBCDH - 1
       brcs BCDb8_1           ;if carry not set
                              ;--------------------------------------------------------------------------
                              ;|    ;For packed BCD input, replace the above
                              ;|    ;two lines with these.
                              ;| subi fBCDH,$10 ;MSD = MSD - 1
                              ;| brmi BCDb8_1  ;if Zero flag not set
                              ;--------------------------------------------------------------------------
       subi tbin,-10          ;    result = result + 10
       rjmp BCDb8_0           ;    loop again
BCDb8_1:
       ret                    ;else return

                              ;***************************************************************************
                              ;*
                              ;* "BCDadd" - 2-digit packed BCD addition
                              ;*
                              ;* This subroutine adds the two unsigned 2-digit BCD numbers 
                              ;* "BCD1" and "BCD2". The result is returned in "BCD1", and the overflow 
                              ;* carry in "BCD2".
                              ;*  
                              ;* Number of words :19
                              ;* Number of cycles :17/20 (Min/Max)
                              ;* Low registers used :None
                              ;* High registers used  :3 (BCD1,BCD2,tmpadd) 
                              ;*
                              ;***************************************************************************

                              ;***** Subroutine Register Variables

.def BCD1=r16                 ;BCD input value #1
.def BCD2=r17                 ;BCD input value #2
.def tmpadd=r18               ;temporary register

                              ;***** Code

BCDadd:
       ldi tmpadd,6           ;value to be added later
       add BCD1,BCD2          ;add the numbers binary
       clr BCD2               ;clear BCD carry
       brcc add_0             ;if carry not clear
       ldi BCD2,1             ;set BCD carry
add_0: 
       brhs add_1             ;if half carry not set
       add BCD1,tmpadd        ;add 6 to LSD
       brhs add_2             ;if half carry not set (LSD <= 9)
       subi BCD1,6            ;restore value
       rjmp add_2             ;else
add_1: 
       add BCD1,tmpadd        ;add 6 to LSD
add_2: 
       swap tmpadd
       add BCD1,tmpadd        ;add 6 to MSD
       brcs add_4             ;if carry not set (MSD <= 9)
       sbrs BCD2,0            ;if previous carry not set
       subi BCD1,$60          ;restore value 
add_3: 
       ret                    ;else
add_4: 
       ldi BCD2,1             ;set BCD carry
       ret


                              ;***************************************************************************
                              ;*
                              ;* "BCDsub" - 2-digit packed BCD subtraction
                              ;*
                              ;* This subroutine subtracts the two unsigned 2-digit BCD numbers 
                              ;* "BCDa" and "BCDb" (BCDa - BCDb). The result is returned in "BCDa", and 
                              ;* the underflow carry in "BCDb".
                              ;*  
                              ;* Number of words :13
                              ;* Number of cycles :12/17 (Min/Max)
                              ;* Low registers used :None
                              ;* High registers used  :2 (BCDa,BCDb) 
                              ;*
                              ;***************************************************************************

                              ;***** Subroutine Register Variables

.def BCDa=r16                 ;BCD input value #1
.def BCDb=r17                 ;BCD input value #2

                              ;***** Code

BCDsub:
       sub BCDa,BCDb          ;subtract the numbers binary
       clr BCDb
       brcc sub_0             ;if carry not clear
       ldi BCDb,1             ;store carry in BCDB1, bit 0
sub_0: 
       brhc sub_1             ;if half carry not clear
       subi BCDa,$06          ;LSD=LSD-6
sub_1: 
       sbrs BCDb,0            ;if previous carry not set
       ret                    ;return
       subi BCDa,$60          ;subtract 6 from MSD
       ldi BCDb,1             ;set underflow carry
       brcc sub_2             ;if carry not clear
       ldi BCDb,1             ;clear underflow carry 
sub_2: 
       ret   

                              ;****************************************************************************
                              ;*
                              ;* Test Program
                              ;*
                              ;* This program calls all the subroutines as an example of usage and to 
                              ;* verify correct operation.
                              ;*
                              ;****************************************************************************

                              ;***** Main Program Register variables

.def temp=r16                 ;temporary storage variable

                              ;***** Code

RESET:
       ldi temp,low(RAMEND)
       out SPL,temp
       ldi temp,high(RAMEND)
       out SPH,temp           ;init Stack Pointer (remove for AT90Sxx0x)

                              ;***** Convert 54,321 to 2.5-byte packed BCD format

       ldi fbinL,low(54321)
       ldi fbinH,high(54321)
       rcall bin2BCD16        ;result: tBCD2:tBCD1:tBCD0=$054321

                              ;***** Convert 55 to 2-byte BCD 

       ldi fbin,55
       rcall bin2BCD8         ;result: tBCDH:tBCDL=0505

                              ;***** Convert $065535 to a 16-bit binary number
       ldi fBCD2,$06
       ldi fBCD1,$55
       ldi fBCD0,$35
       rcall BCD2bin16        ;result: tbinH:tbinL=$ffff (65,535)

                              ;***** Convert $0403 (43) to an 8-bit binary number
       ldi fBCDL,3
       ldi fBCDH,4
       rcall BCD2bin8         ;result: tbin=$2b (43)

                              ;***** Add BCD numbers 51 and 79
       ldi BCD1,$51
       ldi BCD2,$79
       rcall BCDadd           ;result: BCD2:BCD1=$0130

                              ;***** Subtract BCD numbers 72 - 28
       ldi BCDa,$72
       ldi BCDb,$28
       rcall BCDsub           ;result: BCDb=$00 (positive result), BCDa=44

                              ;***** Subtract BCD numbers 0 - 90
       ldi BCDa,$00
       ldi BCDb,$90
       rcall BCDsub           ;result: BCDb=$01 (negative result), BCDa=10 



forever:
       rjmp forever

No comments:

Post a Comment