正在加载……
专注、离线、切勿分心
实现一个子程序 setscreen,为显示输出提供如下功能:
① 清屏
② 设置前景色
③ 设置背景色
④ 向上滚动一行
入口参数说明:
① 用 ah 寄存器传递功能号:0表示清屏,1表示设置前景色,2表示设置背景色,3表示向上滚动一行;
② 对于2、3号功能,用 al 传送颜色值,(al)∈{0,1,2,3,4,5,6,7}


assume cs:code
code segment
start:        mov ax , cs
        mov ds , ax
        mov si , offset setscreen
        mov ax , 0
        mov es , ax
        mov di , 200h
        mov cx , offset setscreenend - offset setscreen
        cld
        rep movsb

        mov ax , 0
        mov es , ax
        mov word ptr es:[7ch*4] , 200h
        mov word ptr es:[7ch*4+2] , 0

        mov ah , 1        ; 功能1 设置前景色
        mov al , 1        ; 蓝色
        int 7ch
        call delay

        mov ah , 2        ; 功能2 设置背景色
        mov al , 3        ; 红色
        int 7ch
        call delay

        mov ah , 3        ; 功能3 向上滚动一行
        int 7ch
        call delay

        mov ah , 0        ; 清屏
        int 7ch
        call delay

        mov ax , 4c00h
        int 21h

delay:        push ax
        push dx
        mov dx , 6h
        mov ax , 0
s:        sub ax , 1
        sbb dx , 0
        cmp ax , 0
        jne s
        cmp dx , 0
        jne s
        pop dx
        pop ax
        ret

        org 200h        ; 伪指令,表示下一条指令从偏移地址200h开始;因为我们把下面的中断例程安装到了0:200h
; 如果没有org 200h,中断例程安装到指定位置后,标号所代表的相对偏移地址也变了,是从200h开始算偏移的,和编译文件的时候不一样了,后面call不能找到我们要的执行代码;







setscreen:        jmp short set        ; 调试的时候变成 jmp 020Ah
; 这条命令是段内短转移,set的偏移是从当前指令开始计算的,所以前面写的代码,不用org也不会出错。
        table dw sub1 , sub2 , sub3 , sub4 ; 这里的值在编译的时候编译器就设置好了
set:        push bx
        cmp ah , 3
        ja sret
        mov bl , ah
        mov bh , 0
        add bx , bx
        call word ptr table[bx]                ; 程序编译到这里的时候 CS是当前程序CS:IP的CS
;等到中断程序安装好后,table==cs:200h,cs==0;执行到这里的时候CS==0
sret:        pop bx
        iret


sub1:        push bx                ; 清屏
        push cx
        push es
        mov bx , 0b800h
        mov es , bx
        mov bx , 0
        mov cx , 2000
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
        mov cx , 2000
sub2s:        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 cl , 4
        shl al , cl
        mov bx , 0b800h
        mov es , bx
        mov bx , 1
        mov cx , 2000
sub3s:        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 si
        push di
        push es
        push ds
        mov si , 0b800h
        mov es , si
        mov ds , si
        mov si , 160
        mov di , 0
        cld
        mov cx , 24
sub4s1:        push cx
        mov cx , 160
        rep movsb
        pop cx
        loop sub4s1
        mov cx , 80
        mov si , 0
sub4s2:        mov byte ptr [160*24+si] , ' '
        add si , 2
        loop sub4s2
        pop ds
        pop es
        pop di
        pop si
        pop cx
        ret
setscreenend:        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 , 2        ; 颜色值
        int 7ch
        mov ah , 3
        int 7ch
        call delay
        mov ah , 0
        int 7ch

        mov ax , 4c00h
        int 21h

delay:        push ax
        push dx
        mov dx , 5h
        mov ax , 0
s:        sub ax , 1
        sbb dx , 0
        cmp ax , 0
        jne s
        cmp dx , 0
        jne s
        pop dx
        pop ax
        ret
code ends
end
; 上面的程序不分开来写的话,还可以优化,在执行int 21h中断前恢复原来7ch的中断例程入口地址
assume cs:code
stack segment
        db 128 dup (0)
stack ends
code segment
start:        mov ax , cs
        mov ds , ax
        mov si , offset setscreen
        mov ax , 0
        mov es , ax
        mov di , 204h
        mov cx , offset setscreenend - offset setscreen
        cld
        rep movsb

        mov ax , stack
        mov ss , ax
        mov sp , 128

        push es:[7ch*4]                ; 保存原7ch的中断例程入口地址
        pop es:[200h]
        push es:[7ch*4+2]
        pop es:[202h]

        mov word ptr es:[7ch*4] , 204h
        mov word ptr es:[7ch*4+2] , 0
; 这里是自己调用中断号测试代码和延迟代码(没放上来)
        push es:[200h]                ; 恢复原7ch的中断例程入口地址
        pop es:[7ch*4]
        push es:[202h]
        pop es:[7ch*4+2]

        mov ax , 4c00h
        int 21h









posted on 2017-09-30 19:21  正在加载……  阅读(211)  评论(0编辑  收藏  举报