《汇编语言》王爽(第四版) 第十六章 实验16

文章目录

前言

一、实验任务

二、思路分析

1.程序框架

2.设置前景色

3.设置背景色

三、最终成果

1.完整代码

2.效果图

总结


前言

本文是王爽老师《汇编语言》(第四版) 第十六章 实验16 编写包含多个功能子程序的中断例程 的分析及代码。

子程序功能:清屏;设置前景色;设置背景色;向上滚动一行。

(最后附完整代码)


一、实验任务

本次实验任务:

安装一个新的int 7CH 中断例程,为显示输出提供如下功能子程序。

(1)清屏;

(2)设置前景色;

(3)设置后景色;

(4)向上滚动一行。

入口参数说明如下。

(1)用ah寄存器传递功能号:0表示清屏,1表示设置前景色,2表示设置背景色,3表示向上滚动一行;

(2)对于1、2号功能,用al传送颜色值,al的值∈{0,1,2,3,4,5,6,7}。

二、思路分析

下面对一些关键点进行分析。

1.程序框架

首先来设计程序框架。

(1)要有一个子程序install,功能是将int 7CH中断例程安装到内存中。这个功能以前写过,这里不再赘述。

(2)对于多个功能的子程序,根据书上讲的思路,应当用“cmp” 和“ je ”这两个指令的组合来实现查找对应子程序的功能,这样程序结构清晰,扩展性良好。这类似于java语法中的switch-case语句。

以下是程序的基本框架。

    ;实验16:编写包含多个功能子程序的中断例程
assume cs:code
stack segment
    db 64 dup(0)
stack ends
code segment
start:
    mov ax,stack    ;设置栈顶
    mov ss,ax
    mov sp,40H

    call install    ;安装7CH中断例程

    mov ah,0        ;设置子程序功能号
    mov al,1H       ;指定程序参数
    int 7CH         ;触发7CH中断例程

    mov ax,4c00H
    int 21H
install:    ;功能:将7CH中断例程安装在内存0:200H处
        ;参数:无
        ;返回:无
    ret
do7CH:      ;7CH中断例程 功能:包含设置屏幕属性的4个子程序
        ;参数:ah 功能号; al 颜色参数
        ;返回:无

    ;根据功能号,跳转到对应的子程序地址中    
    cmp ah,0
    je do1
    cmp ah,1
    je do2
    cmp ah,2
    je do3
    cmp ah,3
    je do4
    jmp do7CH_ret   ;子程序执行完毕,就返回

    ;这部分相当于子程序地址表
    do1:    call sub1
            jmp short do7CH_ret
    do2:    call sub2
            jmp short do7CH_ret
    do3:    call sub3
            jmp short do7CH_ret
    do4:    call sub4
            jmp short do7CH_ret
    
    ;程序返回
    do7CH_ret:
    iret

    sub1:   ;功能:清屏
        ret
    sub2:   ;功能:设置前景色
        ret
    sub3:   ;功能:设置背景色
        ret
    sub4:   ;功能:向上滚动一行
        ret

do7CH_end:nop   ;中断例程代码结尾处
code ends
end start

2.设置前景色

这里的设置方法值得注意。and 指令的功能是将属性字节(8个2进制位)的低3位置为0,其它位保持不变;or指令的功能是将属性字节的低3位设置为指定的颜色值(即al中的低三位)。这个设置方法颇为巧妙。

其中注意,在and指令中一定要写上“byte ptr”,否则,编译时不会报错但运行时会出错,因为编译器会默认翻译为“and word ptr es:[si],0000 0000 1111 1000B ”

这部分代码如下。

        mov bx,0B800H   ;设置es:si指向显存首个字符属性字节
        mov es,bx
        mov si,1

        mov cx,2000     ;修改2000个字符属性字节的前景色
        s_sub2:
        and byte ptr es:[si],11111000B   ;将属性字节最低3位置为0
        or es:[si],al   ;将属性字节最低3位设置为指定值
        add si,2
        loop s_sub2

3.设置背景色

对于属性字节,有0-7共8位二进制位,其中012三位用来设置前景色,取值范围0-7,而456位用来设置背景色,取值范围也是0-7 。al参数,其中存放的值就是0-7,假如是7,那么al=0000 0111 B 。而要通过and 指令与 or指令来设置背景色,就要将al修改为0111 0000 B。因此需要将al执行逻辑左移4次的操作。代码如下。

mov cl,04H    ;将颜色参数al的有效位从012位移到456位
shl al,cl

三、最终成果

1.完整代码

完整代码如下。

    ;实验16:编写包含多个功能子程序的中断例程
assume cs:code
stack segment
    db 64 dup(0)
stack ends
code segment
start:
    mov ax,stack    ;设置栈顶
    mov ss,ax
    mov sp,40H

    call install    ;安装7CH中断例程

    mov ah,2        ;设置子程序功能号
    mov al,1H       ;指定程序颜色参数
    int 7CH         ;触发7CH中断例程

    mov ax,4c00H
    int 21H
install:    ;功能:将7CH中断例程安装在内存0:200H处
        ;参数:无
        ;返回:无

    push ax
    push ds
    push si
    push es
    push di
    push cx
    
    ;1.将中断例程代码复制到0:200H处

    mov ax,cs   ;ds:si指向复制的源地址首地址
    mov ds,ax
    mov si,offset do7CH
    mov ax,0    ;es:di指向复制的目标地址首地址
    mov es,ax
    mov di,200H
    mov cx,offset do7CH_end - offset do7CH  ;设置数据长度
    rep movsb   ;复制数据

    ;2.将中断例程入口地址写入中断向量表
    mov word ptr es:[7CH*4],200H    ;偏移地址
    mov word ptr es:[7CH*4+2],0     ;段地址

    pop cx
    pop di
    pop es
    pop si
    pop ds
    pop ax
    
    ret
do7CH:      ;7CH中断例程 功能:包含设置屏幕属性的4个子程序
        ;参数:ah 功能号; al 颜色参数
        ;返回:无

    ;根据功能号,跳转到对应的子程序地址中    
    cmp ah,0
    je do1      ;清屏
    cmp ah,1
    je do2      ;设置前景色
    cmp ah,2
    je do3      ;设置背景色
    cmp ah,3
    je do4      ;向上滚动一行

    jmp do7CH_ret   ;子程序执行完毕,程序返回

    ;这部分相当于子程序地址表
    do1:    call sub1   
            jmp short do7CH_ret
    do2:    call sub2   
            jmp short do7CH_ret
    do3:    call sub3
            jmp short do7CH_ret
    do4:    call sub4
            jmp short do7CH_ret
    
    ;程序返回
    do7CH_ret:
    iret

    sub1:   ;功能:清屏
        ;参数:无
        ;返回:无

        push ax
        push es
        push si
        push cx

        mov ax,0B800H   ;es:si指向显存首地址
        mov es,ax 
        mov si,0

        mov al,0        ;空格的ASCII码是0
        mov cx,2000     ;将屏幕中每一个字符字节都写为0
        s_sub1:
        mov es:[si],al
        add si,2
        loop s_sub1

        pop cx
        pop si
        pop es
        pop ax
        ret
    sub2:   ;功能:设置前景色
        ;参数:al前景色,范围0-7
        ;返回:无

        push bx
        push es
        push si
        push cx

        mov bx,0B800H   ;设置es:si指向显存首个字符属性字节
        mov es,bx
        mov si,1

        mov cx,2000     ;修改2000个字符属性字节的前景色
        s_sub2:
        and byte ptr es:[si],11111000B   ;将属性字节最低3位置为0
        or es:[si],al   ;将属性字节最低3位设置为指定值
        add si,2
        loop s_sub2
        
        pop cx
        pop si
        pop es
        pop bx
        ret
    sub3:   ;功能:设置背景色
        ;参数:al 背景色,范围0-7
        ;返回:无

        push bx
        push es
        push cx
        push si
        push ax

        mov bx,0B800H   ;es:si指向显存首个字符属性字节
        mov es,bx
        mov si,1H   

        mov cx,0004H    ;将颜色参数al的有效位从012位移到456位
        shl al,cl

        mov cx,2000     ;将屏幕中每个字符的属性字节中的背景色都进行修改
        s_sub3:
        and byte ptr es:[si],10001111B  ;将属性字节的456位(即背景色的位置)置为0
        or es:[si],al    ;将属性字节的背景色位(456位)设置为指定值(即al)
        add si,2
        loop s_sub3
       
        pop ax
        pop si
        pop cx
        pop es
        pop bx
        
        ret
    sub4:   ;功能:向上滚动一行
        ;参数:无
        ;返回:无
        
        ;实现思路:从n=0开始,将n+1行的内容复制到第n行,最后一行为空白

        push ax
        push es
        push ds
        push si
        push di

        mov ax,0B800H   ;es:di指向复制的目标地址
        mov ds,ax       ;ds:si指向复制的源地址
        mov es,ax
        mov si,160
        mov di,0

        mov cx,24       ;复制24行
        s_sub4:
        push cx
        mov cx,160*2      ;每行复制160个字符
        rep movsb
        pop cx
        loop s_sub4     ;继续下一行

        mov cx,160      ;将最后一行设置为空白
        mov al,0
        s_sub4_1:
        mov ds:[si],al
        add si,2
        loop s_sub4_1

        pop di
        pop si
        pop ds
        pop es
        pop ax
        ret

    do7CH_end:nop   ;中断例程代码结尾处

code ends
end start

2.效果图


总结

本文是王爽老师《汇编语言》(第四版) 第十六章 实验16 编写包含多个功能子程序的中断例程 的分析及代码。通过这个实验,练习了在一个中断例程(或者子程序)中如何结构清晰地设计多个功能子程序,且保持良好的可扩展性,这是非常实用的编程方法。

猜你喜欢

转载自blog.csdn.net/Dr_Cheeze/article/details/127784620
今日推荐