assume cs:codesg
codesg segment
start:
mov bx,cs
mov ds,bx
mov si,offset setscreen
mov bx,0
mov es,bx
mov di,200h ;将中断例程安装到0:0200h处
mov cx,offset setscreenEnd - offset setscreen
cld
rep movsb
cli ;设置IF=0 防止设置中断向量时 发生中断
mov word ptr es:[7ch*4],200h
mov word ptr es:[7ch*4+2],0 ;设置新的中断向量
sti
mov ax,4c00h
int 21h
org 200h ;指定后面的程序放到从偏移地址为200h处,子程序被安装到到0:200h处时 子程序的偏移地址起始地址为200h
;而没有被安装时 刚编译完加载程序的地址为 cs:xxx xxx为 setscreen标号的所在偏移地址 不一定为200h
;把这段(表现为二进制数据形式的)指令复制到另外一块内存区域,每条指令在内存中的位置发生巨大变化,
;原来的直接定址表就不适用了,它提供的偏移地址和现在的子程序位置不对应了,程序的跳转就会失控。
setscreen:
jmp short set
table dw sub1,sub2,sub3,sub4
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 ;注意这里时iret
;功能清屏
sub1:
push cx
push es
push bx
mov cx,2000
mov bx,0b800h
mov es,bx
mov bx,0
sub1s: mov byte ptr es:[bx],' '
add bx,2
loop sub1s
pop bx
pop es
pop cx
ret
;设置前景色 低3位为前景色,al存放颜色
sub2:
push cx
push bx
push es
mov cx,2000
mov bx,0b800h
mov es,bx
mov bx,1
sub2s: and byte ptr es:[bx],11111000b
or byte ptr es:[bx],al
add bx,2
loop sub2s
pop es
pop bx
pop cx
ret
;设置背景色 第4 5 6位为背景色 al存放颜色 0000 0111
sub3:
push cx
push bx
push es
mov cx,2000
mov bx,0b800h
mov es,bx
mov bx,1
sub3s: and byte ptr es:[bx],10001111b
shl al,1
shl al,1
shl al,1
shl al,1
or byte ptr es:[bx],al ;al需要左移4位
add bx,2
loop sub3s
pop es
pop bx
pop cx
ret
;向上滚动一行 即将后面的数据依次向前复制 movsb
sub4:
push cx
push bx
push es
push ds
push di
push si
mov bx,0b800h
mov es,bx
mov ds,bx
mov si,160 ;ds:si 源地址
mov di,0 ;es:di 目的地址
mov cx,24 ;复制24行 每行160字节
cld ;cld DF=0 std DF=1 最后一个字母表示要设置的标志寄存器 cli sti
sub4s: push cx
mov cx,160 ;每160个字节一个小循环
rep movsb
pop cx
loop sub4s
mov cx,80
mov bx,0
sub4s1: mov byte ptr es:[bx],' ';最后一行 单独处理
add bx,2
loop sub4s1
pop si
pop di
pop ds
pop es
pop bx
pop cx
ret
setscreenEnd:
nop
codesg ends
end start
测试程序
assume cs:code
code segment
begin:
mov ah,2 ;测试2号程序
mov al,2 ; 闪烁 背景R G B 高亮 前景R G B
int 7CH
mov ax,4c00h
int 21H
code ends
end begin