(2011.11.09)汇编_王爽_第16章_学习小结
本章内容:
1. seg操作符,取得某一标号的段地址。offset操作符,取得某一标号的偏移地址。
2. 如何使用数据标号,描述了单元长度的标号。
3. 数值+30h = 对应字符的ASCII代码。
4. 直接定址表
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
; 程序名称:实验16_setscreen_编写多个功能子程序的中断例程.asm
; 程序功能:1. 清屏 2. 设置前景色 3.设置背景色 4. 向上滚动一行
; ------------------------------------------------------------------------------------------------ the whole program start---
assume cs:code
; -------------------------------------------------------------------------------------------statement start ---
; 段名:ss:stack
; 功能: 用于临时保存各个寄存器的数据
; 大小:共占用了128个字节,即64个字
; ---------statement end------------------------
stack segment
db 128 dup (0)
db 128 dup (0)
stack ends
;-------------------------------------------------------------------------------------------- program end---
; -------------------------------------------------------------------------------------------statement start ---
; 段名: ds:data
; 功能:用于保存int9中断例程的入口地址
; 大小:共占用两个字,即四个字节
; ---------- statement end --------------------------------
data segment
dw 0, 0
data ends
; ------------------------------------------------------------------------------------------- program end ---
code segment
start2:
; 设置中断入口
mov ax, stack ; 先设置好堆栈的地址
mov ss, ax ; 让ss:sp指向stack段的末端
mov sp, 256
mov ax, data ; 然后设置ds的地址,让其指向data段
mov ds, ax ; 目的是存放原中断向量表的地址
mov ax, 0 ; 之后是设置es的地址,令es作为段地址可以指向中断向量表
mov es, ax
push es:[9*4] ; 将中断向量表中int9的地址放入堆栈中
pop ds:[0] ; 再将地址取出放入data段中
push es:[9*4+2]
pop ds:[2] ; 将原来的int 9中断例程的入口地址保存在ds:0, ds:2单元中
mov word ptr es:[9*4], offset int9
mov es:[9*4+2], cs ; 在中断向量表中设置新的int 9中断例程的入口地址
; 新的中断入口设置完成
; 下面开始主程序
mov ax, 0b800h
mov es, ax
mov ah, 'a'
mov bx, 0
mov cx, 2000
sss:
mov es:[bx], ah
call delay
add bx, 2
loop sss
; 主程序执行完
; 下面开始将中断向量表的int 9中断例程恢复为原来的地址
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
mov ax, 4c00h
int 21h
; 主程序执行完成。
; --------------------------------------------------------------------------------------------statement start ---
; 子程序名称:delay
; 子程序的功能:不断地执行空循环,目的是时间延迟
; ---------------------statement end ---
delay:
push ax
push dx
push cx
mov cx, 9fffh
clop:
mov dx, 0 ; 循环次数2X次。
mov ax, 0
s1:
inc dx
add ax, dx
cmp ax, 9fffH ; 此处设置重复的X次
jne s1
s2:
dec dx
cmp dx, 0
jne s2
loop clop
pop cx
pop dx
pop ax
ret
; -----------------------------------------------------------------------------------------------program end ----
; --------------------------------------------------------------------------------------------statement start ---
; 子程序名称:新int 9中断例程段
; 子程序功能:设置新的int9例程,并模拟中断过程。
; 子程序分析:子程序一共分为四大步骤
; 1. 标志寄存器入栈 2. IF = 0, TF = 0 3. CS、IP入栈
; 4. (IP) = ((ds)*16+0), (CS) = ((ds)*16 +2)
; -------------statement end ---------------------------------
int9:
push ax
push bx
push es
push cx
push ds
in al, 60h ; 此处为了引发9号中断
; 当键盘的输入到达60h端口时
; 相关的芯片就会向CPU发出中断类型码为9的可屏蔽中断信息
; 如果IF = 1, 则响应中断,转去执行int9中断例程
pushf ; 此步模拟第1步,标志寄存器入栈
pushf ; 此处开始第2步,将IF及TF置零
pop bx ; 将flag寄存器中的数据从堆栈中取出,并且下面进行修改
and bh, 11111100b ; 将IF和TF置0
push bx ; 第2 步结。修改以后再将flag寄存器中的数据放回堆栈中
popf ; 第1步结.
call dword ptr ds:[0] ; 第3步,CS:IP入栈.对int指令进行模拟,调用原来的int 9中断指令
cmp al, 0Bh
je functions ; 等于零
cmp al, 02
jb int9ret ; 小于1
cmp al, 04
ja int9ret ; 大于3
functions:
mov ah, 0 ; 扫描码转化成数字
cmp al, 0Bh
je ss3
cmp al, 02
je ss2
cmp al, 03
je ss1
cmp al, 04
je ss0
ss0:
inc ah
ss1:
inc ah
ss2:
inc ah
ss3:
mov al, 0101b
call setscreen
int9ret:
pop ds
pop cx
pop es
pop bx
pop ax
iret
; ----------------------------------------------------------------------------------------------------program end ----------------
; ---------------------------------------------------------------------------------------- statement start ------
; 子程序名称:setscreen
; 子程序功能:将0.清屏,1.设置前景色,2.设置背景色,3.向上滚动一行 四种功能封装在这函数中。
; 子程序参数:ah为功能号0,1,2,3, al为颜色值(对于1,2功能的)
; 功能号*2 = 对应的功能子程序在地址表中的偏移。
; -----------------------------------------------------------------------------------------statement end -----
setscreen:
jmp short set
table dw sub1, sub2, sub3, sub4
set:
push bx ; 因为下面要用到bx,为了防止对其它子程序造成影响,先将bx放入堆栈中。
cmp ah, 3 ; 判断功能号是否大于3,大于3则不执行任何操作
ja sret
mov bl, ah
mov bh, 0
add bx, bx ; 根据ah中的功能号按*2计算在table中的地址
call word ptr table[bx] ; 调用相对应的功能子程序
sret:
pop bx
ret
;--------------------------------------------------------------------------------------------------------------- program end -----
; ------------------------------------------------------------------------------------------ statement start -----
; 子程序名称:sub1
; 子程序功能:清屏:将显存中当前屏幕中的字符设为空格符。
; --------------------------------------- statement end --------
sub1:
push bx
push cx
push es
mov bx, 0b800h
mov es, bx ; 设置显示区域的地址
mov bx, 0
mov cx, 2000 ; 一屏有80*25 = 2000 个字符
sub1s:
mov byte ptr es:[bx], ' '
add bx, 2 ; 高位存放字符,低位存放属性,所以步进为2
loop sub1s
pop es
pop cx
pop bx
ret
;---------------------------------------------------------------------------------------------------------------- program end -----
; ---------------------------------------------------------------------------------------------statement start -----
; 子程序名称:sub2
; 子程序功能:设置前景色,设置显存中当前屏幕中处于奇地址的属性字节的第0, 1, 2位
; --------------------------------------- statement end --------
sub2:
push bx
push cx
push es
mov bx, 0b800h
mov es, bx
mov bx, 1 ; 字符属性区域从下标1开始
mov cx, 2000 ; 一屏需要设置2000个属性
sub2s:
and byte ptr es:[bx], 11111000b ; 在使用颜色设置时,先将该属性清零
or es:[bx], al ; 结合al,设置前景色
add bx, 2 ; 步进为2,原因为2个字节存放一个字符
loop sub2s
pop es
pop cx
pop bx
ret
;---------------------------------------------------------------------------------------------------------------- program end -----
; ---------------------------------------------------------------------------------------------statement start -----
; 子程序名称:sub3
; 子程序功能:设置背景色,设置显存中当前屏幕中处于奇地址的属性字节的第4, 5, 6位
; --------------------------------------- statement end --------
sub3:
push bx
push cx
push es
mov cl, 4
shl al, cl ; 将属性左移至正确的位置
mov bx, 0b800h
mov es, bx
mov bx, 1 ; 字符属性区域从下标1开始
mov cx, 2000 ; 一屏需要设置2000个属性
sub3s:
and byte ptr es:[bx], 10001111b ;将背景色属性清零
or es:[bx], al ; 结合al,设置背景色
add bx, 2 ; 步进为2,原因为2个字节存放一个字符
loop sub3s
pop es
pop cx
pop bx
ret
;---------------------------------------------------------------------------------------------------------------- program end -----
; ---------------------------------------------------------------------------------------------statement start -----
; 子程序名称:sub4
; 子程序功能:使屏幕显示向上滚动一行:依次将第n+1行的内容复制到第n行处:最后一行为空。
; --------------------------------------- statement end --------
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行
; 将下一行移上, mov es:[di], byte ptr ds:[si]
cld ; 设置正方向递增, DF = 0
mov cx, 24 ; 共复制24行
sub4s:
push cx ; 此处需要内嵌循环,先将cx存放
mov cx, 160
rep movsb ; 复制160列
pop cx
loop sub4s ; 再复制21行
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
;---------------------------------------------------------------------------------------------------------------- program end -----
code ends
end start2
;---------------------------------------------------------------------------------------------------------------- the whole program end -----