汇编语言8086如何制作64位整数计算器?

时间:2013-04-10 15:28:34

标签: assembly x86 masm x86-16

我想用8086汇编语言制作一个64位整数计算器,它具有以下功能:加法,减法,除法,乘法。

它应该提供一个菜单,这样如果我们按1它会添加,如果我们按2,它会减去等等,我们可以给出64位输入值。

问题是我们在编程时只能使用16位寄存器/存储器,所以问题是如何在控制台窗口中使用16位寄存器并给出64位输入值。

我正在使用KIP.R.IRVINE程序集链接库。

我们必须对它进行编码,使其为每个功能使用16位寄存器/操作数,如加法,减法,除法和乘法。 16 + 16 + 16 + 16 = 64

我是汇编语言的新手,如果有人可以帮我制作计算器的1个功能(+, - ,/,x),我可以完成剩下的工作。

2 个答案:

答案 0 :(得分:3)

这个问题与汇编语言几乎没有关系,或者至少与狮子会分享问题。您应该使用C或任何您喜欢的语言对其进行原型设计,然后将其转换为另一种语言(在本例中为汇编)。

如果你还记得小学,我们想要加999 + 1

 999
   1 +
======

我们将会有很多"携带一个"继续

111
 999
   1 +
======
1000

现在小学里可能没有定义的是"随身携带"并且"执行"。你携带1到下一栏的东西就是执行。当你将那个被遗留的东西添加到当前列中时,对于这个列,现在这个号码被称为进位。

ab
 c
 d +
====
 e

b进位,a进行,操作数为c和d。 e是该列的结果。我们在小学就读过,我们可以添加无限大的数字,因为我们只需要学习一次添加一列并无限重复。请注意,第一列上的进位上方的原始问题是空白的,它是隐含的零。零加9加1等于" 0带1" 0是9 + 1的结果,1是执行。

所以现在做999 + 1但是设置了一个人为的限制,我们一次只能添加两列,也许我们的论文只有两个数字足够宽,谁知道(处理器的寄存器有一个固定的限制在宽度,在您的情况下为16位,或16列宽。)

我们知道答案看起来像四列,

1110
0999
0001 +
======
1000

一次两列

11    10
09    99
00 +  01 +
====  ====
10    00

首先使用零进行最低有效列。然后,无论将哪个用作进入下两列的进位,我们都可以无限重复这个无限大数。

在汇编语言中你常常(但并不总是)有一些ADD和一些风格的ADC指令,无需携带添加和附加,正常添加有一个隐含的零进位并且理想地有一个进位到一个进位某处处理器状态寄存器中的标志。然后如果有一个带有进位指令的加法你用剩余的高阶加法加上进位,带进位的加法使用进位标志作为进位,并将进位放入进位标志,这样就可以级联增加。

清楚如泥?

减法,计算机中没有真正的减法,有一个原因让你在初学者编程课中学到了很多东西。使用二进制补码否定一个数字是"反转并添加1"。现在考虑一下我们的添加操作,一个add添加两个带有进位的数字。如果你要反转第二个操作数,然后在进位中放一个1怎么办?那是"反转并添加1"对吧?如果我想要数学5 - 1与5 +( - 1)相同,这与5 +反转(1)+ 1相同吗?完全适合ADD逻辑。

不同的指令集用进位执行不同的操作,基本上在进入加法器的过程中,减法意味着反转第二个操作数并反转进位,然后做一个正常的加法,在出路的时候有些如果操作是减法,处理器系列会反转进位,有些则不会。您可能会或可能不会想到这一点,具体取决于您在操作后对进位位执行的操作(条件分支,例如,如果进位设置则跳转,如果未设置则跳转),在这种情况下如另一张海报所示,某些说明集合借用减法。就像添加一系列addc操作来级联一个无限大的加法一样,你可以使用sub和sbb来级联一个无限大的减法。

繁殖......幸运的是8086让这更容易,但整体属性在任何地方都是一样的。如果你看两个x位宽的数字(二进制​​),结果理想情况下需要2 * x宽,所以要正确地乘以任意两个16位数,你需要32位结果。如果您的硬件只能做16bit * 16bit = 16bit那么可以轻松级联该乘数为零的高8位并假装做8bit * 8bit = 16bit ......

小学

 abcd
 efgh *
======

我们最终得到了四个加在一起的数字?我用hhhh代表abcd * h和gggg代表abcd * g等。

   abcd
   efgh *
======= 
   hhhh
  gggg
 ffff
eeee    +
==========

当我们做了两列乘法

 cd
 gh *
====

分为四个乘法步骤

h * d
h * (c*10)
(g*10) * d
(g*10) * (d*10)
使用math属性的

h * d = h*d
h * (c*10) = 10 * (h*c)
(g*10) * d = 10 * (g*d)
(g*10) * (d*10) = 100 * (g*d)

在基数10中乘以10只是移动一列,时间100是两列,所有这些项目相加。因此,如果你将你的乘法操作数分解成可消化的部分,并记录你需要移动每个项目的数量,这基本上是将该项目放在特定的列中,使用我们无限广泛的添加,我们已经将事物分解为列或组列。是的它变成了一个交互过程,如上所述,我们有四个要添加的东西,我们的级联加法只增加两个东西,所以你必须做3个加法,1)前两个操作数,2)1)的结果加上第三个操作数3 )2)的结果加上最后一个操作数

说这些字母都是16位数字

abcd
efgh *
======

上面唯一的乘法对不会有一些与它相关的16的倍数偏移(想想乘以10或100或十进制的1000)是h * d。

因此结果的低16位是h * d的低16位。 h * d的高16位必须添加到其他内容中

下一层是h * c <&lt; 16且g * d&lt; 16。每个低16位加在一起,也加到d * h的高16位。使用两个字母组合来表示其乘法结果

换句话说abcd * efgh =

000000hd
00000hc0
0000hb00
000ha000
00000gd0
0000gc00
000gb000
00ga0000
0000fd00
000fc000
00fb0000
0fa00000
000ed000
00ec0000
0eb00000
ea000000 +
==========

将h * d的低16位(表示为上面的hd)加到零,然后直接进入结果,h * d的上半部分和h * c和g * d的下半部分被加到成为结果的下一个16位,依此类推。

如果你想使用16 * 16 = 32位乘法运算和16 * 16 = 16 +进位加法运算将两个64位数相乘,你可以根据上述内容进行硬编码。

如果你想把结果限制在64 * 64 = 64位而不是64 * 64 = 128位你可以减少一半

00hd
0hc0
hb00
a000 (h*a)
0gd0
gc00
b000 (g*b)
fd00
c000 (f*c)
d000 + (e*d)
======

我会留下师给你弄清楚......

首先使用基本操作加法和减法以高级语言实现它,合成进位位

制作添加功能

unsigned int a,b,c,result,carry;

//addition
a = operand1&0xFFFF;
b = operand2&0xFFFF;
c = a+b;
result = c&0xFFFF;
carry = (c>>16)&1;

和带有进位功能的添加

//add with carry 
a=(operand1>>16)&0xFFFF;
b=(operand2>>16)&0xFFFF;
c = a+b+carry_in;
result = c&0xFFFF;
carry = (c>>16)+1;

或者如果你想像硬件一样只用附加功能进行添加,并为添加步骤输入一个0进行输入,否则输入执行。

清楚如泥?

例如,x86可以在减法时反转执行,也可以反对执行。有些处理器根本没有标记(mips),你必须使用小于寄存器大小的数字合成上述所有内容(使用32位寄存器进行16位加法,允许一个地方保存第17位,执行,或者可能做无论如何,一次31位。就像某些处理器一样,你必须使用输入乘法的一半大小(上半部分为零)才能获得结果的未剪辑答案,并执行上述游戏以正确地进行全宽乘法。

答案 1 :(得分:1)

要使用16位寄存器减去2个64位值,可以使用:

lea di, [operand1]  ;;  *di -= *si
lea si, [operand2]

    mov ax, [si]     // subtract initially first 16 bits
    sub [di], ax
    mov cx, 3        // setup loop counter
    xor bx, bx

a:  lea bx, [bx+2]    // advance the pointers without affecting status register
    mov ax, [si+bx]   // subtract 
    sbb [di+bx], ax

    loop a           // this does not affect carry flag
相关问题