任務1
task1.asm
assume cs:code, ds:data
data segment
x db 1, 9, 3
len1 equ $ - x ; 符號常量, $指下一個數據項的偏移地址,這個示例中,是3
y dw 1, 9, 3
len2 equ $ - y ; 符號常量, $指下一個數據項的偏移地址,這個示例中,是9
data ends
code segment
start:
mov ax, data
mov ds, ax
mov si, offset x ; 取符號x對應的偏移地址0 -> si
mov cx, len1 ; 從符號x開始的連續字節數據項個數 -> cx
mov ah, 2
s1: mov dl, [si]
or dl, 30h ; 數值轉為字符
int 21h
mov dl, ' '
int 21h ; 輸出空格
inc si
loop s1
mov ah, 2
mov dl, 0ah
int 21h ; 換行
mov si, offset y ; 取符號y對應的偏移地址3 -> si
mov cx, len2/2 ; 從符號y開始的連續字數據項個數 -> cx
mov ah, 2
s2: mov dx, [si]
or dl, 30h
int 21h
mov dl, ' '
int 21h ; 輸出空格
add si, 2
loop s2
mov ah, 4ch
int 21h
code ends
end start
int 21h
功能2:在標准輸出上顯示一個字符並將光標前進一個位置。
接收參數:AH=2
DL=字符值
返回值: 無
-
理解運算符offset、偽指令equ、預定義符號$的靈活使用。通過line4、line6,以及數據項的數據屬性(字節、字、雙字,等),可以方便計算出連續數據項的個數,而無需人工計數。
注*: 符號常量len1, len2不占用數據段內存空間 -
回答問題
① line26, 匯編指令 loop s1 跳轉時,是根據位移量跳轉的。通過debug反匯編,查看其機器碼,分析其跳轉的位移量是多少?(位移量數值以十進制數值回答)從CPU的角度,說明是如何計算得到跳轉后標號s1其后指令的偏移地址的。
E2F2
中 位移量: F2(h) --> 11110010(b) --> 00001110(b) --> -12(d) (補碼-->原碼)
位移量的計算: d(h) - 19(h) --> -12(d)
CPU根據目標偏移地址減去當前偏移地址得到位移量② line44,匯編指令 loop s2 跳轉時,是根據位移量跳轉的。通過debug反匯編,查看其機器碼,分析其跳轉的位移量是多少?(位移量數值以十進制數值回答)從CPU的角度,說明是如何計算得到跳轉后標號s2其后指令的偏移地址的。
分析同上, 跳轉的位移量為 FO(h).
任務2
task2.asm
assume cs:code, ds:data
data segment
dw 200h, 0h, 230h, 0h
data ends
stack segment
db 16 dup(0)
stack ends
code segment
start:
mov ax, data
mov ds, ax
mov word ptr ds:[0], offset s1
mov word ptr ds:[2], offset s2
mov ds:[4], cs
mov ax, stack
mov ss, ax
mov sp, 16
call word ptr ds:[0]
s1: pop ax
call dword ptr ds:[2]
s2: pop bx
pop cx
mov ah, 4ch
int 21h
code ends
end start
根據call指令的跳轉原理,先從理論上分析,程序執行到退出(line31)之前,寄存器(ax) = ? 寄存器(bx) = ? 寄存器(cx) = ?
分析:
call word ptr ds:[0] 短轉移, 將下一條指令偏移地址(ip)壓入棧, 並轉移至 ds:[0]地址即 s1 處, 此后的 pop ax 將該內容出棧給ax;
call dword ptr ds:[2] 段間轉移, 將下一條指令基址和偏移地址(cs 和 ip)壓入棧, 並轉移至 ds:[2] 起始的雙字指向的地址即 s2 處, 此后的 pop bx 將ip出棧給ax, pop cx 將 cs 出棧給 cx.
即:
ax = s1 bx = s2 cx = s2行所在段基址
任務3
針對8086CPU,已知邏輯段定義如下:
data segment
x db 99, 72, 85, 63, 89, 97, 55
len equ $- x
data ends
編寫8086匯編源程序task3.asm,在屏幕上以十進制形式輸出data段中這一組連續的數據,數據和數據之間以空格間隔。
要求:
- 編寫子程序printNumber
功能:以十進制形式輸出一個兩位數
入口參數:寄存器ax(待輸出的數據 --> ax)
出口參數:無 - 編寫子程序printSpace
功能:打印一個空格
入口參數:無
出口參數:無
在主體代碼中,綜合應用尋址方式和循環,調用printNumber和printSpace, 實現題目要求。
task3.asm
assume cs:code, ds:data
data segment
x db 99, 72, 85, 63, 89, 97, 55
len equ $- x
data ends
code segment
main:
mov ax, data
mov ds, ax
mov cx, len
mov si, offset x
print:
mov al, [si]
mov ah, 0
call printNumber
call printSpace
inc si
loop print
mov ah, 4ch
int 21h
;功能:以十進制形式輸出一個兩位數
;入口參數:寄存器ax(待輸出的數據 --> ax)
;出口參數:無
printNumber:
mov bl, 10
div bl
mov bx, ax
mov ah, 2
mov dl, bl ; 打印商(10位)
or dl, 30h
int 21h
mov dl, bh ; 打印余數(個位)
or dl, 30h
int 21h
ret
printSpace:
mov ah, 2
mov dl, ' '
int 21h
ret
code ends
end main
運行結果:
任務4
針對8086CPU,已知邏輯段定義如下:
data segment
str db 'try'
len equ $ - str
data ends
編寫8086匯編源程序task4.asm,在屏幕上以指定顏色、指定行,在屏幕上輸出字符串。
要求:
- 編寫子程序printStr
- 功能:在指定行、以指定顏色,在屏幕上顯示字符串
- 入口參數
- 字符串首字符地址 --> ds:si(其中,字符串所在段的段地址—> ds, 字符串起始地址的偏移地址—> si)
- 字符串長度 --> cx
- 字符串顏色 --> bl
- 指定行 --> bh (取值:0 ~24)
- 出口參數:無
- 在主體代碼中,兩次調用printStr,使得在屏幕最上方以黑底綠字顯示字符串,在屏幕最下方以黑
底紅色顯示字符串
task4.asm
assume cs:code
data segment
str db 'try'
len equ $ - str
data ends
code segment
main:
mov ax, 0b800h
mov es, ax
first_print:
mov ax, data
mov ds, ax
mov si, offset str
mov cx, len
mov bl, 00000010b ; 黑底綠字
mov bh, 0 ; 第0行
call printStr
second_print:
mov si, offset str
mov cx, len
mov bl, 00000100b ; 黑底紅字
mov bh, 24 ; 第24行
call printStr
mov ah, 4ch
int 21h
; 入口參數:
; 字符串首字符地址 --> ds:si(其中,字符串所在段的段地址—> ds, 字符串起始地址的偏移地址—> si)
; 字符串長度 --> cx
; 字符串顏色 --> bl
; 指定行 --> bh (取值:0 ~24)
printStr:
push bp ; 因為要用到bp和di, 先保存現場
push di
mov ah, 0
mov al, 160
mul bh
mov bp, ax ; 計算行數偏移地址存儲在bp
mov di, si ; di存儲顯存中每個字符偏移地址
printChar:
mov al, ds:[si]
mov es:[bp+di], al ; 字符
mov es:[bp+di+1], bl ; 顏色
inc si
inc di
inc di ; di要加兩次
loop printChar
pop bp ; 還原現場
pop di
ret
code ends
end main
運行結果:
任務5
針對8086CPU,針對8086CPU,已知邏輯段定義如下:
data segment
stu_no db '20498329042'
len = $ - stu_no
data ends
在80×25彩色字符模式下,在屏幕最后一行正中間顯示學號。要求輸出窗口藍底,學號和兩側折線,以
白色前景色顯示。
task5.asm
assume cs:code, ds:data
data segment
stu_no db '201983300514'
len = $ - stu_no
data ends
code segment
main:
call print_blue_screen
call print_stu_no
mov ah, 4ch
int 21h
print_blue_screen:
push ax ; 保存現場
push es
push si
mov ax, 0b800h
mov es, ax
mov cx, 2000
mov si, 1
single_blue:
mov byte ptr es:[si], 00010000b
inc si
inc si
loop single_blue
pop si ; 還原現場
pop es
pop ax
ret
print_stu_no:
push ax
push es
push si
push ds
push di
prefix:
mov ax, 0b800h
mov es, ax
mov cx, 34
mov si, 3840 ; si存放每次顯存輸出的偏移地址
call print_dash
content:
mov ax, data
mov ds, ax
mov cx, len
mov di, 0 ; di存放data中每個字符的偏移地址
single_no:
mov al, ds:[di]
inc di
mov byte ptr es:[si], al
inc si
mov byte ptr es:[si], 00010111b
inc si
loop single_no
postfix:
mov cx, 34
call print_dash
pop di
pop ds
pop si
pop es
pop ax
ret
; 輸入參數:
; 顯示的基地址si
; 輸出長度cx
; 輸出:
; 迭代后的基地址si
print_dash:
single_dash:
mov byte ptr es:[si], '-'
inc si
mov byte ptr es:[si], 00010111b
inc si
loop single_dash
ret
code ends
end main
運行結果: