我想把无符号数字转换成一个68k asm格式的ascii字符串,我可以对单词范围内的一些字符进行转换:
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
上面的代码可以工作。它是展开的,可能可以打包成一个循环。然而,我真正想做的是把unsigned long转换成它们的ascii表示。但是,当然,divu只允许16位的字作为除数,所以divby#10000是可能的,但是divby#100000是不可能的。如何对unsigned long的32位数字范围进行转换呢?
2条答案
按热度按时间lokaqttq1#
我为一个街机重制版写了一个long到ascii的整数转换器。
实际上,您可以使用高达
(1<<16*10)-1
的DIVU,因为655359/10仍然适合16位(并且是65535)更进一步,将一个长数除以
10000
,6553590000 > 1<<32
也不能大于655359,所以结果将适合16位。然后继续进行你刚才得到的除法的余数,对下半部分做同样的操作。
如果
num = (1<<32)-1
(最大无符号值,又称$ffffffff
),num
除以10000
等于429496
,小于65536*10-1
,所以可以处理,余数也可以用同样的方法处理。这是我从我的游戏改编并测试过的一些代码。零填充看起来有点过,但你可能不需要它。
xqk2d5yq2#
您所展示的算法向前提取数字,例如,从高阶十进制数字开始,然后到低阶。
DIVU指令将32位被除数除以16位除数,得到16位商与16位余数。
所以,关键是要使用这个特性,在某种程度上,这意味着首先提取低位数字,这可以在标准的
itoa
中看到。与从最左到最右使用更小的10的幂不同,这对从右到左的每个数字使用10的除法和模数。
由于数字是按逆序生成的,因此有几种方法可以反转字符串,例如:
-(a0)
代替(a0)+
)。0
(零)数字填充缓冲区的剩余部分,或者,movmem
的等效操作以将其滑动到缓冲区的开头,或者,这种方法的一个优点是,当商为0时,您可以提前停止,因为所有剩余的数字都将为零。
当然,
DIVU
的问题是,由于只捕获16位结果,因此大数在除以10时会产生溢出。在溢出情况下,由于目标寄存器保持不变,因此既得不到商也得不到余数。因此,这里有一个技巧,涉及到两个除法运算。x86版本见这里:Trying to Display a 32bit number in Assembly 8086 32bit
算法是这样的:
这种双除法安排适用于32位被除数和16位除数,并且永远不会溢出16位结果。
这将很容易地转换为68 k,因为所有需要的操作符都在那里。
由于
DIVU
同时产生商和余数,并且两者都需要,在68 k中这总共只需要两个DIVU。