from Tony Kübek tony.kubek at flintab.com
...it's for 24 bit signed variable, then I cannot output a variable at a time ( supposed to go inside an int handler ), therefore I'm using a 9 byte string to store the result, furthermore for the decimal point and supressing of leading zeroes I needed 1 byte and 2 bit variables. ... Its a bit of 'bloatware', requires about 290 ! instructions but thats efficient enough for me, I might get back to hammer on it when I've finished off the other bits I'm starting with now. I think it goes around 480 instruction executed worst case, and all the way down to 250 something for best case. Also I added a minor conditional that makes execution a tad faster for 20 bit numbers ( as my app will have about 99 % in this range ) to the expence of more code and additional execution for larger numbers.
;********************************************************************** ; This file is a basic code template for assembly code generation * ; on the PICmicro PIC16F877. This file contains the basic code * ; building blocks to build upon. * ; * ; If interrupts are not used all code presented between the ORG * ; 0x004 directive and the label main can be removed. In addition * ; the variable assignments for 'w_temp' and 'status_temp' can * ; be removed. * ; * ; Refer to the MPASM User's Guide for additional information on * ; features of the assembler (Document DS33014). * ; * ; Refer to the respective PICmicro data sheet for additional * ; information on the instruction set. * ; * ; Template file assembled with MPLAB V4.00 and MPASM V2.20.00. * ; * ;********************************************************************** ; * ; Filename: MathTest.asm 24bit signed binary->ASCII w. dp * ; Date: 2000-03-31 * ; File Version: 0.1B * ; * ; Author: Tony Kübek * ; Company: * ; * ; * ;********************************************************************** ; * ; Files required: * ; * ; * ; * ;********************************************************************** ; * ; Notes: Tests of binary to ASCII coversion * ; Routines from techref.massmind.org * ; Originators(16bit): Scott Dattalo and Nikolai Golovchenko* ; Routine takes 24 bit signed binary number and coverts to * ; 8/9 byte ASCII(true!) decimal string with decimal point * ; and minus sign as the first byte ( if negative ). * ; 24 bit variabel is stored in last three string bytes * ; These are 'destroyed' during processing * ; Leading zeroes are surpressed (conv. to space) * ; Resources needed: * ; DpPlacement 1 byte + 1 bit * ; PrevIsChar 1 bit ,prev. zero was surpressed* ; ASCII string of 9 bytes * ;********************************************************************** list p=16f877 ; list directive to define processor #include <p16f877.inc> ; processor specific variable definitions __CONFIG _CP_OFF & _WDT_ON & _BODEN_ON & _PWRTE_ON & _RC_OSC & _WRT_ENABLE_ON & _LVP_OFF& _DEBUG_OFF & _CPD_OFF ; '__CONFIG' directive is used to embed configuration data within .asm file. ; The lables following the directive are located in the respective .inc file. ; See respective data sheet for additional information on configuration word. #define TEST_SMALL_NUMBER ; if defined then tests are performed ; to see number is less than +/-1048575 ( 20 bit ) ; makes routine a little faster for thoose numbers ; to the expence of more code ; and adds some cycles to all numbers above if used ; but can deduct upto 62 cycles on smaller numbers #define DECIMAL_POINT 0x2E ; '.' #define BYTE_OFFSET 0x30 ; start decimal ASCII numbers #define SIGN_NEGATIVE 0x2D ; '-' ;***** VARIABLE DEFINITIONS CBLOCK 0x20 ; start userram bank 0 BitVars:1 ; used for dp-bit variable OutPut:9 ; 8 used if no dp, else 9 DpPlacement:1 ; where to put dp, counted from start, min=1 ; note an added bonus here ! as this var is ; located directly after the string and will ; 'always' be = 0x00(after conversion), ; you have an 'free' null terminator ENDC w_temp EQU 0x70 ; variable used for context saving status_temp EQU 0x71 ; variable used for context saving #define _DpUsed BitVars,0 ; decimal point has been placed #define _PrevIsSpace BitVars,1 ; previous byte/digit is 'converted' to space #define Sample OutPut+6 ; Note !! to save ram, 24 bit variable is stored ; in highest three byte in 9 byte string ;********************************************************************** ORG 0x000 ; processor reset vector clrf PCLATH ; ensure page bits are cleared goto MAIN ; go to beginning of program ORG 0x004 ; interrupt vector location movwf w_temp ; save off current W register contents movf STATUS,w ; move status register into W register movwf status_temp ; save off contents of STATUS register ; isr code can go here or be located as a call subroutine elsewhere movf status_temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_temp,f swapf w_temp,w ; restore pre-isr W register contents retfie ; return from interrupt MAIN ;************************ Tony test 24 bit->8/9 digit ASCII with decimal point ; code with TEST_SMALL_NUMBER: (about)290 instructions ( excluding variable setup code ) ; ; True ASCII conversion, variable decimalpoint, surpress leading zeroes ; 24 bit variable is handled as SIGNED! ;************************************ CLRF BitVars ; dp=1->dp=7(no dp), adds approx 50 cycles, i.e. dp=1 least cycles MOVLW 1 ; note dp = 1 = between first and second digit ; dp = 7 between the last and second last digit ; if dp >= 7, dp = 0 then last digit is = 0x00 MOVWF DpPlacement MOVLW BYTE_OFFSET ; preset with ASCII offset MOVWF OutPut MOVWF OutPut+1 MOVWF OutPut+2 MOVWF OutPut+3 MOVWF OutPut+4 MOVWF OutPut+5 BCF OutPut,4 ; clear bit, makes first char 'space' ; OutPut+6 - OutPut+8 will contain 24 bit sample, LSB in OutPut+8 ; ** NOTE ** Sample = OutPut+6, Sample+1 = OutPut+7, Sample+2 = OutPut+8 ; Sample is defined as a separate name as it makes the code easier to read ; test number : 1235783 = 0x12DB47 - ok ! cycles approx: 301 -350 depending on dp placment ; Note ! This with TEST_SMALL_NUMBER, without deduct 10 cycles ; MOVLW 0x47 ; MOVWF Sample+2 ; MOVLW 0xDB ; MOVWF Sample+1 ; MOVLW 0x12 ; MOVWF Sample ; test number : -1235783 = 0xED24B9 - ok ! cycles approx: 311 -360 depending on dp placment ; Note ! This with TEST_SMALL_NUMBER, without deduct 10 cycles ; MOVLW 0xB9 ; MOVWF Sample+2 ; MOVLW 0x24 ; MOVWF Sample+1 ; MOVLW 0xED ; MOVWF Sample ; test number : 60900 = 0x00EDE4 - ok ! cycles approx: 315 -371 depending on dp placment ; Note ! This with TEST_SMALL_NUMBER, without add 63 cycles ; MOVLW 0xE4 ; MOVWF Sample+2 ; MOVLW 0xED ; MOVWF Sample+1 ; MOVLW 0x00 ; MOVWF Sample ; test number : -60900 = 0xFF121C - ok ! cycles approx: 325 -381 depending on dp placment ; Note ! This with TEST_SMALL_NUMBER, without add 56 cycles ; MOVLW 0x1C ; MOVWF Sample+2 ; MOVLW 0x12 ; MOVWF Sample+1 ; MOVLW 0xFF ; MOVWF Sample ; test number : 231 = 0xE7 - ok !, cycles approx 244-302 depending on dp placement ; NOTE ! With TEST_SMALL_NUMBER, without add 62 cycles ; MOVLW 0xE7 ; MOVWF Sample+2 ; MOVLW 0x00 ; MOVWF Sample+1 ; MOVLW 0x00 ; MOVWF Sample ; test number : -1 = 0xFFFFFF - ok !, cycles approx:262-326 depending on dp placement ; This with TEST_SMALL_NUMBER, without add 62 cycles ; ; MOVLW 0xFF ; MOVWF Sample+2 ; MOVLW 0xFF ; MOVWF Sample+1 ; MOVLW 0xFF ; MOVWF Sample ; test number : 1048575 = 0x0FFFFF - ok !, cycles approx: 297-348 depending on dp placement ; this with TEST_SMALL_NUMBER, without add 8 cycles ; MOVLW 0xFF ; MOVWF Sample+2 ; MOVLW 0xFF ; MOVWF Sample+1 ; MOVLW 0x0F ; MOVWF Sample ; test number : 1000000 = 0x0F4240 - ok !, cycles approx: 291-350 depending on dp placement ; this with TEST_SMALL_NUMBER, without add 8 cycles ; MOVLW 0x40 ; MOVWF Sample+2 ; MOVLW 0x42 ; MOVWF Sample+1 ; MOVLW 0x0F ; MOVWF Sample ; test number : 8388607 = 0x7FFFFF - ok !, cycles approx: 394-445 depending on dp placement ; this with TEST_SMALL_NUMBER, without add 8 cycles ; MOVLW 0xFF ; MOVWF Sample+2 ; MOVLW 0xFF ; MOVWF Sample+1 ; MOVLW 0x7F ; MOVWF Sample ; test number : -7099999 = 0x93A9A1 - ok !, cycles approx:429-480 depending on dp placement ; this with TEST_SMALL_NUMBER, without add 8 cycles MOVLW 0xA1 MOVWF Sample+2 MOVLW 0xA9 MOVWF Sample+1 MOVLW 0x93 MOVWF Sample TEST_NEGATIVE BTFSS Sample,7 ; test if negative IFDEF TEST_SMALL_NUMBER GOTO TEST_TOPNIBBLE ; nope ELSE GOTO SUB4M ; nope ENDIF ; sample is negative ; make two's complement COMF Sample+2,F COMF Sample+1,F COMF Sample,F MOVLW 1 ADDWF Sample+2,F SKPNC ADDWF Sample+1,F SKPNC ADDWF Sample,F MOVLW SIGN_NEGATIVE MOVWF OutPut ; first digit minus sign IFDEF TEST_SMALL_NUMBER ; test for small numbers and skips some loops ; use if number is often in 0-1048575 range ( negative or not) ; i.e. 0x000000 - 0x0FFFFF ( 2.5 bytes 20 bits ) TEST_TOPNIBBLE ; test if top nibble is zero, i.e. number less than 1048575 ( decimal ) ; if so we can skip to sub300k routine MOVF Sample,w ANDLW 0x70 ; Mask out top three bits BNZ SUB4M ; nope do full conversion ; this digit is zero, and dp is not yet set ; then downshift to space BSF _PrevIsSpace BCF OutPut+1,4 GOTO SUB300k ; continue ENDIF ; TEST_SMALL_NUMBER SUB4M: ; subtract 4 million from sample MOVLW 4 ADDWF OutPut+1, f MOVLW low(4000000) SUBWF Sample+2, f MOVLW low(4000000>>8) SKPC MOVLW low(4000000>>8)+1 SUBWF Sample+1, f MOVLW low(4000000>>16) SKPC MOVLW low(4000000>>16) + 1 SUBWF Sample, f SKPNC ; overflow, i.e. negative GOTO SUB4M ADD1M: ; add 1 million to sample DECF OutPut+1, f MOVLW low(1000000) ADDWF Sample+2, f MOVLW low(1000000>>8) SKPNC MOVLW low(1000000>>8) + 1 ADDWF Sample+1, f MOVLW low(1000000>>16) SKPNC MOVLW low(1000000>>16) + 1 ADDWF Sample, f SKPC ; done ? GOTO ADD1M ; test for leading zeroes MOVLW BYTE_OFFSET SUBWF OutPut+1,w BNZ SUB300k ; this digit is zero, and dp is not yet set ; then downshift to space BSF _PrevIsSpace BCF OutPut+1,4 SUB300k: ; substract 300 thousand from sample MOVLW 3 ADDWF OutPut+3, f MOVLW low(300000) SUBWF Sample+2, f MOVLW low(300000>>8) SKPC MOVLW low(300000>>8)+1 SUBWF Sample+1, f MOVLW low(300000>>16) SKPC MOVLW low(300000>>16) + 1 SUBWF Sample, f SKPNC GOTO SUB300k ADD100k ; add 100 thousand to sample DECF OutPut+3, f MOVLW low(100000) ADDWF Sample+2, f MOVLW low(100000>>8) SKPNC MOVLW low(100000>>8) + 1 ADDWF Sample+1, f MOVLW low(100000>>16) SKPNC MOVLW low(100000>>16) + 1 ADDWF Sample, f SKPC ; done GOTO ADD100k IFDEF TEST_SMALL_NUMBER ; if this test enabled it is possible ; to have an overflow here ; test for overflow ( Output+3 = 10 ) MOVLW BYTE_OFFSET+0x0A SUBWF OutPut+3,W BTFSS STATUS,Z ; test if non zero GOTO ADD100k_TstDp ; over flow, result is = 10, second digit = 1, third = 0 MOVLW BYTE_OFFSET MOVWF OutPut+3 BTFSS _DpUsed ; test if dp already used BSF OutPut+1,0 ; if no dp used set this digit to one BSF OutPut+2,0 ; set also third digit to 1 ( in case dp is used ) ; restore previous digit BTFSS _PrevIsSpace GOTO ADD100k_TstDp BSF OutPut+1,4 BCF _PrevIsSpace ENDIF ADD100k_TstDp: ; test for dp DECFSZ DpPlacement,F ; test for dp placement GOTO ADD100k_NoDp ; no dp yet ; place dp BSF _DpUsed ; dp is used MOVLW DECIMAL_POINT ; MOVWF OutPut+2 ; dp is third digit ; restore zero before dp BTFSC _PrevIsSpace BSF OutPut+1,4 GOTO SUB30k ; continue ADD100k_NoDp: ; no dp copy back number MOVF OutPut+3,W MOVWF OutPut+2 ; test for leading zeroes MOVLW BYTE_OFFSET SUBWF OutPut+2,w BTFSS STATUS,Z BCF _PrevIsSpace BNZ SUB30k BTFSS _PrevIsSpace GOTO SUB30k ; this digit is zero, and dp is not yet set ; then downshift to space BSF _PrevIsSpace BCF OutPut+2,4 SUB30k: ; subtract 30'000 from sample MOVLW 3 ADDWF OutPut+4, f MOVLW low(30000) SUBWF Sample+2, f MOVLW low(30000>>8) SKPC MOVLW low(30000>>8)+1 SUBWF Sample+1, f MOVLW low(30000>>16) SKPC MOVLW low(30000>>16) + 1 SUBWF Sample, f SKPNC ; negative ? GOTO SUB30k ADD10k: ; add 10'000 to sample DECF OutPut+4, f MOVLW low(10000) ADDWF Sample+2, f MOVLW low(10000>>8) SKPNC MOVLW low(10000>>8) + 1 ADDWF Sample+1, f MOVLW low(10000>>16) SKPNC MOVLW low(10000>>16) + 1 ADDWF Sample, f SKPC ; done ? GOTO ADD10k BTFSC _DpUsed GOTO SUB3k ; dp is already used continue ; test for dp DECFSZ DpPlacement,F ; test for dp placement GOTO ADD10k_NoDp ; no dp yet ; place dp BSF _DpUsed ; dp is used MOVLW DECIMAL_POINT ; MOVWF OutPut+3 ; dp is fourth digit ; restore zero before dp BTFSS _PrevIsSpace BSF OutPut+2,4 GOTO SUB3k ; continue ADD10k_NoDp: ; no dp copy back number MOVF OutPut+4,W MOVWF OutPut+3 ; test for leading zeroes MOVLW BYTE_OFFSET SUBWF OutPut+3,w BTFSS STATUS,Z BCF _PrevIsSpace BNZ SUB3k BTFSS _PrevIsSpace GOTO SUB3k ; this digit is zero, and dp is not yet set ; then downshift to space BSF _PrevIsSpace BCF OutPut+3,4 SUB3k: ; subtract 3000 from sample MOVLW 3 ADDWF OutPut+5, f MOVLW low(3000) SUBWF Sample+2, f MOVLW low(3000>>8) SKPC MOVLW low(3000>>8)+1 SUBWF Sample+1, f SKPNC ; negative ? GOTO SUB3k ADD1k: ; add 1000 to sample DECF OutPut+5, f MOVLW low(1000) ADDWF Sample+2, f MOVLW low(1000>>8) SKPNC MOVLW low(1000>>8) + 1 ADDWF Sample+1, f SKPC GOTO ADD1k BTFSC _DpUsed GOTO SUB300_PreLoad ; dp is already used continue ; test for dp DECFSZ DpPlacement,F ; test for dp placement GOTO ADD1k_NoDp ; no dp yet ; place dp BSF _DpUsed ; dp is used MOVLW DECIMAL_POINT ; MOVWF OutPut+4 ; dp is fifth digit ; restore zero before dp BTFSC _PrevIsSpace BSF OutPut+3,4 GOTO SUB300_PreLoad ; continue ADD1k_NoDp: ; no dp copy back number MOVF OutPut+5,W MOVWF OutPut+4 ; test for leading zeroes MOVLW BYTE_OFFSET SUBWF OutPut+4,w BTFSS STATUS,Z BCF _PrevIsSpace BNZ SUB300_PreLoad BTFSS _PrevIsSpace GOTO SUB300_PreLoad ; this digit is zero, and dp is not yet set ; then downshift to space BSF _PrevIsSpace BCF OutPut+4,4 SUB300_PreLoad MOVLW BYTE_OFFSET MOVWF OutPut+6 SUB300: ; subtract 300 from sample MOVLW 3 ADDWF OutPut+6, f MOVLW low(300) SUBWF Sample+2, f MOVLW low(300>>8) SKPC MOVLW low(300>>8)+1 SUBWF Sample+1, f SKPNC ; negative ? GOTO SUB300 MOVLW 100 ADD100: ; add 100 to sample DECF OutPut+6, f ADDWF Sample+2, f SKPC GOTO ADD100 INCF Sample+1, f BTFSC Sample+1, 7 GOTO ADD100 BTFSC _DpUsed GOTO SUB30_PreLoad ; dp is already used continue ; test for dp DECFSZ DpPlacement,F ; test for dp placement GOTO ADD100_NoDp ; no dp yet ; place dp BSF _DpUsed ; dp is used MOVLW DECIMAL_POINT ; MOVWF OutPut+5 ; dp is sixth digit ; restore zero before dp BTFSC _PrevIsSpace BSF OutPut+4,4 GOTO SUB30_PreLoad ; continue ADD100_NoDp: ; no dp copy back number MOVF OutPut+6,W MOVWF OutPut+5 ; test for leading zeroes MOVLW BYTE_OFFSET SUBWF OutPut+5,w BTFSS STATUS,Z BCF _PrevIsSpace BNZ SUB30_PreLoad BTFSS _PrevIsSpace GOTO SUB30_PreLoad ; this digit is zero, and dp is not yet set ; then downshift to space BSF _PrevIsSpace BCF OutPut+5,4 SUB30_PreLoad: MOVLW 30 SUB30: ; subtract 30 from sample INCF OutPut+7, f SUBWF Sample+2, f SKPNC GOTO SUB30 MOVFW OutPut+7 RLF OutPut+7, f ADDWF OutPut+7, f MOVLW 10 ADD10: ; add 10 to sample DECF OutPut+7, f ADDWF Sample+2, f SKPC GOTO ADD10 MOVLW BYTE_OFFSET ADDWF OutPut+7,f BTFSC _DpUsed GOTO LAST_DIGIT ; dp is already used continue ; test for dp DECFSZ DpPlacement,F ; test for dp placement GOTO ADD10_NoDp ; no dp yet ; place dp BSF _DpUsed ; dp is used MOVLW DECIMAL_POINT ; MOVWF OutPut+6 ; dp is seventh digit ; restore zero before dp BTFSC _PrevIsSpace BSF OutPut+5,4 GOTO LAST_DIGIT ; continue ADD10_NoDp ; no dp copy back number MOVF OutPut+7,W MOVWF OutPut+6 ; test for leading zeroes MOVLW BYTE_OFFSET SUBWF OutPut+6,w BNZ LAST_DIGIT BTFSS _PrevIsSpace GOTO LAST_DIGIT ; this digit is zero, and dp is not yet set ; then downshift to space BSF _PrevIsSpace BCF OutPut+6,4 LAST_DIGIT: MOVLW BYTE_OFFSET ADDWF Sample+2,w MOVWF Sample+2 BTFSS _DpUsed MOVWF OutPut+7 ; save in previous byte BTFSC _DpUsed GOTO END_CONV DECFSZ DpPlacement,F ; test for dp placement GOTO CLEAR_LAST ; no dp used at all ?? MOVLW DECIMAL_POINT ; MOVWF OutPut+7 ; dp is eigth digit ; restore zero before dp BTFSC _PrevIsSpace BSF OutPut+6,4 GOTO END_CONV CLEAR_LAST: ; no dp used copy back number, and clear last digit BTFSS _DpUsed CLRF OutPut+8 ; clear last digit no dp used END_CONV NOP ; done :-) GOTO MAIN END ; directive 'end of program'