汇编语言-第三版-王爽-实验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

# 执行结果

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