第6章 相同的功能 不同的代码

第六章 相同的功能 不同的代码


上一章我们分别将每一个显示字符打入显示缓冲区,这样太麻烦,每次修改显示不同内容得重写,所以我们这一章设一个专门存放字符串的数据区,当要显示时,再用指令统一取出来。

补课:除法指令div

8086处理器除法指令有两种类型。

  • 类型一:16位数除以8位数。被除数放置于ax,除数可以由8位通用寄存器或内存单元提供。商在寄存器al中,余数在寄存器ah中。
div cl		;除以cx寄存器低位的8位cl
div byte [0x0023]	;除以0x0023处的1字节数据
  • 类型二:32位数除以16位数。因为16位处理器无法直接提供32位数,所以要求被除数的高16位在dx中,低16位在ax中。商在ax中,余数在dx中。
div cx
div word [0x0230]

6.5 段之间的批量数据传送


         jmp near start
         
  mytext db 'L',0x07,'a',0x07,'b',0x07,'e',0x07,'l',0x07,' ',0x07,'o',0x07,\
            'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07
  number db 0,0,0,0,0
  
  start:
         mov ax,0x7c0                  ;设置数据段基地址 
         mov ds,ax
         
         mov ax,0xb800                 ;设置附加段基地址 
         mov es,ax
         
         cld
         mov si,mytext                 
         mov di,0
         mov cx,(number-mytext)/2      ;实际上等于 13
         rep movsw

因为计算机启动时从硬盘启动,那么ROM-BIOS将读取主引导扇区的内容,将它加载到内存地址0x0000:0x7c00处。而每一条mov指令,如果不指定段寄存器的话,都采用"DS指令右移4位+操作数地址"作为目标地址。此处如果将数据段寄存器ds设为0x7c0,则由于这段代码的初始地址就是0x7c00,则可以从这个地方开始,下面自动用ds计算偏移,不用每次都指定地址了。

附加段基址为0xb800,因为文本模式的显示缓冲区首地址就是0xb800,我们要控制movsw指令向显示缓冲区写数据,来显示数据到屏幕上。

上述代码显然可看出,35行为数据段,而718行为代码段。按照数据代码分开储存的原则,这样显然是不对的。但是看到有指令jmp将运行顺序跳过了数据区,则可以。

第3行的**\符号**,应该为不中断换行符,将下一行的内容同样也作为本行,接到后面,这样就不用在同一行中打印太多内容。

批量数据传送指令movsb与指令movsw

movsb以字节为单位传送,movsw以字(2字节)为单位传送。

需要设置以下参数:源数据串地址、目标地址、传送计数、正向/反向传送指定标志。

  • 源数据串地址:在DS:SI指定。
  • 目标地址:在ES:DI指定。
  • 传送计数:在CX指定。如果是movsb,就设置为传送的字节数;如果是movsw,就设置为传送的字数(字节数/2)。
  • 正向、反向传送指定标志:正向传送是指从低地址到高地址传送;反向传送是指从高地址到低地址传送。无操作数指令cld意为将标志寄存器的第10位DF置为0,表示正向传送;std将DF置为1,表示反向传送。标志寄存器的第6位即为ZF,即零标志位。每条逻辑或者算数指令后,如果结果为0,则修改ZF为1,如果结果为1,则修改ZF为0.

每次移动后,DI或SI均+1或+2(正向),-1或-2(反向);无论正反,CX均-1。

单纯的movsw或movsb只能执行一次,如果将整个区间全都读入,则需要用rep指令,意为不断重复每一步移动过程,直到CX为0。


         ;得到标号所代表的偏移地址
         mov ax,number
         
         ;计算各个数位
         mov bx,ax
         mov cx,5                      ;循环次数 
         mov si,10                     ;除数 
  digit: 
         xor dx,dx
         div si
         mov [bx],dl                   ;保存数位
         inc bx 
         loop digit
         
         ;显示各个数位
         mov bx,number 
         mov si,4                      

循环指令loop

重复转到标号处执行。loop指令做两件事

  1. 将cx中的值-1
  2. 如果cx不为零,则转移到指定位置处执行,如果cx为零,就顺序执行后面的指令

偏移地址寄存器使用限制

对于第11行,相当于把余数所在的dl的内容赋值给bx中地址指向的存储单元。注意,如果要用寄存器来提供偏移地址,只能使用BX、SI、DI、BP,使用其他寄存器都是非法的。

自增自减指令:inc、dec

自增指令inc,相当于C语言中的++。可以指定目标格式。下面的格式都是合法的。

inc al
inc byte [bx]		;将(默认)DS:BX地址处的内容(字节)+1
inc word [label_a]	;将指定位置处的字+1

和inc相对的指令是指令dec,自减,其他都和inc相同。

位扩展指令cbw、cwd

cbw: Convert Byte to Word

cwd: Convert Word to Double-word

cbw意思是将AL中的有符号数扩展到整个AX,如AL中为01001111,则cbw之后AX为0000000001001111;如果AL为10001101,则执行cbw后AX为1111111110001101.

swd是将AX中的数扩展到DX:AX中。

合法的基址变址寄存器格式

INTEL8086处理器只允许以下四种基址变址寄存器组合

[bx+si]
[bx+di]
[bp+si]
[bp+di]

这些组合可以用于任何带有内存操作数的指令,其他像[bx+ax]、[ax+cx]等都是非法的。

其他标志位,如PF、OF、AF、CF

  • PF:如果某次计算结果低8位有偶数个1,则PF=1,否则为0。
  • OF:当进行有符号数计算时,如果结果出现了溢出,则OF=1,其他情况下OF都为0,无论有无符号数。
  • AF:看运算结果的最后四位,如果发生进位或者借位,则AF=1,否则AF=0。
  • CF:如果某次运算过程中,最高位有向前进位或借位的情况发生,那么这次计算后CF=1,否则CF-0。

你可能感兴趣的:(汇编语言)