正在加载……
专注、离线、切勿分心
编写并安装 int 7ch 中断例程,
功能:显示一个用 0 结束的字符串,中断例程安装在 0:200 处
参数:(dh)=行号,(dl)=列号,(cl)=颜色,ds:si 指向字符串首地址
assume cs:code
code segment
start:        mov ax , cs
        mov ds , ax
        mov si , offset show_str
        mov ax , 0
        mov es , ax
        mov di , 200h
        mov cx , offset show_strend - offset show_str
        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 ax , 4c00h
        int 21h

show_str:        push dx
        push cx
        push si
        mov ax , 0b800h
        mov es , ax

        mov ah , 0        ; 确保高8位为0
        mov al , 160        ; 每行160个字符
        mul dh                ; al*行号dh->ax
        mov bx , ax        ; 暂存行偏移
        mov ax , 0
        mov al , 2
        mul dl                ; 列的偏移是2,1个存字符,一个存显示属性
        add bx , ax        ; 得到偏移地址

        mov di , 0
        mov al , cl        ; 字符显示属性放到al中
        mov ch , 0        ; cx 高8位设置为0

show:        mov cl , ds:[si]        ; 将字符串单个字符读入cl中
        jcxz ok
        mov es:[bx+di] , cl
        mov es:[bx+di+1] , al
        add di , 2
        inc si
        jmp short show

ok:        pop si
        pop cx
        pop dx
        iret
show_strend:        nop       
code ends
end start
assume cs:code
data segment
        db 'Welcome to masm!' , 0
data ends
code segment
start:        mov dh , 12     ; 要显示的所在行
        mov dl , 32        ; 要显示的所在列
        mov cl , 2        ; 要传递的显示属性
        mov ax , data
        mov ds , ax
        mov si , 0        ; 入口参数DS:SI指向字符串
        int 7ch                ; 调用自己重写的中断

        mov ax , 4c00h
        int 21h
code ends
end start




编写并安装 int 7ch 中断例程
功能:完成loop指令功能
参数:(cx)=循环次数,(bx)=位移
assume cs:code
code segment
start:        mov ax , cs
        mov ds , ax
        mov si , offset lp        ; 中断例程安装
        mov ax , 0
        mov es , ax
        mov di , 200h
        mov cx , offset lpend - offset lp
        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 ax , 4c00h
        int 21h

lp:        push bp                ; 后面用到bp,保证退出不修改,先暂存
        mov bp , sp        ; 堆栈指针赋值给bp,bp对应的段寄存器和sp一样是ss
        dec cx                ; 中断实现cx-1
        jcxz lpret
        add [bp+2] , bx        ; 中断入栈的时候最后入栈的是IP,刚才bp入栈,
        ; 由于mov后bp==sp,所以+2得到IP的栈中存储位置,加上bx,实现向上跳转完成loop功能
lpret:        pop bp
        iret
lpend:        nop
code ends
end start
assume cs:code
code segment
start:        mov ax , 0b800h
        mov es , ax
        mov di , 160*12
        mov bx , offset s - offset se   ; 负位移,实现向上跳转
        mov cx , 80        ; 循环次数80
s:        mov byte ptr es:[di] , '!'
        mov byte ptr es:[di+1] , 10001100b        ; 设置显示属性,闪烁高亮红色
        add di , 2
        int 7ch                ; 修改后的 7ch 中断,实现loop s功能
se:        nop
        mov ax , 4c00h
        int 21h
code ends
end start



// 在屏幕的第2、4、6、8行显示4句英文诗
assume cs:code
code segment
        s1: db 'Good,better,best,' , '$'
        s2: db 'Never let it rest,' , '$'
        s3: db 'Till good is better,' , '$'
        s4: db 'And better,best.' , '$'
        s: dw offset s1 , offset s2 , offset s3 , offset s4
        row: db 2 , 4 , 6 , 8
start:        mov ax , 3
        int 10h                ; 调用10h号中断中的3号功能实现清屏
        mov ax , cs
        mov ds , ax
        mov si , offset s        ; si == 存储标号s:表示的数据段偏移
        mov di , offset row        ; di == 存储标号row:表示的数据段偏移
        mov cx , 4
ok:        mov bh , 0        ; 显示在0页
        mov dh , [di]        ; 显示在第2行
        mov dl , 0        ; 0 列
        mov ah , 2        ; 设置光标位置
        int 10h

        mov dx , [si]        ; [si]==offset s,取出值就是s1的位移
        mov ah , 9        ; 9号功能,显示ds:dx处以'$'结尾的字符串
        int 21h

        add si , 2        ; 偏移设置下一个要显示的字符串
        inc di                ; 偏移设置下一个行要显示的位置
        loop ok

        mov ax , 4c00h
        int 21h
code ends
end start




10h 号中断的2号设置光标位置功能不会自动偏移光标,所以必须每次dl+1
改进:不用21h号中断的一次显示一行字符串,全用10h号中断显示,并设定相应的颜色
assume cs:code
code segment
        s1: db 'Good,better,best,' , 0
        s2: db 'Never let it rest,' , 0
        s3: db 'Till good is better,' , 0
        s4: db 'And better,best.' , 0
        s: dw offset s1 , offset s2 , offset s3 , offset s4
        row: db 0 , 2 , 4 , 6
start:        mov ax , 3
        int 10h                ; 调用10h号中断中的3号功能实现清屏
        mov ax , cs
        mov ds , ax
        mov si , offset s        ; si == 存储标号s:表示的数据段
        mov di , offset row        ; di == 存储标号row:表示的数据段
        mov cx , 4

num1:        push cx                ; 待会子程序要显示字符还要用到,先压栈保存
        mov bh , 0        ; 显示在0页
        mov dh , [di]        ; 显示在第ds:[di]行
        mov dl , 0        ; 0 列
        mov ah , 2        ; 设置光标位置
        int 10h

        push si                ; si相当于一个指针;本来si是指向标号s的,里面存的是4个字符串的偏移量;
        ;但是后面子程序要用10h号中断挨个输出字符串中的字符,如果[si+1]得到的只是s:中s2的偏移量,一个常数
        ;所以只能让这个指针si指向第一个s1:处的字符串,要设置si的值为s1:的偏移量
        mov ax , [si]
        mov si , ax


num3:        mov ah , 9        ; 调用10h中断的9号功能显示字符
        mov al , [si]
        mov bh , 0
        mov bl , 01001010b
        mov cx , 1
        int 10h

        mov ah , 2        ; 调用10h中断的2号功能设置光标,10号中断显示字符只会在光标位置显示
        add dl , 1
        int 10h

        cmp byte ptr [si] , 0        ; 如果读到0表示一行已经显示完成,跳转准备开始读取下一行
        jz ok
        inc si                ; 一行没有读完就si偏移一个位置读取下一个字符
        jmp num3        ; 跳转从新设置光标和显示对应字符

ok:        pop si        ; 恢复主程序si和cx
        pop cx
        add si , 2        ; si偏移2读取下一个常数(s2:的偏移量)
        inc di                ; di偏移1读取下一个字符串要显示的行
        loop num1

        mov ax , 4c00h
        int 21h
code ends
end start



posted on 2017-12-11 15:27  正在加载……  阅读(250)  评论(0编辑  收藏  举报