1615 字
8 分钟
王爽「汇编语言」学习笔记(七)
內中断
中断类型码为 1 byte 的数据,可以表示 256 种中断信息的来源,但是实际上装载好的远少于 256 种。
在 8086CPU 中,中断向量表存放在 0000:0000~0000:03E8 单元中,一个表项占 2 word ,偏移地址 word 存在低地址,段地址 word 存在高地址中。
中断过程如下:
- 取得中断类型码 N
pushfTF = 0, IF = 0push CSpush IPIP = (N * 4), CS = (N * 4 + 2)
在编写中断处理程序时,需在结尾使用 iret 指令返回,作用与 ret 相似。
CPU 在执行完一条指令之后,如果检测到 TF = 1 ,就会产生类型码为 1 的单步中断,转去执行 1 号中断处理程序,从而为单步跟踪程序的执行提供了可能。
但是为了避免出现 1 号中断程序的套娃现象,需要在每次进入中断程序之前需要将 TF 置为 0 。
特殊情况:在执行完 ss 寄存器传送数据的指令后,即便发生中断,CPU 也不会响应。 -> 我们应该将设置 ss 和 sp 的指令连续存放。
Lab 12
编写 0 号中断的处理程序
assume cs:code
code segmentstart: mov ax, cs mov ds, ax mov si, offset do0 mov ax, 0 mov es, ax mov di, 200h mov cx, offset do0end - offset do0 cld rep movsb
mov ax, 0 mov es, ax mov word ptr es:[0], 200h mov word ptr es:[2], 0
mov ax, 4200h int 21h
do0: jmp short do0start db "divide error!"
do0start: mov ax, cs mov ds, ax mov si, 202h
mov ax, 0b800h mov es, ax mov di, 12*160+36*2
mov cx, 13s: mov al, [si] mov es:[di], al inc si add di, 2 loop s
mov ax, 4200h int 21hdo0end: nopcode endsend startLab 13
显示用 0 结束的字符串
assume cs:code
data segment db "welcome to masm!", 0data ends
stack segment dw 8 dup (0)stack ends
code segmentstart: mov ax, stack mov ss, ax mov sp, 16
mov ax, cs mov ds, ax mov si, offset showstr mov ax, 0 mov es, ax mov di, 200h mov cx, offset showstrend - offset showstr 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 dh, 10 mov dl, 10 mov cl, 2 mov ax, data mov ds, ax mov si, 0 int 7ch
mov ax, 4c00h int 21h
showstr: push ax push bx push cx push ds push es push di push si
mov ax, 0b800h mov es, ax mov ah, 0 mov al, 160 mul dh mov dh, 0 add ax, dx mov di, ax
mov al, cl mov cx, 0
s: mov cl, ds:[si] jcxz se mov es:[di], cl mov es:[di+1], al inc si add di, 2 loop s
se: pop si pop di pop es pop ds pop cx pop bx pop ax iret
showstrend: nopcode endsend start完成 loop 指令的功能
assume cs:code
stack segment dw 8 dup (0)stack ends
code segmentstart: mov ax, stack mov ss, ax mov sp, 16
call load call setIVT
mov ax, 0b800h mov es, ax mov di, 160*12 mov bx, offset s - offset se mov cx, 80
s: mov byte ptr es:[di], '!' add di, 2 int 7ch
se: nop mov ax, 4c00h int 21h
setIVT: push ax push es
mov ax, 0 mov es, ax mov word ptr es:[7ch*4], 200h mov word ptr es:[7ch*4+2], 0
pop es pop ax ret
load: push ax push cx push ds push es push di push si
mov ax, 0 mov es, ax mov di, 200h mov ax, cs mov ds, ax mov si, offset myloop mov cx, offset myloopend - offset myloop cld rep movsb
pop si pop di pop es pop ds pop cx pop ax ret
myloop: push bp mov bp, sp dec cx jcxz myloopret add [bp+2], bx
myloopret: pop bp iret
myloopend: nopcode endsend start显示四句英文诗
assume cs:code
code segments1: 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 s4row:db 2, 4, 6, 8
start: mov ax, cs mov ds, ax mov bx, offset s mov si, offset row mov cx, 4
ok: mov bh, 0 mov dh, ds:[si] mov dl, 0 mov ah, 2 int 10h
mov dx, ds:[bx] mov ah, 9 int 21h inc si add bx, 2 loop ok
mov ax, 4200h int 21hcode endsend start端口
CPU 通过主线相连的芯片除了各种存储器之外,还有以下 3 种芯片:
- 各种接口卡的芯片
- 主板上的接口芯片,用来访问外设
- 其他芯片,存储系统相关信息或进行相关输入输出
in 和 out 指令
CPU 使用地址线和控制线向端口发送指令,从而与芯片进行交互,间接访问芯片的存储单元。
在 in 和 out 指令中,只能使用 ax 或 al 来存放端口读/写的数据,其中访问 8 位端口时用 al ,访问 16 位端口时用 ax 。
shl 和 shr 指令
它们都是逻辑位移指令,都会将最后移出的一位写入 CF 中,如果移动位数大于 1 ,则需要将移动位数放在 cl 中。
Lab 14
访问 CMOS RAM
assume cs:code
stack segment db 128 dup (0)stack ends
code segmentstart: mov ax, stack mov ss, ax mov sp, 128
mov bx, 0b800h mov es, bx mov bx, 160*12+28*2
call show_ymd mov ah, ' ' call print_char call show_hms
mov ax, 4c00h int 21h
show_ymd: push ax push cx
mov al, 9 call show_single
mov ah, '/' call print_char
mov al, 8 call show_single
mov ah, '/' call print_char
mov al, 7 call show_single
pop cx pop ax ret
show_hms: push ax push cx
mov al, 4 call show_single
mov ah, ':' call print_char
mov al, 2 call show_single
mov ah, ':' call print_char
mov al, 0 call show_single
pop cx pop ax ret
; al 存端口号show_single: call get_char call print_char mov ah, al call print_char
ret
; ah 存要打印的字符; es:[bx] 要打印的屏幕位置print_char: mov byte ptr es:[bx], ah add bx, 2
ret
; al 存放单元; ah 存十位数 ASCII 码; al 存个位数 ASCII 码get_char: push cx
out 70h, al in al, 71h mov ah, al mov cl, 4 shr ah, cl and al, 00001111b
add ah, 30h add al, 30h
pop cx retcode endsend start外中断
外中断信息来自 CPU 外部,外中断源一共有两种:
- 可屏蔽中断
- 如果
IF = 0,则会禁止进入可屏蔽中断。 - 进入内中断时会将 IF 置为 0 。
- 如果在內中断过程中需要处理可屏蔽中断,则需要用指令将 IF 置为 1 。
sti: IF = 1cli: IF = 0
- 如果
- 不可屏蔽中断
- 中断类型码固定为 2
- 中断过程与內中断一致,除了最后是
(IP) = (8), (CS) = (0AH)
Lab 15
安装新的 int9 中断例程
assume cs:code
stack segment db 128 dup (0)stack ends
code segmentstart: mov ax, stack mov ss, ax mov sp, 128
push cs pop ds mov si, offset int9
mov ax, 0 mov es, ax mov di, 204h
mov cx, offset int9end - offset int9 cld rep movsb
push es:[9*4] pop es:[200h] push es:[9*4+2] pop es:[202h]
cli mov word ptr es:[9*4], 204h mov word ptr es:[9*4+2], 0 sti
mov ax, 4c00h int 21h
int9: push ax push bx push cx push es
in al, 60h pushf call dword ptr cs:[200h] cmp al, 1eh jne int9ret pushf
in al, 60h pushf call dword ptr cs:[200h] cmp al, 1eh+80h jne int9ret
mov ax, 0b800h mov es, ax mov bx, 0 mov cx, 2000s: mov byte ptr es:[bx], 'A' add bx, 2 loop s
int9ret: pop es pop cx pop bx pop ax iret
int9end: nopcode endsend start