繁体   English   中英

将二进制数转换为4个BCD数字-除法如何工作?

[英]Converting a Binary number to 4 BCD digits - how does division work?

我正在研究Motorola 68000 CPU的组件。 我使用的书是:
68000汇编语言编程,第二版,Leventhal,Hawkins,Kane,Cramer
EASy68k模拟器。

我对将二进制数转换为BCD(二进制编码的十进制)有一些疑问。
书中最初的问题是:“将内存位置6000的变量NUMBER的内容转换为位置6002的变量STRING中的四个BCD数字(6002中的最高有效数字)。NUMBER中的16位数字是无符号的,并且更少超过10,000。”

例:

 input:  NUMBER - (6000) = 1C52
 output: STRING - (6002) = 07
                  (6003) = 02
                  (6004) = 05
                  (6005) = 00

因为1C52(十六进制)= 7250(十进制)(MC68k是大端CPU)

由于MC68k是一款出色的CISC CPU,具有丰富的指令库,因此编写解决方案并不难:

DATA:       EQU $6000
PROGRAM:    EQU $4000

        ORG DATA

NUMBER:     DS.W 1
STRING:     DS.L 1

        ORG PROGRAM

MAIN:       
        CLR.L D0                ; Clear D0               
        MOVE.W NUMBER, D0       ; Store our number (2 bytes) to D0      
        MOVEA.L #STRING+4, A0   ; We'll go backwards -> so we store the address of the last byte + 1 of the variable STRING to A0 (+1 because we use pre-decrement addressing)
        MOVEQ #1, D2            ; A counter which will cause (DBRA) two iterations of the LOOP part of the program        
        MOVE.L #$FFFF,D3        ; D3 is a mask used to clear the 2 most significant bytes of D0 in each iteration of LOOP       

LOOP:   DIVU.W #10, D0          ; Divide D0 by 10 (the result will be saved in the first 2 bytes od D0, and the remainder (our BCD digit) in the second two (more significant) two bytes of D0         
        MOVE.L D0, D1           ; Make a copy of D0         
        SWAP D1                 ; swap the first 16 bits of D0 with the second 16 bits of D0            
        MOVE.B D1,-(A0)         ; Now the first 16 bits of D1 contain the remainder (our BCD digit) which we will save to address -(A0)          
        AND.L D3, D0            ; Use the mask to clear the second half (16 bits) of D0 so that the next DIVU instruction doesn't by mistake take the remainder as a part of the number which needs to be divided      
        DBRA D2, LOOP           ; Decrement our counter D2 by 1 and go back to LOOP if D2 is not equal to -1

        DIVU #10, D0            ; This (last) division by 10 will cause our most significant BCD decimal to be at the lower 16 bits of D0 while the second most significant BCD decimal will be the remainder of the DIVU instruction and therefore stored at the higher 16 bits of D0          
        MOVE.B D0, -2(A0)       ; Save the most significant BCD digit       
        SWAP D0                 ; swap lower and higher 16 bits of D0         
        MOVE.B D0, -(A0)        ; Save second most significant BCD digit

        MOVE.B #9, D0
        TRAP #15

        END MAIN

DIVU = DIVision未签名

我对该解决方案感到满意,但我想更详细地了解/了解MC68k如何执行该除法(计算结果和余数)。 例如,如果我们想做相反的事情,即将BCD编号转换为二进制编号,则可以使用以下算法:让我们采用以下顺序:的'7','2','5','0' BCD数字,其中“ 7”是最高有效数字,“ 0”是最低有效数字。 如果我们想用这些数字的十进制数,我们可以这样做(伪代码):

number = 0;
number = number * 10 + 7   = 0 * 10 + 7 = 0 + 7 = 7 
number = number * 10 + 2   = 7 * 10 + 2 = 70 + 2 = 72 
number = number * 10 + 5   = 72 * 10 + 5 = 720 + 5 = 725  
number = number * 10 + 0   = 725 * 10 + 0 = 7250 + 0 = 7250  

但是,当然,我们需要调整以2为底的数字的乘法。MC68k提供或多或少的2种方法:

  1. 像“ MULU#10,D1”这样的乘法助记符,将简单地产生一个数字乘以10
  2. 或一组简单的指令组成:

     ADD.W D1, D1 ; D1 = D1 + D1 = 2x MOVE.W D1, D3 LSL.W #2, D3 ; D3 = 8x = (2x) * 4 ADD.W D3, D1 ; D1 = 10x = 2x + 8x 

产生相同的结果(原始数字x-> 10x)。 ADD指令的工作方式如下:

ADD D1, D2  = pseudo-code =  D2 = D2 + D1

LSL指令是逻辑左移指令。 而且我们知道,逻辑上将数字左移1位的结果与将数字乘以2并将其左移2位的结果与将数字乘以4相同。

因此,对于从BCD到二进制的转换,我可以在算法中使用诸如MULU的乘法指令,而对于从二进制到BCD的转换,我可以在算法中使用诸如DIVU的除法指令。

而且,对于从BCD到Binary的代码,我可以使用ADD和逻辑移位指令来模拟乘法,但是从Binary到BCD的类似方法是什么? 如何使用比DIV更简单的指令来模拟除法并计算商/余数(例如减法,加法,逻辑移位等)?

我还在这里找到了一种有趣的算法,可以将二进制转换为BCD:
http://www.eng.utah.edu/~nmcdonal/Tutorials/BCDTutorial/BCDConversion.html

但是我不知道为什么会这样。 为什么我们需要在包含大于或等于5的数字的每一列(= 4位)上增加3(= 11个二进制)?

我考虑过编写使用此算法的解决方案,但是:
-3个班次后,我将必须检查是否在每一班次后的“ ones”列中包含大于4的数字--7个班次后,我将必须检查“每次移位后,thenes和tens列中是否包含大于4的数字”
-在11个班次之后,我将必须检查每个班次之后的1,数十和数百列是否包含大于4的数字
-15个班次后,我必须检查每个班次之后的数十,十万和数千列是否包含大于4的数字

看来CPU还有更多工作要做...

关于“加三”:在列中达到5或更大的值时,在下一个移位时,列的值将大于等于10。

现在考虑一下:左移后,每个二进制数字的权重都会加倍。 但是,当从“ 1”列转换为“十”列时,“ 1”失去其先前的16个权重,变为十(10)。 因此,它的重量不再是16,而是10。

我们该如何补偿? 很简单,我们将三(3)加为六(6)的一半,这样,在下一个班次,我们将失去六(3)的体重,但同时通过左移(左移=>乘以二)我们之前添加的三。 重量再次达到平衡。

更好的解释器在这里

希望能帮助到你。 顺便说一下,我也在大学里学习M68k,谢谢,您的代码读得不错。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM