第七章习题 计算1+2+3+...+1000的汇编mbr程序 adc指令使用

来源:互联网 发布:数据分析 用户画像 编辑:程序博客网 时间:2024/05/22 12:10

在16位的处理器上,做加法的指令是add,但它每次只能做8位或16位的加法。
除此之外,还有一个带进位加法指令adc(Add With Carry),它的指令格式和add一样,目的操作数可以是8位或16位的通用寄存器和内存单元,源操作数可以是与目的操作数宽度一致的通用寄存器、内存单元和立即数(但目的操作数和源操作数同为内存单元的除外)。
不过,adc指令在执行的时候,除了将目的操作数和源操作数相加,还要加上当前标志寄存器的CF位。也就是说,视CF位的状态,还要再加0或者加1。这样一来,用adc指令配合add指令,就可以计算16位以上的加法。
adc指令对OF、SF、ZF、AF、CF和PF的影响视计算结果而定。

1+2+…+1000的结果是500500, 二进制的话是一个19位的数字, 如果用普通add则会溢出, 高位被舍弃, 从而出错. 所以就用到了带进位的加法指令adc.

adc oprd1,oprd2

上面这句含义是:oprd1 = oprd1 + oprd2 + CF.
这样就可以把会溢出的部分(高16位)放到另一个寄存器中, 像这样:

add ax,cxadc dx,0

这样ax + cx产生的进位就会加到dx中.
完整代码如下, 是由随书的c07_mbr.asm代码改来的, 原代码是计算1+2+…+100的.

         ;代码清单7-2         ;文件名:c07_2.asm         ;文件说明:硬盘主引导扇区代码         ;创建日期:2017-10-05 18:12         jmp near start message db '1+2+3+...+1000=' start:         mov ax,0x7c0           ;设置数据段的段基地址          mov ds,ax         mov ax,0xb800          ;设置附加段基址到显示缓冲区         mov es,ax         ;以下显示字符串          mov si,message                   mov di,0         mov cx,start-message     @g:         mov al,[si]         mov [es:di],al         inc di         mov byte [es:di],0x07         inc di         inc si         loop @g         ;以下计算11000的和,500500          xor ax,ax         xor dx,dx         mov cx,1000     @f:         add ax,cx         adc dx,0         loop @f                         mov bx,10         xor cx,cx     @d:         inc cx                            ;原来xor dx,dx在这里         div bx         or dl,0x30         push dx         xor dx,dx          ;现在在这里         cmp ax,0         jne @d         ;以下显示各个数位      @a:         pop dx         mov [es:di],dl         inc di         mov byte [es:di],0x07         inc di         loop @a         jmp near $ times 510-($-$$) db 0                 db 0x55,0xaa

这里有一点, 结果中只有一位在高16位的dx寄存器中, 所以这里可以不把dx和ax分别输出, 而是在@d的第一层循环中直接把最高位剔出来, 之后再把dx赋值0用来计算ax的每一位. 如果要计算更大一些的数字的话, 就要分别将dx和ax输出了. 但是, 如果要这么做就要把原本在44行的xor dx,dx移到后面. 可以理解吧, 你总不能先把人家值给覆盖了在输出人家啊.
下面是未移动xor dx,dx的执行结果:

错误结果

正确结果:

正确结果

原创粉丝点击