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.
Translated and optimized for the Scenix SX by Nikolai Golovchenko
;********************************************************************** ; * ; Filename: MathTest.asm 24bit signed binary->ASCII w. dp * ; Date: 2000-03-31 * ; File Version: 0.1B * ; * ; Author: Tony Kübek * ; Company: * ; * ; * ;********************************************************************** ; * ; 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 * ;********************************************************************** DEVICE SX28 RESET Start TEST_SMALL_NUMBER EQU 1 ; 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 DECIMAL_POINT EQU 0x2E ; '.' BYTE_OFFSET EQU 0x30 ; start decimal ASCII numbers SIGN_NEGATIVE EQU 0x2D ; '-' ORG $10 ; start userram bank 0 BitVars DS 1 ; used for dp-bit variable OutPut DS 9 ; 8 used if no dp, else 9 DpPlacement DS 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 _DpUsed EQU BitVars.0 ; decimal point has been placed _PrevIsSpace EQU BitVars.1 ; previous byte/digit is 'converted' to space Sample EQU OutPut+6 ; Note !! to save ram, 24 bit variable is stored ; in highest three byte in 9 byte string ; define constants to add/sub to the input number ; low/mid/high byte is relative to a 24 bit number ;LOW4M EQU 4000000 & $FF is zero! MID4M EQU (4000000 >> 8) & $FF HIGH4M EQU $3D ;(4000000 >> 16) & $FF LOW1M EQU 1000000 & $FF MID1M EQU (1000000 >> 8) & $FF HIGH1M EQU $0F ;(1000000 >> 16) & $FF LOW300K EQU 300000 & $FF MID300K EQU (300000 >> 8) & $FF HIGH300K EQU $04 ;(300000 >> 16) & $FF LOW100K EQU 100000 & $FF MID100K EQU (100000 >> 8) & $FF HIGH100K EQU $01 ;(100000 >> 16) & $FF LOW30K EQU 30000 & $FF MID30K EQU (30000 >> 8) & $FF LOW10K EQU 10000 & $FF MID10K EQU (10000 >> 8) & $FF LOW3K EQU 3000 & $FF MID3K EQU (3000 >> 8) & $FF LOW1K EQU 1000 & $FF MID1K EQU (1000 >> 8) & $FF LOW300 EQU 300 & $FF MID300 EQU (300 >> 8) & $FF ORG $0 Start ;************************ 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 IF TEST_SMALL_NUMBER == 1 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 IF TEST_SMALL_NUMBER == 1 ; 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 1048576 ( decimal ) ; if so we can skip to sub300k routine mov W, Sample and W, #$F0 ; Mask out top four bits sb Z jmp 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, #MID4M sb C mov W, #MID4M + 1 sub Sample+1, W mov W, #HIGH4M sb C mov W, #HIGH4M + 1 sub Sample, W snb C ; overflow, i.e. negative jmp SUB4M ADD1M: ; add 1 million to sample dec OutPut+1 mov W, #LOW1M add Sample+2, W mov W, #MID1M snb C mov W, #MID1M + 1 add Sample+1, W mov W, #HIGH1M snb C mov W, #HIGH1M + 1 add Sample, W sb C ; done ? jmp ADD1M ; test for leading zeroes mov W, #BYTE_OFFSET mov W, OutPut+1-w sb Z jmp 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, #LOW300K sub Sample+2, W mov W, #MID300K sb C mov W, #MID300K + 1 sub Sample+1, W mov W, #HIGH300K sb C mov W, #HIGH300K + 1 sub Sample, W snb C jmp SUB300k ADD100k ; add 100 thousand to sample dec OutPut+3 mov W, #LOW100K add Sample+2, W mov W, #MID100K snb C mov W, #MID100K + 1 add Sample+1, W mov W, #HIGH100K snb C mov W, #HIGH100K + 1 add Sample, W sb C ; done jmp ADD100k IF TEST_SMALL_NUMBER == 1 ; 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 sb Z jmp 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, #LOW30K sub Sample+2, W mov W, #MID30K sb C mov W, #MID30K + 1 sub Sample+1, W sb C dec Sample sb Sample.7 ; negative ? jmp SUB30k ADD10k: ; add 10'000 to sample dec OutPut+4 mov W, #LOW10K add Sample+2, W mov W, #MID10K snb C mov W, #MID10K + 1 add Sample+1, W snb C inc Sample snb Sample.7 ; 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 sb Z jmp 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, #LOW3K sub Sample+2, W mov W, #MID3K sb C mov W, #MID3K + 1 sub Sample+1, W snb C ; negative ? jmp SUB3k ADD1k: ; add 1000 to sample dec OutPut+5 mov W, #LOW1K add Sample+2, W mov W, #MID1K snb C mov W, #MID1K + 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 sb Z jmp 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, #LOW300 sub Sample+2, W mov W, #MID300 sb C mov W, #MID300 + 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 sb Z jmp 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 sb Z jmp 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 Start