彙編語言-第三版-王爽-實驗6、7、9、10、11、12、13、14、15

實驗6(p160)、實驗7(p173)、實驗9(p189)、實驗10(p206,p208, p209)、實驗11(p234)、實驗12(p251)、p256(編寫7cH中斷例程完成loop指令功能)、實驗13(p262)、實驗14(p271)、實驗15(p285)


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

實驗6(p160)

; DATE: 20190608
; DESCRIPTION: 每個單詞的前4個字母改爲大寫

assume cs:code, ds:data, ss:stack

stack segment
    dw 0, 0, 0, 0, 0, 0, 0, 0 ; 定義一個段,16Bytes,用作棧段
stack ends

data segment
    db '1. display      '
    db '2. brows        '
    db '3. replace      '
    db '4. modify       '
data ends

code segment
start:
    mov ax, stack
    mov ss, ax
    mov sp, 16
    mov ax, data
    mov ds, ax
    mov bx, 0
    
    mov cx, 4
line:
    push cx             ; 將外層循環的計數值cx入棧
    mov cx, 4
    mov si, 0           ; cx設置爲內層循環的次數
toBig:
    mov al, [bx+si+3]
    and al, 11011111B
    mov [bx+si+3], al
    inc si
    loop toBig
    
    add bx, 16
    pop cx              ; 出棧,恢復外層循環的計數值
    loop line           ; loop指令將cx中的計數值減1
    
    mov ax, 4c00H
    int 21H
code ends
end start

運行結果:

# before

# after


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

實驗7(p173)

; DATE: 20190608
; DESCRIPTION: 實驗7(p173)

assume cs:code

data segment
    db '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983'
    db '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992'
    db '1993', '1994', '1995'
    
    dd 16, 22, 382, 1356, 2390, 8000, 16000, 24486, 50065, 97497, 140417, 197514
    dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000
    
    dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5635, 8226
    dw 11542, 14430, 15257, 17800
data ends

table segment
    db 21 dup ('year summ ne ?? ')
table ends

code segment
start:
    mov ax, data
    mov es, ax
    mov si, 0
    mov di, 168         ; di指向data中的僱員
    
    mov ax, table
    mov ds, ax
    mov bx, 0
    
    mov cx, 21          ; 21年,循環21次
year:
    ; 年份
    mov ax, es:[si]     ; si指向data中的年份
    mov [bx], ax        ; bx指向table
    mov ax, es:[si+2]
    mov [bx+2], ax
    
    ; 收入
    mov ax, es:[si+84]  ; si+84指向data中的收入
    mov [bx+5], ax
    mov ax, es:[si+86]
    mov [bx+7], ax

    ; 僱員
    mov ax, es:[di]
    mov [bx+0aH], ax

    ; 人均收入
    mov ax, [bx+5]      ; ax存放被除數低16位
    mov dx, [bx+7]      ; dx存放被除數高16位
    div word ptr [bx+0aH]
    mov [bx+0dH], ax    ; 結果的商存放在ax中
    
    add bx, 10H
    add si, 4 
    add di, 2
    loop year

    mov ax, 4c00H
    int 21H
code ends
end start

運行結果:

# before

# after


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

實驗9(p189)

# 草稿版

; DATE: 20190609
; DESCRIPTION: 在屏幕中間分別顯示綠色、綠底紅色、白底藍色的
;       字符串'welcome to masm!'

assume cs:code, ds:data, ss:stack

data segment
    db 'welcome to masm!'   ; 16Bytes
data ends

code segment
start:
    mov ax, data
    mov ds, ax
    mov bx, 0
    
    mov ax, 0B800H
    mov es, ax
    mov si, 160*11+64       ; 定位到屏幕中間
    
    mov cx, 16
write:    
    mov al, [bx]
    mov ah, 01110001B       ; 白底藍字
    mov es:[si], ax
    inc bx
    add si, 2
    loop write

    mov ax, 4c00H
    int 21H
code ends
end start

# 運行結果

# 完善版

; DATE: 20190609
; DESCRIPTION: 在屏幕中間分別顯示綠色、綠底紅色、白底藍色的
;       字符串'welcome to masm!'

assume cs:code, ds:data

data segment
    db 'welcome to masm!'   ; 16Bytes
    db 02H, 24H, 71H        ; 顏色屬性:綠色、綠底紅色、白底藍色
data ends

stack segment
    db 16 dup (0)
stack ends

code segment
start:
    mov ax, data
    mov ds, ax
    mov bx, 0               ; ds:bx 數據段
    mov di, 16              ; ds:di 顏色屬性 
    
    mov ax, stack
    mov ss, ax
    mov sp, 16              ; ss:sp 棧空間
    
    mov ax, 0B800H
    mov es, ax
    mov si, 160*11+64       ; es:si 定位到屏幕中間區域

    mov cx, 3               ; 3行
line:
    push cx
    push si
    mov cx, 16              ; 每行16個字符
write: 
    mov al, [bx]            ; 字符
    mov ah, [di]            ; 顏色屬性
    mov es:[si], ax
    inc bx
    add si, 2
    loop write
    
    mov bx, 0               ; ds:bx 重新指向第一個字符
    inc di                  ; ds:di 指向下一個顏色屬性
    pop si
    add si, 160             ; es:si 指向下一行
    pop cx
    loop line
    
    mov ax, 4c00H
    int 21H
code ends
end start

# 運行結果


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

實驗10-1(p206)

; DATE: 20190611
; DESCRIPTION: 顯示字符串

assume cs:code

data segment
    db 'welcome to masm!', 0
data ends

code segment
start:
    mov dh, 8   ; 第8行
    mov dl, 3   ; 第3列
    mov cl, 2   ; 綠色
    mov ax, data
    mov ds, ax
    mov si, 0   ; ds:si指向data段
    call show_str
    
    mov ax, 4c00H
    int 21H
    
; 名稱:show_str
; 功能:在指定的位置,用指定的顏色,顯示一個用0結束的字符串
; 參數:(dh)=行號(取值範圍0~24),(dl)=列號(取值範圍0~79)
;       (cl)=顏色, ds:si指向字符串首地址
; 返回:無
show_str:
    push dx
    push cx
    push si

    mov ax, 0b800H
    mov es, ax      ; 顯示緩衝區 b8000 ~ b8ffff
    
    mov al, 160     ; 一行80個字符,加上顏色屬性,佔160Bytes
    mul dh
    mov di, ax 
    mov al, 2
    mul dl
    add di, ax      ; es:di指向屏幕指定位置對應的顯示緩衝區
    
    mov ah, cl      ; 高位字節存儲顏色屬性
s0:
    mov ch, 0
    mov cl, [si]    ; 給定的字符串以0結尾
    jcxz ok
    mov al, cl      ; 低位字節存儲字符ASCII碼
    mov es:[di], ax
    inc si
    add di, 2
    jmp short s0
ok:
    pop si
    pop cx
    pop dx
    ret
    
code ends
end start

# 運行結果


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

實驗10-2(p208)

; DATE: 20190613
; DESCRIPTION: 不會產生溢出的除法

assume cs:code

code segment
start:
    mov ax, 4240H
    mov dx, 000fH
    mov cx, 0aH
    call divdw
    
; 名稱:divdw
; 功能:不會產生溢出的除法,被除數爲dword,除數爲word,結果爲dword
; 參數:(ax)=dword低16位 (dx)=dword高16位 (cx)=除數
; 返回:(dx)=結果高16位 (ax)=結果低16位 (cx)=餘數
divdw:
    push ax     ; 被除數低16位

    ; 被除數的高16位除法
    mov ax, dx
    mov dx, 0
    div cx

    ; 被除數的低16位除法
    mov bx, ax  ; 高16位除法的商暫移到bx
    pop ax
    div cx

    ; 結果返回
    mov cx, dx  ; 低16位除法的餘數移到cx
    mov dx, bx  ; 高16位除法的商移到dx

    mov ax, 4c00H
    int 21H
code ends
end start

# 運行結果


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

實驗10-3(p209)

; DATE: 20190613
; DESCRIPTION: 十進制數轉爲字符串

assume cs:code

data segment
    db 10 dup (0)
data ends

code segment
start:
    mov ax, 12666
    mov bx, data
    mov ds, bx
    mov si, 0
    call dtoc
    
    mov dh, 8
    mov dl, 3
    mov cl, 2
    call show_str
    
    mov ax, 4c00H
    int 21H
    
; 名稱:dtoc
; 功能:將word型數據轉變爲表示十進制數的字符串,以0結尾
; 參數:(ax)=word型數據,ds:si指向字符串的首地址
; 返回:無
dtoc:
    push ax
    push cx
    push dx 
    push si
    mov bx, 10    
change:
    mov dx, 0       ; 被除數的高16位
    div bx
    add dx, 30H     ; dx爲餘數,轉爲字符
    push dx         ; 餘數入棧
    inc si          ; 通過si統計長度
    mov cx, ax      ; ax爲商
    jcxz save
    jmp short change
save:
    mov cx, si
    mov si, 0
s1:
    pop [si]        ; 餘數出棧,保存到ds:si
    inc si          ; 取巧,出棧2Bytes,但si+1;末尾以0結尾
    loop s1
    
    pop si
    pop dx
    pop cx
    pop ax
    ret
    
; 名稱:show_str
; 功能:在指定的位置,用指定的顏色,顯示一個用0結束的字符串
; 參數:(dh)=行號(取值範圍0~24),(dl)=列號(取值範圍0~79)
;       (cl)=顏色, ds:si指向字符串首地址
; 返回:無
show_str:
    push dx
    push cx
    push si

    mov ax, 0b800H
    mov es, ax      ; 顯示緩衝區 b8000 ~ b8ffff
    
    mov al, 160     ; 一行80個字符,加上顏色屬性,佔160Bytes
    mul dh
    mov di, ax 
    mov al, 2
    mul dl
    add di, ax      ; es:di指向屏幕指定位置對應的顯示緩衝區
    
    mov ah, cl      ; 高位字節存儲顏色屬性
s0:
    mov ch, 0
    mov cl, [si]    ; 給定的字符串以0結尾
    jcxz ok
    mov al, cl      ; 低位字節存儲字符ASCII碼
    mov es:[di], ax
    inc si
    add di, 2
    jmp short s0
ok:
    pop si
    pop cx
    pop dx
    ret
    
code ends
end start

# 運行結果


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

實驗11(p234)

assume cs:code
data segment
    db "Beginner's All-purpose Symbolic Instruction Code.",0
data ends

code segment
begin:
    mov ax, data
    mov ds, ax
    mov si, 0
    call letterc
    
    mov ax, 4c00H
    int 21H

; 名稱:letterc
; 功能:將以0結尾的字符串中的小寫字母轉爲大寫
; 參數:ds:si指向字符串首地址
; 返回:無    
letterc:
    push cx
    push si     ; 保護現場
    
    mov ch, 0
change:
    mov cl, [si]
    jcxz ok
    cmp cl, 'a'
    jb next
    cmp cl, 'z'
    ja next
    and cl, 11011111B ; 爲小寫字母則減32
    mov [si], cl
next:
    inc si
    jmp short change
ok:
    pop si
    pop cx      ; 恢復現場
    ret
    
code ends
end begin

# 運行結果


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

實驗12(p251)

; DATE: 20190618
; DESCRIPTION: 編寫0號中斷處理程序,使得在除法溢出發生時,
;       在屏幕上顯示字符串"divide error!",然後回到DOS

assume cs:code

code segment
start:
    mov ax, cs
    mov ds, ax
    mov si, offset do0  ; ds:si指向源地址,處理程序所在
    mov ax, 0
    mov es, ax
    mov di, 0200H       ; es:di指向目的地址
    
    mov cx, offset do0end - offset do0 ; 設置cx爲傳輸長度
    cld                 ; 設置DF標誌位爲0,即傳輸方向爲正
    rep movsb           ; 將ds:si中的字節送入es:di
    
    mov ax, 0
    mov es, ax          ; 設置中斷向量表中除法錯誤即
    mov word ptr es:[0*4], 0200H    ; 0號中斷對應的處理程序入口地址
    mov word ptr es:[0*4+2], 0      ; 我們選用0000:0200~0000:02ff這段內存空間
    
    mov ax, 4c00H
    int 21H
    
do0:
    jmp short do0start
    db "divide error!"  ; 提示信息
do0start:
    push ax
    push cx
    push ds
    push es
    push di
    push si             ; 保護現場

    mov ax, cs
    mov ds, ax
    mov si, 0202H       ; ds:si指向字符串
    mov ax, 0b800H
    mov es, ax
    mov di, 12*160+36*2 ; es:di指向屏幕中間位置對應的顯存空間
    
    mov cx, 13          ; 字符串長度爲13
    mov ah, 71H         ; 顏色屬性,白底藍字
s:
    mov al, [si]
    mov es:[di], ax
    inc si
    add di, 2
    loop s              ; 將字符串複製到顯存空間
    
    pop si
    pop di
    pop es
    pop ds
    pop cx
    pop ax              ; 恢復現場
    
    mov ax, 4c00H
    int 21H
do0end:                 ; 標記結束位置,用於前面計算處理程序的長度
    nop
    
code ends
end start

# 除法溢出的測試代碼

; DATE: 20190618
; DESCRIPTION: 除法溢出的測試代碼

assume cs:code
code segment
start:
    mov ax, 1000H
    mov bh, 1
    div bh
    
    mov ax, 4c00H
    int 21H
code ends
end start

# 運行結果


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

p256(編寫7cH中斷例程完成loop指令功能)

; DATE: 20190620
; DESCRIPTION: 編寫7cH中斷例程完成loop指令功能

assume cs:code

code segment
start:
    mov ax, cs
    mov ds, ax
    mov si, offset myloop   ; ds:si指向源地址
    
    mov ax, 0
    mov es, ax
    mov di, 0200H           ; es:di指向目的地址
    
    mov cx, offset myloopend - offset myloop ; 設置cx爲傳輸長度
    cld                     ; 設置DF標誌位爲0,即傳輸方向爲正
    rep movsb               ; 將ds:si中的字節送入es:di
    
    mov ax, 0
    mov es, ax
    mov word ptr es:[7cH*4], 0200H
    mov word ptr es:[7cH*4+2], 0 ; 設置中斷向量表
    
    mov ax, 4c00H
    int 21H
    
myloop:
    ; 使用寄存器間接尋址時,只可以使用 BX,BP,SI,DI這四個寄存器
    ; 中斷過程中,當前的標誌寄存器、CS和IP都要入棧
    push bp
    mov bp, sp
    dec cx
    jcxz myloopret
    sub [bp+2], bx ; 修改進入中斷時的IP值
myloopret:
    pop bp
    iret
myloopend:
    nop
    
code ends
end start

p256-2(調用編寫的7cH中斷例程所實現的loop功能,在屏幕中間顯示80個‘!’)

; DATE: 20190620
; DESCRIPTION: 編寫7cH中斷例程完成loop指令功能
;       在屏幕中間顯示80個'!'

assume cs:code

code segment
start:
    mov ax, 0b800H
    mov es, ax
    mov di, 160*12

    mov bx, offset send - offset s
    mov cx, 80
    ;mov ah, 71H
    ;mov al, '!'
s:
    ;mov es:[di], ax
    mov byte ptr es:[di], '!'
    add di, 2
    ;loop s
    int 7cH
send:
    nop
    
    mov ax, 4c00H
    int 21H
code ends
end start

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

實驗13-1(p262)

# 安裝中斷例程

; DATE: 20190620
; DESCRIPTION: 編寫並安裝7cH中斷例程
;   功能爲顯示一個用0結束的字符串
assume cs:code

code segment
    mov ax, cs
    mov ds, ax
    mov si, offset show     ; ds:si
    
    mov ax, 0
    mov es, ax
    mov di, 0200H           ; es:di
    
    mov cx, offset showend - offset show
    cld
    rep movsb               ; 複製
    
    mov ax, 0
    mov es, ax
    mov word ptr es:[7cH*4], 0200H
    mov word ptr es:[7cH*4+2], 0 ; 設置中斷向量表
    
    mov ax, 4c00H
    int 21H

; 名稱:show
; 功能:顯示一個用0結束的字符串
; 參數:(dh)=行號 (dl)=列號 (cl)=顏色,ds:si指向字符串首地址
; 返回:無
show:
    push ax
    push cx
    push si
    push di
    push es         ; 保護現場
    
    mov ax, 0b800H
    mov es, ax      ; es:di指向顯示緩衝區
    
    mov al, dh
    mov ah, 160
    mul ah          ; 行號*160
    mov di, ax
    
    mov al, dl
    mov ah, 2
    mul ah          ; 列號*2
    add di, ax      
    
    mov ah, cl
showbegin:
    mov al, [si]
    cmp al, 0
    je showret
    mov word ptr es:[di], ax
    inc si
    add di, 2
    jmp short showbegin
showret:
    pop es
    pop di
    pop si
    pop cx
    pop ax          ; 恢復現場
    iret
showend:
    nop
    
code ends
end

# 測試中斷例程

; DATE: 20190620
; DESCRIPTION: 調用自定義的7cH中斷例程
;   顯示一個用0結束的字符串

assume cs:code

data segment
    db "Welcome to masm!", 0
data ends

code segment
start:
    mov dh, 10
    mov dl, 10
    mov cl, 2
    mov ax, data
    mov ds, ax
    mov si, 0
    ; 參數:(dh)=行號 (dl)=列號 (cl)=顏色
    ; ds:si指向字符串首地址
    int 7cH
    
    mov ax, 4c00H
    int 21H
code ends
end start

# 執行結果


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

實驗13-2(p263)

# 安裝中斷例程

; DATE: 20190620
; DESCRIPTION: 編寫並安裝7cH中斷例程
;   功能爲完成loop指令功能
assume cs:code

code segment
    mov ax, cs
    mov ds, ax
    mov si, offset myloop   ; ds:si
    
    mov ax, 0
    mov es, ax
    mov di, 0200H           ; es:di
    
    mov cx, offset myloopend - offset myloop
    cld
    rep movsb               ; 安裝中斷例程
    
    mov ax, 0
    mov es, ax
    mov word ptr es:[7cH*4], 0200H
    mov word ptr es:[7cH*4+2], 0 ; 設置中斷向量表

    mov ax, 4c00H
    int 21H
    
; 名稱:myloop
; 功能:完成loop指令功能
; 參數:(cx)=循環次數 (bx)=位移
; 返回:無
myloop:
    push bp
    
    dec cx
    jcxz myloopret
    mov bp, sp
    add [bp+2], bx
myloopret:
    pop bp
    iret
myloopend:
    nop
    
code ends
end

# 測試中斷例程

; DATE: 20190620
; DESCRIPTION: 調用自定義的7cH中斷例程
;   在屏幕中間顯示80個'!'
assume cs:code
code segment
    mov ax, 0b800H
    mov es, ax
    mov di, 12*160  ; es:di
    
    mov cx, 80
    mov bx, offset s - offset send
s:
    mov byte ptr es:[di], '!'
    add di, 2
    int 7cH
send:
    nop
    
    mov ax, 4c00H
    int 21H
code ends
end

# 執行結果


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

實驗13-3(p264)

; DATE: 20190620
; DESCRIPTION: 分別在屏幕第2、4、6、8行顯示4句話
assume cs:code

code segment
s1: db 'Good, better, best,', '$'
s2: db 'Never let it rest,', '$'
s3: db 'Till good is better,', '$'
s4: db 'And better, best.', '$'
s : dw offset s1, offset s2, offset s3, offset s4
row: db 2,4,6,8

start:
    mov ax, cs
    mov ds, ax
    mov bx, offset s
    mov si, offset row
    mov cx, 4
ok:
    mov bh, 0   ; 頁
    mov dh, [si] ; 行
    mov dl, 0   ; 列號
    mov ah, 2   ; 第10H號中斷例程的2號子程序:置光標
    int 10H
    
    mov dx, [bx] ; ds:dx指向字符串,字符串以'$'作爲結束符
    mov ah, 9   ; 第21H號中斷例程的9號子程序:在光標位置顯示字符串
    int 21H
    
    inc si
    add bx, 2
    loop ok

    mov ax, 4c00H
    int 21H
code ends
end start

# 執行結果


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

實驗14(p271)

# 法一:直接寫入顯示緩衝區

; DATE: 20190621
; DESCRIPTION: 從CMOS RAM中讀取當前時間,
;       並以"年/月/日 時:分:秒"的格式顯示
assume cs:code
code segment
addres: db 9,8,7,4,2,0      ; 單元的地址

start:
    mov ax, cs
    mov ds, ax
    mov si, offset addres
    
    mov ax, 0b800H          ; 顯示緩衝區
    mov es, ax
    mov di, 12*160+35*2
    
    ; 將分隔符寫入顯示緩衝區
    mov byte ptr es:[di+4], '/'
    mov byte ptr es:[di+10], '/'
    mov byte ptr es:[di+16], ' '
    mov byte ptr es:[di+22], ':'
    mov byte ptr es:[di+28], ':'
    
    mov cx, 6
time:
    push cx         ; 保護循環次數
    mov al, [si]
    out 70H, al ; 將單元號送入端口70H
    in al, 71H  ; 從端口71H讀出該單元的內容
    
    mov ah, al
    mov cl, 4
    shr ah, cl          ; 右移4位
    and al, 00001111B   ; 得到低字節
    add ah, 30H         ; 將數字轉爲字符
    add al, 30H
    
    mov es:[di], ah     ; 寫入顯示緩衝區
    mov es:[di+2], al
    
    inc si
    add di, 6
    pop cx
    loop time

    mov ax, 4c00H
    int 21H
code ends
end start

# 執行結果

# 法二:調用DOS的第21H號中斷例程的9號子程序:在光標位置顯示字符串

; DATE: 20190621
; DESCRIPTION: 從CMOS RAM中讀取當前時間,
;       並以"年/月/日 時:分:秒"的格式顯示
assume cs:code
code segment
addres: db 9,8,7,4,2,0  ; 單元的地址
date  : db '2000/00/00 00:00:00', '$'

start:
    mov ax, cs
    mov ds, ax
    mov si, offset addres   ; ds:si
    mov di, offset date     ; ds:di
    add di, 2
    
    mov cx, 6
time:
    push cx         ; 保護循環次數
    mov al, [si]
    out 70H, al ; 將單元號送入端口70H
    in al, 71H  ; 從端口71H讀出該單元的內容
    
    mov ah, al
    mov cl, 4
    shr ah, cl
    and al, 00001111B
    add ah, 30H
    add al, 30H
    
    mov [di], ah    ; 寫入字符串ds:di中
    mov [di+1], al
    
    inc si
    add di, 3
    pop cx
    loop time
    
    mov bh, 0   ; 頁
    mov dh, 12  ; 行號
    mov dl, 35  ; 列號
    mov ah, 2   ; 第10H號中斷例程的2號子程序:置光標
    int 10H
    
    mov dx, offset date ; ds:dx指向字符串,字符串以'$'作爲結束符
    mov ah, 9   ; 第21H號中斷例程的9號子程序:在光標位置顯示字符串
    int 21H

    mov ax, 4c00H
    int 21H
code ends
end start

# 執行結果


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

實驗15(p285)

; DATE: 20190622
; DESCRIPTION: 在DOS下,按'A'鍵後鬆開時顯示滿屏幕的‘A’,其他的鍵照常處理
;
; 已知:int 9爲BIOS提供的一箇中斷例程,用來進行基本的鍵盤輸入處理
assume cs:code

stack segment
    db 128 dup (0)
stack ends

code segment
start:
    mov ax, stack
    mov ss, ax
    mov sp, 128         ; ss:sp
    
    push cs
    pop ds
    mov si, offset int9 ; ds:si指向源地址
    
    mov ax, 0
    mov es, ax
    mov di, 204H        ; es:di指向目的地址
    
    ; 將新int 9中斷例程安裝在0:204開始處
    mov cx, offset int9end - offset int9 ; cx傳輸長度
    cld         ; 將DF標誌位置0,即傳輸方向爲正
    rep movsb   ; 從ds:si複製到es:di
    
    ; 將原int 9中斷例程的入口地址保存到0:200單元
    ; 所以,程序二次執行將出錯
    push es:[9*4]
    pop es:[200H]
    push es:[9*4+2]
    pop es:[202H]
    
    ; 將新int 9中斷例程的入口地址保存到中斷向量表
    cli     ; 將IF標誌位置0,不響應可屏蔽中斷
    mov word ptr es:[9*4], 204H
    mov word ptr es:[9*4+2], 0
    sti     ; 將IF標誌位置1,響應可屏蔽中斷
    
    mov ax, 4c00H
    int 21H
    
int9:
    push ax
    push bx
    push cx
    push es
    
    in al, 60H  ; 從端口60H讀出鍵盤的輸入
    
    pushf       ; 標誌寄存器入棧
    call dword ptr cs:[200H] ; 當此中斷例程執行時(CS)=0
    
    cmp al, 1eH+80H ; 'A'鍵按下的掃描碼爲3bH,即通碼; 鬆開時的斷碼=通碼+80H
    jne int9ret

    ; 顯示滿屏幕的‘A’
    mov ax, 0b800H
    mov es, ax
    mov bx, 0
    mov cx, 2000
s:  mov byte ptr es:[bx], 'A'
    add bx, 2
    loop s 
    
int9ret:
    pop es
    pop cx
    pop bx
    pop ax
    iret
int9end:
    nop
code ends
end start

# 執行結果


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

實驗16(p299)

# 安裝中斷例程

; DATE: 20190622
; DESCRIPTION: 安裝一個新的int 7cH中斷例程,提供以下功能子程序:
;   1)清屏;2)設置前景色;3)設置背景色;4)向上滾動一行
;   入口參數:ah功能號 0~3;al顏色值 0~7

assume cs:code

code segment
start:
    mov ax, cs
    mov ds, ax
    mov si, offset setscreen    ; ds:si 指向源地址
    
    mov ax, 0
    mov es, ax
    mov di, 200H                ; es:di 指向目的地址
    
    ; 將新int 9中斷例程安裝在0:200開始處
    cld     ; 將DF標誌位置0,即傳輸方向爲正
    mov cx, offset setend - offset setscreen ; cx傳輸長度
    rep movsb   ; 從ds:si複製到es:di
    
    ; 將新int 9中斷例程的入口地址保存到中斷向量表
    cli     ; 將IF標誌位置0,不響應可屏蔽中斷
    mov word ptr es:[7cH*4], 200H
    mov word ptr es:[7cH*4+2], 0
    sti     ; 將IF標誌位置1,響應可屏蔽中斷

    mov ax, 4c00H
    int 21H
    
    ; 注意此處必須用org
    ; 否則,將編譯後的table[bx]複製到0:200H後,會指向未知位置
    org 200H    ; 通知編譯器從200H開始重新計算標號

setscreen:
    jmp short set

table dw sub1,sub2,sub3,sub4 ; 查表,4個子程序的入口地址

set:
    push bx
    
    cmp ah, 3   ; 判斷功能號是否大於3
    ja sret
    mov bl, ah
    mov bh, 0
    add bx, bx  ; 根據ah功能號計算子程序在table中的偏移
    call word ptr table[bx] ; 調用對應的子程序
sret:    
    pop bx
    iret        ; 中斷返回

; ------ 4個子程序 ------
; ------ 子程序:清屏 ------
sub1:
    push bx
    push cx
    push es
    
    mov bx, 0b800H
    mov es, bx  ; 此處使用bx節約了寄存器
    mov bx, 0   ; es:bx指向顯示緩衝區
    
    mov cx, 2000 ; 25行*80列
sub1s:
    mov byte ptr es:[bx], ' '
    add bx, 2
    loop sub1s  ; 清屏
    
    pop es
    pop cx
    pop bx
    ret

; ------ 子程序:設置前景色 ------    
sub2:
    push bx
    push cx
    push es

    mov bx, 0b800H
    mov es, bx
    mov bx, 1   ; es:bx指向顯示緩衝區
    
    mov cx, 2000
sub2s:
    ; 高字節爲顏色屬性,前景色爲第0、1、2位
    and byte ptr es:[bx], 11111000B
    or es:[bx], al
    add bx, 2 
    loop sub2s
    
    pop es
    pop cx
    pop bx
    ret

; ------ 子程序:設置背景色 ------      
sub3:
    push bx
    push cx
    push es

    mov bx, 0b800H
    mov es, bx
    mov bx, 1   ; es:bx指向顯示緩衝區

    mov cl, 4
    shl al, cl
    mov cx, 2000
sub3s:
    ; 高字節爲顏色屬性,背景色爲第4、5、6位
    and byte ptr es:[bx], 10001111B
    or es:[bx], al
    add bx, 2 
    loop sub3s
    
    pop es
    pop cx
    pop bx
    ret

; ------ 子程序:向上滾一行 ------      
sub4:
    push cx
    push ds
    push es
    push si
    push di

    mov si, 0b800H
    mov ds, si
    mov es, si
    mov si, 160     ; ds:si指向源地址
    mov di, 0       ; es:di指向目的地址
    
    cld     ; 將DF標誌位置0,即傳輸方向爲正
    mov cx, 24  ; 最後一行爲空
sub4s:
    push cx
    mov cx, 160     ; 每行的傳輸長度爲160Bytes
    rep movsb       ; si=si+1 di=di+1
    pop cx
    loop sub4s
    
    mov cx, 160
    mov si, 0       ; si的默認段地址爲ds
sub4s1:
    mov byte ptr [160*24+si], ' ' ; 最後一行清空
    add si, 2 
    loop sub4s1
    
    pop di
    pop si
    pop es
    pop ds
    pop cx
    ret
    
setend:
    nop
    
code ends
end start

# 測試中斷例程

assume cs:code

code segment
start:
    mov ah, 1   ; 設置前景色
    mov al, 1   ; 藍色
    int 7cH
    
    call delay  ; 延時
    
    mov ah, 2   ; 設置背景色
    mov al, 7   ; 白色
    int 7cH
    
    call delay
    
    mov ah, 3   ; 向上滾一行
    int 7cH
    
    call delay
    
    mov ah, 0   ; 清屏
    int 7cH
    
    mov ax, 4c00H
    int 21H

; ------ 循環延時 ------     
delay:
    push ax
    push dx
    mov dx, 10H ; 循環20000H次,根據自己機器的速度調整循環次數
    mov ax, 0 
s1:
    sub ax, 1 
    sbb dx, 0
    cmp ax, 0 
    jne s1 
    cmp dx, 0 
    jne s1 
    pop dx 
    pop ax 
    ret
    
code ends
end start

# 執行結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章