|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
实验16
这个实验比较有趣,光看书写出来的程序总是运行不正确
不断调试后才发现原来是在偏移地址的计算中出现了错误
以下情况是在代码中int 7ch中断例程放在start前讨论的,至于为什么要写在前面,之后说明
table dw sub1, sub2, sub3, sub4
这里面sub1,sub2等等的偏移地址在未安装前是相对于代码段即code而言的
因为编译时程序的偏移地址已经计算好放在table表中,这里JMP指令占3个字节,table占8个字节,所以sub1的偏移地址为000BH,安装后物理地址为0020BH
如果在安装程序时继续将中断向量表设置为0000H:0200H
那么问题出来了,假设输入0,table的段地址默认是cs,偏移地址是3,在call word ptr table[bx]时,(table[bx])的实际值,3+0=3,则最终转移的物理地址是(0000H:0003H)=?,显然这和预期中的物理地址(0000H:0203H)=0020BH差得太远
所以在设置中断向量表时,应该设成0020H:0000H,这样在计算转移地址时算出来的值是(0020H:0003H),和(0000H:0203H)一样
相信看到这里也就明了了为什么要把中断例程放在start前面,因为容易计算偏移地址来设置中断向量表
assume cs:code, ss:stack
; ****************************************
; 堆栈段
stack segment
db 128 dup(0)
stack ends
; ****************************************
; ****************************************
; 代码段
code segment
; **************************************************
; 新int 7ch中断例程:
; (1) 清屏
; (2) 设置前景色
; (3) 设置背景色
; (4) 向上滚动一行
; 入口参数:
; (1) ah寄存器传递功能号:0清屏,1设置前景色,2设置背景色,3向上滚动一行
; (2) 对于2、3功能,用al传送颜色值,(al)∈{0, 1, 2, 4, 5, 6, 7}
int7ch:
jmp set
table dw sub1, sub2, sub3, sub4 ; 功能子程序表
; ****************************************
; 子程序sub1:
; 清屏
sub1:
push cx
push di
push es
mov di, 0b800h
mov es, di
mov di, 0 ; es:di指向显示区字符
mov cx, 2000 ; 一屏可显示2000个字符
sub1s:
mov byte ptr es:[di], ' '
add di, 2
loop sub1s
pop es
pop di
pop cx
ret
; ****************************************
; ****************************************
; 子程序sub2:
; 设置前景色
sub2:
push cx
push di
push es
mov di, 0b800h
mov es, di
mov di, 1 ; es:di指向显示区字符属性
mov cx, 2000 ; 一屏有2000个字符
sub2s:
and byte ptr es:[di], 11111000b ; 前景色属性为0,1,2位
or es:[di], al
add di, 2
loop sub2s
pop es
pop di
pop cx
ret
; ****************************************
; ****************************************
; 子程序sub3:
; 设置背景色
sub3:
push cx
push di
push es
mov di, 0b800h
mov es, di
mov di, 1 ; es:di指向显示区字符属性
mov cl, 4
shl al, cl
mov cx, 2000 ; 一屏有2000个字符
sub3s:
and byte ptr es:[di], 10001111b ; 背景色属性为4,5,6位
or es:[di], al
add di, 2
loop sub3s
pop es
pop di
pop cx
ret
; ****************************************
; ****************************************
; 子程序sub4:
; 向上滚动一行
sub4:
push cx
push ds
push si
push es
push di
mov si, 0b800h
mov ds, si
mov es, si
mov si, 160 ; ds:si指向n+1行
mov di, 0 ; es:di指向n行
cld ; 复制方向为正
mov cx, 24 ; 复制24行
sub4s:
push cx
mov cx, 160 ; 一行有160个字节
rep movsb
pop cx
loop sub4s
pop di
pop es
pop si
pop ds
pop cx
ret
; ****************************************
set:
push bx
mov bl, ah
mov bh, 0
add bx, bx ; 根据功能号计算对应子程序在table表中的偏移
call word ptr table[bx]
pop bx
iret
int7chend:
nop
; **************************************************
start:
mov ax, stack
mov ss, ax
mov sp, 128 ; ss:sp指向堆栈段
push cs
pop ds
mov si, offset int7ch ; ds:si指向源地址
mov ax, 0
mov es, ax
mov di, 200H ; es:di指向目标地址
mov cx, offset int7chend-offset int7ch ; 传输长度
cld ; 传输方向为正
rep movsb ; 安装中断向量
mov word ptr es:[7ch*4], 0 ; 设置中断向量表
mov word ptr es:[7ch*4+2], 20H ; 20H:0为相对中断入口偏移
mov ah, 1 ; 选择功能
int 21h
sub al, 30h ; ASCII转换成数字
mov ah, al
cmp ah, 3
ja exit ; 大于3则结束
je setscreen ; 等于3则执行中断
cmp ah, 0
je setscreen ; 等于0则执行中断
mov bh, ah ; 暂时保存功能号
mov ah, 1 ; 输入颜色
int 21h
mov ah, bh ; 还原功能号
sub al, 30h ; ASCII转换成数字
cmp al, 7
ja exit ; 大于7则结束
setscreen:
int 7ch
exit:
mov ax, 4c00h
int 21h
code ends
end start
; ****************************************
|
|