I want to convert unsigned numbers to an ascii string in 68k asm. I can do this for something in the range of words:
move.w #12345,d0 ;example number to convert (unsigned word)
lea text,a0 ;adress of output string
;first digit
and.l #$ffff,d0 ;mask lower word
divu #10000,d0 ;calc 10k digit -> d0: remainder.result
add.w #$30,d0 ;convert d0 lowerword to ascii
move.b d0,(a0)+ ;write ascii byte to mem
;next digit
swap d0 ;continue with remainder
and.l #$ffff,d0
divu #1000,d0 ;calc 1k digit
add.w #$30,d0
move.b d0,(a0)+
;...and so on
The code above works. It is unrolled and probably could be packed into a loop. However, what I'd really like to do, is convert unsigned longs to their ascii representation. But, of course, divu will only allow a 16-bit word as divisor, so div by #10000 is possible, but div by #100000 is not. How can the conversion be done for the unsigned long 32bit number range?
The algorithm you're showing extracts the digits in forward direction, e.g. starting from higher order decimal digits and going to the lower order.
The DIVU instruction divides a 32-bit dividend value by a 16-bit divisor value, producing a 16-bit quotient and 16-bit remainder.
So, the key is to use that feature. In part, this means extracting the low order digits first. This can be seen in a standard
itoa.Instead of using ever smaller powers of 10 going leftmost to rightmost, this uses division and modulus by 10 for each digit going right to left.
Since the digits are being produced in reverse order, there are several approaches to reversing the string, such as:
-(a0)instead of(a0)+).0(zero) digits, or,movmemto slide it to the beginning of the buffer, or,An advantage of this approach is that you can stop early, when the quotient is 0, since all remaining digits will be zero.
The problem with
DIVU, of course is that large numbers will produce overflow in division by 10, since only 16-bit result is captured. In an overflow situation, you get neither the quotient nor the remainder as the destination register remains unmodified..So, there is a trick to this, involving two division operations. See here for the x86 version: Trying to Display a 32bit number in Assembly 8086 32bit
The algorithm goes something like this:
This arrangement of dual divisions works with 32-bit dividend and 16-bit divisor, and will never overflow a 16-bit result.
This will translate to 68k pretty easily, as all the needed operators are there.
Since
DIVUproduces both quotient and remainder and both are needed together, in 68k this will only require two DIVU's in total.