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