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 $70 ; variable used for context saving status_temp equ $71 ; 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 $000 ; processor reset vector ;*** WARNING: PCLATH register bits are in STATUS PAx bits. Or use PAGE/IREAD if possible ; clrf PCLATH ; ensure page bits are cleared clr PCLATH ; ensure page bits are cleared jmp MAIN ; go to beginning of program org $004 ; interrupt vector location mov w_temp, W ; save off current W register contents mov W, STATUS ; move status register into W register mov status_temp, W ; save off contents of STATUS register ; isr code can go here or be located as a call subroutine elsewhere mov W, status_temp ; retrieve copy of STATUS register mov STATUS, W ; restore pre-isr STATUS register contents swap w_temp mov W, <>w_temp ; restore pre-isr W register contents ;*** WARNING: SX saves/restores W, STATUS, and FSR automatically. ; retfie ; return from interrupt reti ; 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! ;************************************ clr BitVars ; dp=1->dp=7(no dp), adds approx 50 cycles, i.e. dp=1 least cycles mov W, #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 mov DpPlacement, W mov W, #BYTE_OFFSET ; preset with ASCII offset mov OutPut, W mov OutPut+1, W mov OutPut+2, W mov OutPut+3, W mov OutPut+4, W mov OutPut+5, W clrb 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 ; mov W, #$47 ; mov Sample+2, W ; mov W, #$DB ; mov Sample+1, W ; mov W, #$12 ; mov Sample, W ; test number : -1235783 = 0xED24B9 - ok ! cycles approx: 311 -360 depending on dp placment ; Note ! This with TEST_SMALL_NUMBER, without deduct 10 cycles ; mov W, #$B9 ; mov Sample+2, W ; mov W, #$24 ; mov Sample+1, W ; mov W, #$ED ; mov Sample, W ; test number : 60900 = 0x00EDE4 - ok ! cycles approx: 315 -371 depending on dp placment ; Note ! This with TEST_SMALL_NUMBER, without add 63 cycles ; mov W, #$E4 ; mov Sample+2, W ; mov W, #$ED ; mov Sample+1, W ; mov W, #$00 ; mov Sample, W ; test number : -60900 = 0xFF121C - ok ! cycles approx: 325 -381 depending on dp placment ; Note ! This with TEST_SMALL_NUMBER, without add 56 cycles ; mov W, #$1C ; mov Sample+2, W ; mov W, #$12 ; mov Sample+1, W ; mov W, #$FF ; mov Sample, W ; test number : 231 = 0xE7 - ok !, cycles approx 244-302 depending on dp placement ; NOTE ! With TEST_SMALL_NUMBER, without add 62 cycles ; mov W, #$E7 ; mov Sample+2, W ; mov W, #$00 ; mov Sample+1, W ; mov W, #$00 ; mov Sample, W ; test number : -1 = 0xFFFFFF - ok !, cycles approx:262-326 depending on dp placement ; This with TEST_SMALL_NUMBER, without add 62 cycles ; ; mov W, #$FF ; mov Sample+2, W ; mov W, #$FF ; mov Sample+1, W ; mov W, #$FF ; mov Sample, W ; test number : 1048575 = 0x0FFFFF - ok !, cycles approx: 297-348 depending on dp placement ; this with TEST_SMALL_NUMBER, without add 8 cycles ; mov W, #$FF ; mov Sample+2, W ; mov W, #$FF ; mov Sample+1, W ; mov W, #$0F ; mov Sample, W ; test number : 1000000 = 0x0F4240 - ok !, cycles approx: 291-350 depending on dp placement ; this with TEST_SMALL_NUMBER, without add 8 cycles ; mov W, #$40 ; mov Sample+2, W ; mov W, #$42 ; mov Sample+1, W ; mov W, #$0F ; mov Sample, W ; test number : 8388607 = 0x7FFFFF - ok !, cycles approx: 394-445 depending on dp placement ; this with TEST_SMALL_NUMBER, without add 8 cycles ; mov W, #$FF ; mov Sample+2, W ; mov W, #$FF ; mov Sample+1, W ; mov W, #$7F ; mov Sample, W ; test number : -7099999 = 0x93A9A1 - ok !, cycles approx:429-480 depending on dp placement ; this with TEST_SMALL_NUMBER, without add 8 cycles mov W, #$A1 mov Sample+2, W mov W, #$A9 mov Sample+1, W mov W, #$93 mov Sample, W TEST_NEGATIVE sb Sample.7 ; test if negative IFDEF TEST_SMALL_NUMBER jmp TEST_TOPNIBBLE ; nope ELSE jmp SUB4M ; nope ENDIF ; sample is negative ; make two's complement not Sample+2 not Sample+1 not Sample mov W, #1 add Sample+2, W snb C add Sample+1, W snb C add Sample, W mov W, #SIGN_NEGATIVE mov OutPut, W ; 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 mov W, Sample and W, #$70 ; Mask out top three bits ;*** WARNING: MPASM macro BNZ is not supported yet. Replace manually. BNZ SUB4M ; nope do full conversion ; this digit is zero, and dp is not yet set ; then downshift to space setb _PrevIsSpace clrb OutPut+1.4 jmp SUB300k ; continue ENDIF ; TEST_SMALL_NUMBER SUB4M: ; subtract 4 million from sample mov W, #4 add OutPut+1, W mov W, #low(4000000) sub Sample+2, W mov W, #low(4000000> ;>8) sb C mov W, #low(4000000> ;>8)+1 sub Sample+1, W mov W, #low(4000000> ;>16) sb C mov W, #low(4000000> ;>16) + 1 sub Sample, W snb C ; overflow, i.e. negative jmp SUB4M ADD1M: ; add 1 million to sample dec OutPut+1 mov W, #low(1000000) add Sample+2, W mov W, #low(1000000> ;>8) snb C mov W, #low(1000000> ;>8) + 1 add Sample+1, W mov W, #low(1000000> ;>16) snb C mov W, #low(1000000> ;>16) + 1 add Sample, W sb C ; done ? jmp ADD1M ; test for leading zeroes mov W, #BYTE_OFFSET mov W, OutPut+1-w ;*** WARNING: MPASM macro BNZ is not supported yet. Replace manually. BNZ SUB300k ; this digit is zero, and dp is not yet set ; then downshift to space setb _PrevIsSpace clrb OutPut+1.4 SUB300k: ; substract 300 thousand from sample mov W, #3 add OutPut+3, W mov W, #low(300000) sub Sample+2, W mov W, #low(300000> ;>8) sb C mov W, #low(300000> ;>8)+1 sub Sample+1, W mov W, #low(300000> ;>16) sb C mov W, #low(300000> ;>16) + 1 sub Sample, W snb C jmp SUB300k ADD100k ; add 100 thousand to sample dec OutPut+3 mov W, #low(100000) add Sample+2, W mov W, #low(100000> ;>8) snb C mov W, #low(100000> ;>8) + 1 add Sample+1, W mov W, #low(100000> ;>16) snb C mov W, #low(100000> ;>16) + 1 add Sample, W sb C ; done jmp ADD100k IFDEF TEST_SMALL_NUMBER ; if this test enabled it is possible ; to have an overflow here ; test for overflow ( Output+3 = 10 ) mov W, #BYTE_OFFSET+$0A mov W, OutPut+3-w sb Z ; test if non zero jmp ADD100k_TstDp ; over flow, result is = 10, second digit = 1, third = 0 mov W, #BYTE_OFFSET mov OutPut+3, W sb _DpUsed ; test if dp already used setb OutPut+1.0 ; if no dp used set this digit to one setb OutPut+2.0 ; set also third digit to 1 ( in case dp is used ) ; restore previous digit sb _PrevIsSpace jmp ADD100k_TstDp setb OutPut+1.4 clrb _PrevIsSpace ENDIF ADD100k_TstDp: ; test for dp decsz DpPlacement ; test for dp placement jmp ADD100k_NoDp ; no dp yet ; place dp setb _DpUsed ; dp is used mov W, #DECIMAL_POINT ; mov OutPut+2, W ; dp is third digit ; restore zero before dp snb _PrevIsSpace setb OutPut+1.4 jmp SUB30k ; continue ADD100k_NoDp: ; no dp copy back number mov W, OutPut+3 mov OutPut+2, W ; test for leading zeroes mov W, #BYTE_OFFSET mov W, OutPut+2-w sb Z clrb _PrevIsSpace ;*** WARNING: MPASM macro BNZ is not supported yet. Replace manually. BNZ SUB30k sb _PrevIsSpace jmp SUB30k ; this digit is zero, and dp is not yet set ; then downshift to space setb _PrevIsSpace clrb OutPut+2.4 SUB30k: ; subtract 30'000 from sample mov W, #3 add OutPut+4, W mov W, #low(30000) sub Sample+2, W mov W, #low(30000> ;>8) sb C mov W, #low(30000> ;>8)+1 sub Sample+1, W mov W, #low(30000> ;>16) sb C mov W, #low(30000> ;>16) + 1 sub Sample, W snb C ; negative ? jmp SUB30k ADD10k: ; add 10'000 to sample dec OutPut+4 mov W, #low(10000) add Sample+2, W mov W, #low(10000> ;>8) snb C mov W, #low(10000> ;>8) + 1 add Sample+1, W mov W, #low(10000> ;>16) snb C mov W, #low(10000> ;>16) + 1 add Sample, W sb C ; done ? jmp ADD10k snb _DpUsed jmp SUB3k ; dp is already used continue ; test for dp decsz DpPlacement ; test for dp placement jmp ADD10k_NoDp ; no dp yet ; place dp setb _DpUsed ; dp is used mov W, #DECIMAL_POINT ; mov OutPut+3, W ; dp is fourth digit ; restore zero before dp sb _PrevIsSpace setb OutPut+2.4 jmp SUB3k ; continue ADD10k_NoDp: ; no dp copy back number mov W, OutPut+4 mov OutPut+3, W ; test for leading zeroes mov W, #BYTE_OFFSET mov W, OutPut+3-w sb Z clrb _PrevIsSpace ;*** WARNING: MPASM macro BNZ is not supported yet. Replace manually. BNZ SUB3k sb _PrevIsSpace jmp SUB3k ; this digit is zero, and dp is not yet set ; then downshift to space setb _PrevIsSpace clrb OutPut+3.4 SUB3k: ; subtract 3000 from sample mov W, #3 add OutPut+5, W mov W, #low(3000) sub Sample+2, W mov W, #low(3000> ;>8) sb C mov W, #low(3000> ;>8)+1 sub Sample+1, W snb C ; negative ? jmp SUB3k ADD1k: ; add 1000 to sample dec OutPut+5 mov W, #low(1000) add Sample+2, W mov W, #low(1000> ;>8) snb C mov W, #low(1000> ;>8) + 1 add Sample+1, W sb C jmp ADD1k snb _DpUsed jmp SUB300_PreLoad ; dp is already used continue ; test for dp decsz DpPlacement ; test for dp placement jmp ADD1k_NoDp ; no dp yet ; place dp setb _DpUsed ; dp is used mov W, #DECIMAL_POINT ; mov OutPut+4, W ; dp is fifth digit ; restore zero before dp snb _PrevIsSpace setb OutPut+3.4 jmp SUB300_PreLoad ; continue ADD1k_NoDp: ; no dp copy back number mov W, OutPut+5 mov OutPut+4, W ; test for leading zeroes mov W, #BYTE_OFFSET mov W, OutPut+4-w sb Z clrb _PrevIsSpace ;*** WARNING: MPASM macro BNZ is not supported yet. Replace manually. BNZ SUB300_PreLoad sb _PrevIsSpace jmp SUB300_PreLoad ; this digit is zero, and dp is not yet set ; then downshift to space setb _PrevIsSpace clrb OutPut+4.4 SUB300_PreLoad mov W, #BYTE_OFFSET mov OutPut+6, W SUB300: ; subtract 300 from sample mov W, #3 add OutPut+6, W mov W, #low(300) sub Sample+2, W mov W, #low(300> ;>8) sb C mov W, #low(300> ;>8)+1 sub Sample+1, W snb C ; negative ? jmp SUB300 mov W, #100 ADD100: ; add 100 to sample dec OutPut+6 add Sample+2, W sb C jmp ADD100 inc Sample+1 snb Sample+1.7 jmp ADD100 snb _DpUsed jmp SUB30_PreLoad ; dp is already used continue ; test for dp decsz DpPlacement ; test for dp placement jmp ADD100_NoDp ; no dp yet ; place dp setb _DpUsed ; dp is used mov W, #DECIMAL_POINT ; mov OutPut+5, W ; dp is sixth digit ; restore zero before dp snb _PrevIsSpace setb OutPut+4.4 jmp SUB30_PreLoad ; continue ADD100_NoDp: ; no dp copy back number mov W, OutPut+6 mov OutPut+5, W ; test for leading zeroes mov W, #BYTE_OFFSET mov W, OutPut+5-w sb Z clrb _PrevIsSpace ;*** WARNING: MPASM macro BNZ is not supported yet. Replace manually. BNZ SUB30_PreLoad sb _PrevIsSpace jmp SUB30_PreLoad ; this digit is zero, and dp is not yet set ; then downshift to space setb _PrevIsSpace clrb OutPut+5.4 SUB30_PreLoad: mov W, #30 SUB30: ; subtract 30 from sample inc OutPut+7 sub Sample+2, W snb C jmp SUB30 mov W, OutPut+7 rl OutPut+7 add OutPut+7, W mov W, #10 ADD10: ; add 10 to sample dec OutPut+7 add Sample+2, W sb C jmp ADD10 mov W, #BYTE_OFFSET add OutPut+7, W snb _DpUsed jmp LAST_DIGIT ; dp is already used continue ; test for dp decsz DpPlacement ; test for dp placement jmp ADD10_NoDp ; no dp yet ; place dp setb _DpUsed ; dp is used mov W, #DECIMAL_POINT ; mov OutPut+6, W ; dp is seventh digit ; restore zero before dp snb _PrevIsSpace setb OutPut+5.4 jmp LAST_DIGIT ; continue ADD10_NoDp ; no dp copy back number mov W, OutPut+7 mov OutPut+6, W ; test for leading zeroes mov W, #BYTE_OFFSET mov W, OutPut+6-w ;*** WARNING: MPASM macro BNZ is not supported yet. Replace manually. BNZ LAST_DIGIT sb _PrevIsSpace jmp LAST_DIGIT ; this digit is zero, and dp is not yet set ; then downshift to space setb _PrevIsSpace clrb OutPut+6.4 LAST_DIGIT: mov W, #BYTE_OFFSET add W, Sample+2 mov Sample+2, W sb _DpUsed mov OutPut+7, W ; save in previous byte snb _DpUsed jmp END_CONV decsz DpPlacement ; test for dp placement jmp CLEAR_LAST ; no dp used at all ?? mov W, #DECIMAL_POINT ; mov OutPut+7, W ; dp is eigth digit ; restore zero before dp snb _PrevIsSpace setb OutPut+6.4 jmp END_CONV CLEAR_LAST: ; no dp used copy back number, and clear last digit sb _DpUsed clr OutPut+8 ; clear last digit no dp used END_CONV nop ; done :-) jmp MAIN END ; directive 'end of program'