16.1 描述了單元長度的標號
前面的課程中,我們一直在代碼段中使用標號來標記指令、數據、段的起始地址。比如,下面的程序將code段中的a標號處的8個數據累加,結果存儲到b標號處的字中。
assume cs:code
code segment
a db 1,2,3,4,5,6,7,8
b dw 0
start:
mov si,0
mov cx,8
s:
mov al,a[si]
mov ah,0
add b,ax
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start
檢測點16.1
下面的程序將code段中a處的8個數據累加,結果存儲到b處的雙字中,補全程序。
assume cs:code
code segment
a dw 1, 2, 3, 4, 5, 6, 7, 8
b dd 0
start: mov si, 0
mov cx, 8
s: mov ax, a[si] ;a是dw型的,可以直接給ax
add word ptr b[0], ax ;b是dd型的,ax只能和b的低位相加
adc word ptr b[2], 0 ;b的高位和0相加,使用adc進位加法是把低位進位加上
add si, 2 ;用si來控制a中的數據累加
loop s
mov ax, 4c00H
int 21H
code ends
end start
16.2 在其他段中使用數據標號
assume cs:code,ds:data
data segment
a db 1,2,3,4,5,6,7,8
b dw 0
data ends
code segment
start:
mov ax,data
mov ds,ax
mov si,0
mov cx,8
s:
mov al,a[si]
mov ah,0
add b,ax
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start
可以將標號當作數據來定義,此時,編譯器將標號所表示的地址當作數據的值。
檢測點16.2
下面的程序將data段中a處的8個數據累加,結果存儲到b處的字中,補全程序。
assume cs:code,es:data
data segment
a db 1,2,3,4,5,6,7,8
b dw 0
data ends
code segment
start:
mov ax,data ;把es和data段相關聯
mov es,ax
mov si,0
mov cx,8
s:
mov al,a[si]
mov ah,0
add b,ax
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start
16.3 直接定址表
;用al傳送要顯示的數據
showbyte:
jmp short show
table db '0123456789ABCDEF' ;table字符表
show:
push ax
push es
mov ah,al
shr ah,1
shr ah,1
shr ah,1
shr ah,1 ;右移4位,ah中得到高4位的值
and al,00001111b ;al中爲低4位的值
mov bl,ah
mov bh,0
mov ah,table[bx] ;用高4位的值作爲相對table的偏移,取得對應字符,作爲要顯示的字節的高位
mov bx,0b800h
mov es,bx
mov es:[160*12+40*2],ah
mov bl,al
mov bh,0
mov al,table[bx] ;用低4位的值作爲相對於table的偏移,取得對應的字符,作爲要顯示字節的低位
mov es:[160*12+40*2+2],al
pop es
pop bx
ret
showsin:
jmp short show
table dw ag0,ag30,ag60,ag90,ag120,ag150,ag180 ;字符串偏移地址表
ag0 db '0',0 ;sin(0)對應字符串爲0,下同
ag30 db '0.5',0
ag60 db '0.866',0
ag90 db '1',0
ag120 db '0.866',0
ag150 db '0.5',0
ag180 db '0',0
show:
push bx ;先把一些要使用的寄存器壓棧
push es
push si
mov bx,0b800h
mov es,bx ;es指向顯存區域
;用以下角度值/30作爲相對於table的偏移,取得對應的字符串的偏移地址,放在bx中
mov ah ,0 ;最大也才180沒有超過255,用不上ah
mov bl,30
div bl ;除數爲8位,被除數爲ax,商放在al裏面
mov bl,al ;商給bl,作爲table表的索引
mov bh,0
add bx,bx
mov bx,table[bx]
;以下顯示sin(x)對應的字符串
mov si,160*12+40*2
shows:
mov ah,cs:[bx] ;判斷是否讀到了0
cmp ah,0
je showret
mov es:[si],ah
inc bx
add si,2
jmp short shows
showret:
pop si
pop es
pop bx
ret
16.4 程序入口地址的直接定址表
子程序實現功能1:清屏
sub1:
push bx
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,0
mov cx,2000
sub1s:
mov byte ptr es:[bx],' ' ;用空格覆蓋
add bx,2
loop sub1s
pop es
pop cx
pop bx
ret
子程序實現功能2:設置前景
sub2:
push bx
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,1
mov cx,2000
sub2s:
and byte ptr es:[bx],11111000b ;把奇字節的第0、1、2位清零
or es:[bx],al ;用or操作把012三位設置爲我們想要的顏色
add bx,2
loop sub2s
pop es
pop cx
pop bx
ret
子程序實現功能3:設置背景色
sub3:
push bx
push cx
push es
mov cl,4
shl al,cl ;al用來傳送顏色,al的值爲0-7,設置背景色是456位,要把al左移4位、
mov bx,0b800h
mov es,bx
mov bx,1 ;顯存中的基地址爲屬性字節
mov cx,2000
sub3s:
and byte ptr es:[bx],10001111b ;第456位先置0,其他位不變
or es:[bx],al ;es:[bx]和al相或,設置顏色
add bx,2
loop sub3s
pop es
pop cx
pop bx
ret
子程序實現功能4:向上滾動一行
sub4:
push cx
push si
push di
push es
push ds
mov si,0b800h
mov es,si
mov ds,si
mov si,160 ;ds:si指向第n+1行
mov di,0 ;es:di指向第n行
cld ;設置正向傳輸
mov cx,24 ;共複製24行,整屏就24行
sub4s:
push cx
mov cx,160
rep movsb ;複製
pop cx
loop sub4s
mov cx,80
mov si,0
sub4s1:
mov byte ptr [160*24+si],' ' ;最後一行清空
add si,2
loop sub4s1
pop ds
pop es
pop di
pop si
pop cx
ret
我們可以將這些功能子程序的入口地址存儲在一個表中,它們在表中的位置和功能號相對應。對應關係爲:功能號*2=對應的功能子程序在地址表中的偏移。程序如下:
setscreen:
jmp short set
table dw sub1,sub2,sub3,sub4
set:
push bx
cmp ah,3 ;判斷功能號是否大於3
ja sret
mov bl,ah
mov bh,0
add bx,bx ;根據ah中的功能號計算對應子程序在table表中的偏移,即功能號*2=偏移
call word ptr table[bx] ;調用對應的功能子程序
sret:
pop bx
ret
我們也可以將子程序setscreen用以下命令實現:
setscreen:
cmp ah,0
je do1
cmp ah,1
je do2
cmp ah,2
je do3
cmp ah,3
je do4
jmp short sret
do1:
call sub1
jmp short sret
do2:
call sub2
jmp short sret
do3:
call sub3
jmp short sret
do4:
call sub4
jmp short sret
sret:
ret