第六章 相同的功能 不同的代码
上一章我们分别将每一个显示字符打入显示缓冲区,这样太麻烦,每次修改显示不同内容得重写,所以我们这一章设一个专门存放字符串的数据区,当要显示时,再用指令统一取出来。
补课:除法指令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指令做两件事
- 将cx中的值-1
- 如果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。