实验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
# 执行结果