问题是:因为按照课程设计,按2进入dos界面后,会把之前选择时的按键如3、2、F1等在c:\后显示出来,为了进入dos后不显示这些按键,计划在按2进入dos之前把这些按键对应的键盘缓冲都清掉。
我不明白的是下面注释分别为红色字体和绿色字体的两种做法,都可以达到去除缓冲区的目的。但是如果按照蓝色的做法,没有红色的部分,按3进入时钟显示界面后,时间会自己一直跳动;如下
而如果把蓝色的部分注释掉,使用红色的部分(即进入自定义的中断例程后一开始就删除键盘的缓冲),那么进入时钟界面后,时钟界面只显示一次当前的时间,时间不会跳动。想请教一下,不知道这个删除键盘缓冲区的位置怎么会对时钟显示有的影响?
assume cs:codesg,ds:datasg,ss:stacksg
datasg segment
db 4 dup (0)
datasg ends
stacksg segment
dw 32 dup (0)
stacksg ends
codesg segment
start:;write to the floppy
mov ax,cs
mov es,ax
mov bx,offset floppy
mov dl,0
mov dh,0
mov cl,1
mov ch,0
mov al,2
mov ah,3
int 13h
mov ax,4c00h
int 21h
org 7c00h
floppy:jmp short beg
origin_int9 dw 0,0
dis_choice db 0
is_clock db 0
format2 db 'YE/MO/DA hh:mm:ss',0
;mov ax,stacksg
;mov ss,ax
;mov sp,32*2
;mov ax,datasg
beg:;将第二个扇区读入内存
mov ax,0
mov es,ax
mov bx,7c00h+200h
mov dx,0
mov cx,2
mov ax,0201h
int 13h
mov dis_choice,1
call display
;替换9号中断
mov ax,0
mov es,ax
mov ax,es:[9*4]
mov origin_int9,ax
mov ax,es:[9*4+2]
mov origin_int9[2],ax
cli
mov word ptr es:[9*4],offset s9_beg
mov word ptr es:[9*4+2],cs
sti
s3:nop
jmp short s3
s9_beg:push bp
mov bp,sp
add bp,2
push ax
push ds
push bx
push si
push cx
push es
push di
in al,60h
mov bl,al
pushf
;mov si,offset origin_int9
call dword ptr origin_int9;here the book use 'cs' register
;mov ah,0;红色语句
;int 16h;红色语句
cmp bl,2h
je reset
cmp bl,3h
je sys
cmp bl,4
je clock
cmp is_clock,1
jne s10
cmp bl,3Bh
je c_f1
cmp bl,1h
jne s10
jmp near ptr c_esc
s10:jmp near ptr s4
reset:mov ax,ss
mov ds,ax
mov word ptr ds:[bp],0
mov word ptr ds:[bp+2],0ffffh
jmp near ptr s4
sys:;
;恢复int 9
mov ax,0
mov es,ax
mov ax,origin_int9
mov es:[9*4],ax
mov ax,origin_int9[2]
mov es:[9*4+2],ax
;删除键盘缓冲区;蓝色语句
mov ah,0;蓝色语句
int 16h;蓝色语句
;int 13h 读硬盘
mov dx,0080h
mov cx,0001h
mov bx,7c00h
;es的值已设置过
mov ax,0201h
;模拟int 13h指令
pushf
;pushf
;pop ax
;and ah,11111100b
;push ax
;popf
push es
push bx
mov dis_choice,0
call display
jmp dword ptr es:[13h*4]
clock:mov is_clock,1
mov ah,0;蓝色语句
int 16h;蓝色语句
mov ax,ss
mov ds,ax
mov word ptr ds:[bp],offset clock_dis
mov ax,cs
mov word ptr ds:[bp+2],ax
mov dis_choice,0
call display
jmp short s4
c_f1:mov ah,0;蓝色语句
int 16h;蓝色语句
mov ax,0b800h
mov es,ax
mov di,160*12+62+1
mov si,0
cf1_s1:cmp byte ptr format2[si],0
je s4
add byte ptr es:[di],1
inc si
add di,2
jmp short cf1_s1
c_esc:mov ah,0;蓝色语句
int 16h;蓝色语句
mov is_clock,0
;清除屏幕先
mov ax,0b800h
mov es,ax
mov di,160*12+62
mov si,0
cesc_s1:cmp byte ptr format2[si],0
je cesc_s3
mov es:[di],0720h
inc si
add di,2
jmp short cesc_s1
cesc_s3:mov dis_choice,1
call display
mov ax,ss
mov ds,ax
mov word ptr ds:[bp],offset s3
mov ax,cs
mov word ptr ds:[bp+2],ax
jmp short s4
s4:pop di
pop es
pop cx
pop si
pop bx
pop ds
pop ax
pop bp
iret
s9_se:nop
;dis_choice为参数:1为显示,0为清屏
display:jmp short dis_beg
ad dw f1,f2,f3,f4
f1 db '1) reset pc',0
f2 db '2) start system',0
f3 db '3) clock',0
f4 db '4) set clock',0
dis_beg:push ax
push es
push di
push cx
push si
push bx
push dx
mov ax,0b800h
mov es,ax
mov cx,0 ;行数计数器
mov si,0 ;每行地址的指针
next:mov di,10*160+32*2
mov ax,160
mul cx
add di,ax
mov bx,ad[si]
add si,2
s0:mov al,cs:[bx]
cmp al,0 ;一行是否结束
je s1
add bx,1
;display功能选择
cmp dis_choice,1
je s2
mov byte ptr es:[di],' '
jmp short s5
s2:mov es:[di],al
s5:add di,2
jmp short s0
s1:add cx,1
cmp cx,4
je dis_end
jmp short next
dis_end:pop dx
pop bx
pop si
pop cx
pop di
pop es
pop ax
ret
clock_dis:jmp short s7
format db 'YE/MO/DA hh:mm:ss',0
position db 9,8,7,4,2,0
s7:mov bx,0
mov si,0
mov cx,6
s9:mov al,position[bx]
out 70h,al
in al,71h
mov ah,al
push cx
mov cl,4
shr ah,cl
pop cx
and al,00001111b
add ah,30h
add al,30h
mov format[si],ah
mov format[si+1],al
add si,3
inc bx
loop s9
mov ax,0b800h
mov es,ax
mov di,160*12+62
mov si,0
s8:cmp byte ptr format[si],0
je s7
mov al,format[si]
mov es:[di],al
inc si
add di,2
jmp short s8
codesg ends
end start
由于使用代码格式无法再自定义蓝色和红色,所以在下面那个帖子中我会用代码格式把这个再发一遍,方便大家看
另外附上我在标号s7的地方加上下面的代码进行过的一次调试
mov ax,0b800h
mov es,ax
inc byte ptr es:[160*24+158]
观察按3以后s7是不是一直在执行。结果是右下角的符号每次按3会快速变化一下,然后就不变了。比如第一次按3后显示'G',按esc退出第二次按3进去,变成一个乱码,然后再按esc再按3进入,又是变了一下就停了,如图。为啥每次都是只执循环限次数呢?这可能就是带来上面的问题原因
我不明白的是下面注释分别为红色字体和绿色字体的两种做法,都可以达到去除缓冲区的目的。但是如果按照蓝色的做法,没有红色的部分,按3进入时钟显示界面后,时间会自己一直跳动;如下
而如果把蓝色的部分注释掉,使用红色的部分(即进入自定义的中断例程后一开始就删除键盘的缓冲),那么进入时钟界面后,时钟界面只显示一次当前的时间,时间不会跳动。想请教一下,不知道这个删除键盘缓冲区的位置怎么会对时钟显示有的影响?
assume cs:codesg,ds:datasg,ss:stacksg
datasg segment
db 4 dup (0)
datasg ends
stacksg segment
dw 32 dup (0)
stacksg ends
codesg segment
start:;write to the floppy
mov ax,cs
mov es,ax
mov bx,offset floppy
mov dl,0
mov dh,0
mov cl,1
mov ch,0
mov al,2
mov ah,3
int 13h
mov ax,4c00h
int 21h
org 7c00h
floppy:jmp short beg
origin_int9 dw 0,0
dis_choice db 0
is_clock db 0
format2 db 'YE/MO/DA hh:mm:ss',0
;mov ax,stacksg
;mov ss,ax
;mov sp,32*2
;mov ax,datasg
beg:;将第二个扇区读入内存
mov ax,0
mov es,ax
mov bx,7c00h+200h
mov dx,0
mov cx,2
mov ax,0201h
int 13h
mov dis_choice,1
call display
;替换9号中断
mov ax,0
mov es,ax
mov ax,es:[9*4]
mov origin_int9,ax
mov ax,es:[9*4+2]
mov origin_int9[2],ax
cli
mov word ptr es:[9*4],offset s9_beg
mov word ptr es:[9*4+2],cs
sti
s3:nop
jmp short s3
s9_beg:push bp
mov bp,sp
add bp,2
push ax
push ds
push bx
push si
push cx
push es
push di
in al,60h
mov bl,al
pushf
;mov si,offset origin_int9
call dword ptr origin_int9;here the book use 'cs' register
;mov ah,0;红色语句
;int 16h;红色语句
cmp bl,2h
je reset
cmp bl,3h
je sys
cmp bl,4
je clock
cmp is_clock,1
jne s10
cmp bl,3Bh
je c_f1
cmp bl,1h
jne s10
jmp near ptr c_esc
s10:jmp near ptr s4
reset:mov ax,ss
mov ds,ax
mov word ptr ds:[bp],0
mov word ptr ds:[bp+2],0ffffh
jmp near ptr s4
sys:;
;恢复int 9
mov ax,0
mov es,ax
mov ax,origin_int9
mov es:[9*4],ax
mov ax,origin_int9[2]
mov es:[9*4+2],ax
;删除键盘缓冲区;蓝色语句
mov ah,0;蓝色语句
int 16h;蓝色语句
;int 13h 读硬盘
mov dx,0080h
mov cx,0001h
mov bx,7c00h
;es的值已设置过
mov ax,0201h
;模拟int 13h指令
pushf
;pushf
;pop ax
;and ah,11111100b
;push ax
;popf
push es
push bx
mov dis_choice,0
call display
jmp dword ptr es:[13h*4]
clock:mov is_clock,1
mov ah,0;蓝色语句
int 16h;蓝色语句
mov ax,ss
mov ds,ax
mov word ptr ds:[bp],offset clock_dis
mov ax,cs
mov word ptr ds:[bp+2],ax
mov dis_choice,0
call display
jmp short s4
c_f1:mov ah,0;蓝色语句
int 16h;蓝色语句
mov ax,0b800h
mov es,ax
mov di,160*12+62+1
mov si,0
cf1_s1:cmp byte ptr format2[si],0
je s4
add byte ptr es:[di],1
inc si
add di,2
jmp short cf1_s1
c_esc:mov ah,0;蓝色语句
int 16h;蓝色语句
mov is_clock,0
;清除屏幕先
mov ax,0b800h
mov es,ax
mov di,160*12+62
mov si,0
cesc_s1:cmp byte ptr format2[si],0
je cesc_s3
mov es:[di],0720h
inc si
add di,2
jmp short cesc_s1
cesc_s3:mov dis_choice,1
call display
mov ax,ss
mov ds,ax
mov word ptr ds:[bp],offset s3
mov ax,cs
mov word ptr ds:[bp+2],ax
jmp short s4
s4:pop di
pop es
pop cx
pop si
pop bx
pop ds
pop ax
pop bp
iret
s9_se:nop
;dis_choice为参数:1为显示,0为清屏
display:jmp short dis_beg
ad dw f1,f2,f3,f4
f1 db '1) reset pc',0
f2 db '2) start system',0
f3 db '3) clock',0
f4 db '4) set clock',0
dis_beg:push ax
push es
push di
push cx
push si
push bx
push dx
mov ax,0b800h
mov es,ax
mov cx,0 ;行数计数器
mov si,0 ;每行地址的指针
next:mov di,10*160+32*2
mov ax,160
mul cx
add di,ax
mov bx,ad[si]
add si,2
s0:mov al,cs:[bx]
cmp al,0 ;一行是否结束
je s1
add bx,1
;display功能选择
cmp dis_choice,1
je s2
mov byte ptr es:[di],' '
jmp short s5
s2:mov es:[di],al
s5:add di,2
jmp short s0
s1:add cx,1
cmp cx,4
je dis_end
jmp short next
dis_end:pop dx
pop bx
pop si
pop cx
pop di
pop es
pop ax
ret
clock_dis:jmp short s7
format db 'YE/MO/DA hh:mm:ss',0
position db 9,8,7,4,2,0
s7:mov bx,0
mov si,0
mov cx,6
s9:mov al,position[bx]
out 70h,al
in al,71h
mov ah,al
push cx
mov cl,4
shr ah,cl
pop cx
and al,00001111b
add ah,30h
add al,30h
mov format[si],ah
mov format[si+1],al
add si,3
inc bx
loop s9
mov ax,0b800h
mov es,ax
mov di,160*12+62
mov si,0
s8:cmp byte ptr format[si],0
je s7
mov al,format[si]
mov es:[di],al
inc si
add di,2
jmp short s8
codesg ends
end start
由于使用代码格式无法再自定义蓝色和红色,所以在下面那个帖子中我会用代码格式把这个再发一遍,方便大家看
另外附上我在标号s7的地方加上下面的代码进行过的一次调试
mov ax,0b800h
mov es,ax
inc byte ptr es:[160*24+158]
观察按3以后s7是不是一直在执行。结果是右下角的符号每次按3会快速变化一下,然后就不变了。比如第一次按3后显示'G',按esc退出第二次按3进去,变成一个乱码,然后再按esc再按3进入,又是变了一下就停了,如图。为啥每次都是只执循环限次数呢?这可能就是带来上面的问题原因