11章节 标志寄存器
flag的1,3,5,12,13,14,15位在8086CPU中没有使用,不具有任何含义。而
0,2,4,6,7,8,9,10,11
一,ZF
flag的第6位是ZF,零标志位。它记录相关指令执行后,其结果是否为0。
如果结果为0,如么zF=1;如果结果不为0,如么ZF=0
影响FLAG标志寄存器的指令有: ADD,SUB,MUL,DIV INC,OR,AND等(运算指令逻辑或算术指令)
二,PF
flag的第2位是PF,奇偶标志位。它记录相关指令执行后,其结果的所有bit位中1的个数是否为偶数,如果1的个数
为偶数PF=1,如果为奇数,哪么PF=0
三,SF标志
flag的第7位是SF,符号标志位。它记录相关指令执行后,其结果是否为负。如果结果为负,
SF=1;如果非负,SF=0
检测点11.1
写出下面每条指令执行后,ZF,PF,SF等标志位的值。
sub al,al zf= 1 pf=1 sf=0
mov al,1 zf= 0 pf=0 sf=0
push ax zf= 0 pf=0 sf=0
pop bx zf= 0 pf=0 sf=0
add al,bl zf= 0 pf=0 sf=0
add al,10 zf= 0 pf=1 sf=0
mul al zf= 0 pf=1 sf=1
11.4 CF标志
flag的第0位是CF,进位标志位。一般情况下,在进行无符号数运算的时候,它记录了运算
结果的最高有效们向更高位的进位值,或是从更高位的借位值。
11.5 OF标志
flag的第11位是OF,溢出标志位。一般情况下,OF记录了有符号数运算的结果是否发生了
溢出。如果发生溢出,OF=1;如果没有,OF=0。
CF和OF的区别:CF是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位。
检测点 11.2
写出下面每条指令执行后,ZF PF SF CF OF 等标志位的值
CF OF SF ZF PF
sub al,al 0 0 0 1 1
mov al,10H 0 0 0 0 0
add al,90H 0 0 1 0 1
mov al,80H 0 0 0 0 0
add al,80H 1 1 1 0 0
mov al,0FCH 0 0 1 0 1
add al,05H 1 1 1 0 1
mov al,7DH 0 0 0 0 1
add al,0Bh 0 0 1 0 1
11.6 ADC指令
adc是带进位加法指令,它利用了CF位上记录的进位值。
11.9检测比结果的条件转移指令
jmp 强跳
jcxz 关系到CX的值为0就跳否则什么都不做
je zf=1
jne zf=0
jb cf=1
jnb cf=0
ja cf=0且zf=0
jna cf=1或zf=1
检测点11.3
1,补全下面的程序,统计F000:0处32个字节中,大小在[32,128]的数据的个数
mov ax,0f000h
mov ds,ax
mov bx,0
mov dx,0
mov cx,32
s: mov al,[bx]
cmp al,32
jb so
cmp al,128
ja so
inc dx
so: inc bx
loop s
2,补全下面的程序,统计F000:0处32个字节中,大小在(32,128)的数据的个数
mov ax,0f000h
mov ds,ax
mov bx,0
mov dx,0
mov cx,32
s: mov al,[bx]
cmp al,32
jna so
cmp al,128
jnb so
inc dx
so: inc bx
loop s
检测点11.4
下面的程序执行后:(ax)=?
mov ax,0
push ax
popf
mov ax,0fff0h
add ax,0010h
pushf
pop ax
and al,11000101b
and ah,00001000b
AX=45H
实验11 编写子程序
完整程序如下:
编写一个子程序,将包含任意字符,以0结尾的字符串中的小写字母转变成大写字母。
assume cs:codesg
datasg segment
db "Beginner's All-purpose Symbolic Instruction Code.",0
datasg ends
codesg segment
start:
mov ax,datasg
mov ds,ax
mov si,0
call letterc
mov ax,4c00h
int 21h
letterc:
push si
s: mov al,[si]
cmp al,0
je exitsub
cmp al,61h ;61h为'a'的ASCII码
jb next
cmp al,7ah ;7ah为'z'的ASCII码
ja next
and al,11011111B ;或使用sub al,20h
mov [si],al
next: inc si
jmp short s
exitsub:
pop si
ret ;子程序部分[结束]
codesg ends
end start
-d 0B9B:0
0B9B:0000 42 65 67 69 6E 6E 65 72-27 73 20 41 6C 6C 2D 70 Beginner's All-p
0B9B:0010 75 72 70 6F 73 65 20 53-79 6D 62 6F 6C 69 63 20 urpose Symbolic
0B9B:0020 49 6E 73 74 72 75 63 74-69 6F 6E 20 43 6F 64 65 Instruction Code
0B9B:0030 2E 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0B9B:0040 B8 9B 0B 8E D8 BE 00 00-E8 05 00 B8 00 4C CD 21 .............L.!
0B9B:0050 56 8A 04 3C 00 74 0F 3C-61 72 08 3C 7A 77 04 24 V..<.t.<ar.<zw.$
0B9B:0060 DF 88 04 46 EB EB 5E C3-E8 09 5F 83 C4 04 FF 76 ...F..^..._....v
0B9B:0070 04 FF 36 24 21 E8 BC 44-83 C4 04 80 3E 60 08 00 ..6$!..D....>`..
-g
Program terminated normally
-d 0b9b:0
0B9B:0000 42 45 47 49 4E 4E 45 52-27 53 20 41 4C 4C 2D 50 BEGINNER'S ALL-P
0B9B:0010 55 52 50 4F 53 45 20 53-59 4D 42 4F 4C 49 43 20 URPOSE SYMBOLIC
0B9B:0020 49 4E 53 54 52 55 43 54-49 4F 4E 20 43 4F 44 45 INSTRUCTION CODE
0B9B:0030 2E 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0B9B:0040 B8 9B 0B 8E D8 BE 00 00-E8 05 00 B8 00 4C CD 21 .............L.!
0B9B:0050 56 8A 04 3C 00 74 0F 3C-61 72 08 3C 7A 77 04 24 V..<.t.<ar.<zw.$
0B9B:0060 DF 88 04 46 EB EB 5E C3-E8 09 5F 83 C4 04 FF 76 ...F..^..._....v
0B9B:0070 04 FF 36 24 21 E8 BC 44-83 C4 04 80 3E 60 08 00 ..6$!..D....>`..
第12章节 内中断
1,用debug查看内存,情况如下:
0000:0000 68 10 A7 00 8B 01 70 00-16 00 9D 03 8B 01 70 00
则3号中断源对应的中断处理程序的入口地址为:0070:018B
2,存储N号中断源对应的中断处理程序入口的偏移地址的内存单元的地址为:0000:[n*4]
存储N号中断源对应的中断处理程序入口的段地址的内存单元的地址为:0000:[n*4+2]字单元
实验12 编写0号中断的处理程序
编写0号中断的处理程序,使得在除法溢出发生时,在屏幕中间显示字符串"divide
error!",然后返回到DOS。
要求:仔细跟踪调试,在理解整个过程之前,不要进行后面课程的学习。
;此题参照网上代码学习
ASSUME CS:CODESG
CODESG SEGMENT
START:
;这时设置ds:[si]指向需要复制的代码处
MOV AX,CS
MOV DS,AX
MOV SI,OFFSET DO0;offset DO0是把程序开始到do0的偏移地址给si
MOV AX,0000
MOV ES,AX
MOV DI,0200H;设置es:[di]指向要复制程序的目标处
MOV CX,OFFSET DO0END - OFFSET DO0;设置复制的循环次数,这里的循环次数就是要复制程序的开始地址到程
序的结束地址
CLD;设置si、di按1增长
REP MOVSB;进行复制的循环过程
;设置中断向量表,由于是N号中断,其段地址放在0000:[N*4]字单元中,其偏移地址放在0000:[N*4+2]字单
元中。所以0号中断的
;中断程序的段地址放在0000:[N*4]字单元,其偏移地址放在0000:[N*4+2]字单元中。
MOV WORD PTR ES:[0*4],200H
MOV WORD PTR ES:[0*4+2],0000
;这里是写的测试程序,当然也可以在debug时在写入执行
;MOV AX,1000H
;MOV BH,1
;DIV BH
MOV AX,4C00H
INT 21H
;此处是中断处理程序
DO0:
;开始时是是定义要输出的字符串,其不能执行,所以跳转到DO0START处开始执行
JMP SHORT DO0START
DB 'DIVIDE ERROR!'
DO0START:
MOV AX,CS
MOV DS,AX
MOV SI,0202H;设置ds:[si]指向所定义的字符串'DIVIDE ERROR!'
MOV AX,0B800H
MOV ES,AX
MOV DI,12*160+36*2;设置es:[di]指向屏幕的中央处
MOV CX,13;这里是设置显示字符串的循环次数
S:
MOV AL,DS:[SI]
MOV AH,02H;设置显示的字体颜色
MOV ES:[DI],AX
ADD DI,2
INC SI
LOOP S
MOV AX,4C00H
INT 21H
DO0END:
NOP
CODESG ENDS
END START
-g
Program terminated normally
-d 0000:0200
0000:0200 EB 0D 44 49 56 49 44 45-20 45 52 52 4F 52 21 8C ..DIVIDE ERROR!.
0000:0210 C8 8E D8 BE 02 02 B8 00-B8 8E C0 BF C8 07 B9 0D ................
0000:0220 00 8A 04 B4 02 26 89 05-83 C7 02 46 E2 F3 B8 00 .....&.....F....
0000:0230 4C CD 21 00 00 00 00 00-00 00 00 00 00 00 00 00 L.!.............
0000:0240 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0250 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0260 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0270 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
第13章节 int 指令
1,在上面的内容中,我们用7CH中断例程实现LOOP的功能,则上面的7ch中断例
程所能进行的最大转移位移是多少?
分析:参考了abcrazy的说法:虽然说这里它实现了loop的功能,通过修改ip的值使得程序在跳转到循环开始处,
它把位移交给了bx来传递,因为bx所能存储的最大数是ffffh。虽然不能从某个段的偏移位置0转移到该段的偏移位
置ffffh但可以从ffffh转到0处执行。因为掉用7ch中断还要设置cx,bx要用掉至少6个字节,但从某段的ffff跳转到
0,实际跳转位移确实也是ffffh,此时bx设置为1,int 7ch这条语句在本段的fffeh位置,那么在执行该语句时,
(ip)=ffffh了,加1值溢出为0,就转到了本段开头执行。得最大转移位移FFFFH。
2,用7CH中断例程完成JMP NEAR PTR S指令的功能,用BX向中断例程传送转移位移。
应用举例:在屏幕的第12行,显示DATA段中以0结尾的字符串。
assume cs:code
data segment
db 'conversation',0
data ends
code segment
start: mov ax,data
mov ds,ax
mov si,0
mov ax,0b800h
mov es,ax
mov di,12*160
s: cmp byte ptr [si],0
je ok
mov al,[si]
mov es:[di],al
inc si
add di,2
mov bx,offset s-offset ok
int 7ch
ok: mov ax,4c00h
int 21h
code ends
end start
//参考njutyangxiao
assume cs:codesg
datasg segment
db 'conversation',0
datasg ends
codesg segment
start:
mov ax,cs
mov ds,ax
mov si,offset lp_s
mov ax,0
mov es,ax
mov di,0200h
mov cx,offset lp_e - offset lp_s
cld
rep movsb
mov word ptr es:[7ch*4],0200h
mov word ptr es:[7ch*4+2],0000h
;;;;;;;把中断例程的对应得代码拷贝到0000:0200
;处并设置中断向量表项;;;;;;;;;;;;;;;;;;;;
mov ax,datasg
mov ds,ax
mov si,0
mov ax,0b800h
mov es,ax
mov di,12*160
show_s:
mov al,ds:[si]
cmp al,0
je show_ok;判断是否达到了字符串的末尾
mov byte ptr es:[di],al
mov byte ptr es:[di+1],0a0h
add di,2
inc si
mov bx,offset show_s - show_ok;设置转移位移
int 7ch
show_ok:
mov ax,4c00h
int 21h
lp_s:push bp
mov bp,sp
dec cx
jcxz lp_ret
add [bp+2],bx ;change the ip's value
lp_ret:
pop bp
iret
lp_e:nop
codesg ends
13.2
判断下面说法的正误:
(1)我们可以编程改变FFFF:0处的指令,使得CPU不去执行BIOS中的硬件系统检测和初始化程序。
解答:因为FFFF:0处为只读的ROM内存空间,无法编程改变。
(2)int 19h中断例程,可以由DOS提供。
解答:因为BIOS调用int 19h进行操作系统的引导,该中断例程运行在DOS之前,所以不可以由DOS提供。
实验13 编写、应用中断例程
1,编写并安装int 7ch中断例程,功能为显示一个用0结束的字符串,中断例程安装在0:200处
参数:(dh)=行号,(dl)=列号,(cl)=颜色,ds:si指向字符串首地址。
代码如下:
assume cs:code
data segment
db "welcome to masm!",0
data ends
code segment
start:
;安装程序
mov ax, cs
mov ds, ax
mov si, offset ShowStr
mov ax, 0
mov es, ax
mov di, 200h
mov cx, offset EndShowStr - offset ShowStr
CLD
rep movsb
;设置中断向量
n EQU 7ch
mov bx, 4 * n
CLI ; 确保随后二条MOV指令被连续执行而不被打断
mov word ptr es:[bx], 200h
mov word ptr es:[bx+2], 0
STI ;开中断指令,它允许CPU响应其后的中断请求
;测试int 7ch中断例程
mov dh, 10
mov dl, 10
mov cl, 00001010b
mov ax, data
mov ds, ax
mov si, 0
int 7ch
mov ax, 4c00h
int 21h
ShowStr: ;定义中断例程[开始]
push ax ;子程序用到的寄存器入栈
push dx
push si
push di
mov ax, 0b800h
mov es, ax
mov ax, 160
mul dh ;确定行
xor dh, dh
shl dl, 1 ;确定列
add ax, dx
mov di, ax ;设置输出位置
mov ah, cl ;确定颜色
Show:
cmp byte ptr [si], 0
je EndShow
mov al, [si]
mov es:[di], ax
inc si
add di, 2
jmp Short Show
EndShow:
pop di ;子程序用到的寄存器出栈
pop si
pop dx
pop ax
iret
EndShowStr: ;定义中断例程[结束]
nop
code ends
end start
D:/masm/src>debug test13.exe
-r
AX=0000 BX=0000 CX=0088 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B8B ES=0B8B SS=0B9B CS=0B9D IP=0000 NV UP EI PL NZ NA PO NC
0B9D:0000 8CC8 MOV AX,CS
-t
AX=0B9D BX=0000 CX=0088 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B8B ES=0B8B SS=0B9B CS=0B9D IP=0002 NV UP EI PL NZ NA PO NC
0B9D:0002 8ED8 MOV DS,AX
-t
AX=0B9D BX=0000 CX=0088 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B9D ES=0B8B SS=0B9B CS=0B9D IP=0004 NV UP EI PL NZ NA PO NC
0B9D:0004 BE3A00 MOV SI,003A
-t
AX=0B9D BX=0000 CX=0088 DX=0000 SP=0000 BP=0000 SI=003A DI=0000
DS=0B9D ES=0B8B SS=0B9B CS=0B9D IP=0007 NV UP EI PL NZ NA PO NC
0B9D:0007 B80000 MOV AX,0000
-g
Program terminated normally
-d 0000:0200
0000:0200 50 52 56 57 B8 00 B8 8E-C0 B8 A0 00 F6 E6 32 F6 PRVW..........2.
0000:0210 D0 E2 03 C2 8B F8 8A E1-80 3C 00 74 0B 8A 04 26 .........<.t...&
0000:0220 89 05 46 83 C7 02 EB F0-5F 5E 5A 58 CF 00 00 00 ..F....._^ZX....
0000:0230 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0240 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0250 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0260 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0270 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
2,编写并安装int 7ch中断例程,功能完成loop指令的功能。
参数:(cx)=循环次数,(bx)=位移。
以上中断例程安装成功后,对下面的程序进行单步跟踪,尤其注意观察int
iret 指令执行前后CS、IP 和栈中的状态
在屏幕中间显示80个'!'
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
s: mov byte prt es:[di],'!'
add di,2
int 7ch
se: nop
mov ax,4c00h
int 21h
code ends
end start
//参照网上作业的中断安装代码
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],0h
mov ax,4c00h
int 21h
lp: ;安装部分
push bp
mov bp,sp
dec cx
jcxz lpset
add [bp+2],bx
lpset:
pop bp
iret
lpend: ;安装结束
nop
code ends
end start
3,下面的程序,分别在屏幕的第2、4、6、8行显示4句英文诗,补全程序。
assume cs:code
code segment
s1: db 'Good,better,best,','$'
s2: db 'Never let is 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,cs
mov ds,ax
mov bx,offset s
mov si,offset row
mov cx,4
ok: mov bh,0
mov dh,[si]
mov dl,0
mov ah,2
int 10h
mov dx,[bx]
mov ah,9
int 21h
inc si
add bx,2
loop ok
mov ax,4c00h
int 21h
code ends
end start
第14章节 端口
(1)编程:读取CMOS RAM的2号单元的内容。
assume cs:code
code segment
start: mov al,2
out 70h,al
in al,71h ;7:03时测试显示al=03
mov ax,4c00h
int 21h
code ends
end start
(2)编程:向CMOS RAM的2号单元写入0
assume cs:code
code segment
start: mov al,2
out 70h,al
mov al,0
out 71h,al
in al,71h ;7:05时测试显示al=0,证明写入正确
mov ax,4c00h
int 21h
code ends
end start
检测点14.2
编程,用加法和移位指令计算(ax)=(ax)*10。
assume cs:code
code segment
start: mov ax,idata ;此处idata为可以存储在ax中的数值。
mov bx,ax
shl ax,1 ;(ax)=(ax)*2
mov cl,3
shl bx,cl ;(bx)=(ax)*8
add ax,bx ;(ax)=(ax)*10
mov ax,4c00h
int 21h
code ends
end start
实验14 访问CMOS RAM
编程:以“年/月/日 时:分:秒”的格式,显示当前的日期、时间。
注意:CMOS RAM中存储着系统的配置信息,除了保存时间信息的单元外,不要向其他的单元中写入内存,否则将引
起一些系统错误。
assume cs:code
code segment
s: db "yy/mm/dd hh:mm:ss",'$'
s1: db 9,8,7,4,2,0
start:
mov ax,cs
mov ds,ax
mov bx,offset s
mov si,offset s1
mov cx,6
ok:
mov al,[si]
out 70h,al
in al,71h ;读取数据至al
mov ah,al
push cx
mov cl,4
shr al,cl ;十位放在al中
and ah,00001111b ;个位放在ah中
add ah,30h
add al,30h
mov [bx],ax ;写入指定字符串
pop cx
add bx,3
inc si
loop ok
;利用int 20h的中断例程的子程序显示字符串
mov ah,2 ;置光标
mov bh,0 ;第0页
mov dh,5 ;行号
mov dl,12 ;列号
int 10h
mov dx,0 ;ds:dx指向字符串
mov ah,9
int 21h
mov ax,4c00h
int 21h
code ends
end start
第15章 外中断
(1),仔细分析一下上面的int9中断例程,看看是否可以精简一下?
其实在我们的int 9中断例程中,模拟int 指令调用原int 9 中断例程的程序段是可以
精简的,因为在进入中断例程后,IF和TF都已经置0,没有必要再进行设置了。对于程序
段:
pushf
pushf
pop ax
and ah,11111100b
push ax
popf
call dword ptr ds:[0]
可以精简为:
pushf
call dword ptr ds:[0]
两条指令。
(2)仔细分析上面的程序中的主程序,看看有什么潜在的问题?
在主程序中,如果在执行设置int9中断例程的段地址和偏移地址的指令之间发生了键盘中断,则CPU将转去
一个错误的地址执行,将发生错误.
找出这样的程序段,改写它们,排除潜在的问题.
mov word ptr es:[9*4],offset int9
mov es:[9*4+2],cs
应改为:
cli
mov word ptr es:[9*4],offset int9
mov es:[9*4+2],cs
sti
实验15 安装新的int 9 中断例程
assume cs:code
data segment
db 16 dup (0)
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
mov al,9
mov dh,'/'
mov cx,2
s: call change
mov al,8
add bx,3
loop s
mov al,7
mov dh,' '
call change
add bx,3
mov al,4
mov dh,':'
mov cx,2
s1: call change
mov al,2
add bx,3
loop s1
mov al,0
mov dh,'$'
call change
mov ah,2
mov bh,0
mov dh,12
mov dl,0
int 10h ;//调用int10h2号中断例程置光标.
mov dx,0
mov ah,9
int 21h ;//调用int21h9号中断例程显示数据.
mov ax,4c00h
int 21h
change: push ax ;//此子程序读取cmos ram中的数据并转化趁ascii码放入data段
push cx ;//参数al(读取cmos ram中几号单元)
push dx ;//dh(数据后缀).
out 70h,al
in al,71h
mov ah,al
mov cl,4
shr ah,cl
and al,00001111b
add ah,30h
add al,30h
mov [bx],ah
mov [bx+1],al
mov [bx+2],dh
pop dx
pop cx
pop ax
ret
code ends
end start
第十六章节
16.1
1,下面的程序将CODE段中a处的8个数据累加,结果存储到B处的dword中,补全程序。
assume cs:code
code segment
a dw 1,2,3,4,5,6,7,8
b dd 0
start: mov si,0
mov cx,8
s: mov ax,_____ a[si]
add _____,ax cs:[16]
adc _____,0 cs:[18]
add si,_____ 2
loop s
mov ax,4c00h
int 21h
code ends
end start
16.2
1,下面的程序将data段中a处的8个数据累加,结果存储到b处的字中。补全程序。
assume cs:code,es:data
data segment
a db 1,2,3,4,5,6,7,8
b dw 0
data ends
code segment
start: __________ mov ax,data
__________ mov ds,ax
mov si,0
mov cx,8
s: mov al,a[si]
mov ah,0
add b,ax
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start
实验十六
编写包含多个功能子程序的中断例程
assume cs:code
code segment
int7ch: jmp short main
table: dw cls,forecolor,backcolor,roll
main: push bx
cmp ah,3
ja return
mov bl,ah
mov bh,0
add bx,bx
call word ptr table[bx]
return: pop bx
iret
cls: push ax ;//清空
push bx
push cx
push ds
mov ax,0b800h
mov ds,ax
mov bx,0
mov cx,2000
empty: mov byte ptr [bx],' '
add bx,2
loop empty
pop ds
pop cx
pop bx
pop ax
ret
forecolor: push ax ;//换前景
push bx
push cx
push ds
mov bx,0b800h
mov ds,bx
mov bx,1
mov cx,2000
color: and byte ptr [bx],11111000b
or [bx],al
add bx,2
loop color
pop ds
pop cx
pop bx
pop ax
ret
backcolor: push ax ;//换背景
push bx
push cx
push ds
mov bx,0b800h
mov ds,bx
mov bx,1
mov cx,2000
icolor: push cx
and byte ptr [bx],10001111b
mov cl,4
shl al,cl
or [bx],al
shr al,cl
add bx,2
pop cx
loop icolor
pop ds
pop cx
pop bx
pop ax
ret
roll: push ax ;//滚动。
push cx
push ds
push di
push si
push es
mov ax,0b800h
mov ds,ax
mov es,ax
mov di,0
mov si,160
mov cx,160*24
cld
rep movsb
mov cx,80
inc si
clear: mov byte ptr es:[si],' '
add si,2
loop clear
pop es
pop si
pop di
pop ds
pop cx
pop ax
ret
int7chend: nop
start: mov ax,0
mov es,ax
mov di,200h ;es:di目的地址
mov ax,cs
mov ds,ax
mov si,offset int7ch ;ds:si源地址
mov cx,offset int7chend-offset int7ch ;长度
cld ;方向为正
rep movsb
mov word ptr es:[4*7ch],0
mov word ptr es:[4*7ch+2],20h ;//设置中断向量
mov ax,4c00h
int 21h
code ends
end start
第十七章节
"在int16h中断例程中,一定有设置IF=1的指令。"这种说法对吗?
我觉得对的,当键盘缓冲区为空时,int16h会将IF设为1等待用户输入.
实验十七
assume cs:code
code segment
start: mov ax,0
mov es,ax
mov ax,cs
mov ds,ax
mov di,200h
mov si,offset int7ch
mov cx,offset int7chend-offset int7ch
cld
rep movsb ;//把中断例程写入内存
cli
mov word ptr es:[7ch*4],200h
mov word ptr es:[7ch*4+2],0
sti ;//设置向量表
mov ax,4c00h
int 21h
int7ch: push cx
push dx
cmp bx,2879
ja return ;//判断逻辑扇区是否大于2879
cmp ah,1 ;//判断功能号是否大于1
ja return
je first
call diskM_1
mov ah,2
int 13h
return: pop dx
pop cx
iret
first: call diskM_1
mov ah,3
int 13h
jmp short return
diskM_1: push bx ;//此程序通过传逻辑扇区号求得磁道号、磁面号、扇区号并指定驱动器号.
push ax
mov ax,bx
mov cl,18
div cl
mov dh,al ;//计算逻辑扇区除以18,商为偶数磁面为0,奇数则为1
and dh,1 ;//二进制最后位即可判断奇偶。
mov cl,ah
inc cl ;//余数自加1为扇区号
mov ax,bx
mov bl,36
div bl
mov ch,al ;//逻辑扇区除以36的商即为磁道号.
mov dl,0 ;//设驱动器号为0.
pop ax
pop bx
ret
int7chend: nop
code ends
end start