comment ;
1、编写本地程序
①把引导程序写入软盘0面0道1扇区
②把子程序写到软盘0面0道2—5扇区
2、编写软盘程序
①引导程序,从软盘中读出子程序写到0:200内存中
②子程序,菜单,重启、引导现有程序、显示时间、设置时间、清屏
其中,显示时间中按键改变颜色,设置时间中接受字符串
;
;#mode=dos
code segment
assume cs:code
start:
;写软盘的程序
mov ax,seg begin
mov es,ax
mov bx,offset begin
mov al,1
mov ch,0
mov cl,1
mov dh,0
mov dl,0
mov ah,3 ;1扇区的程序
int 13h ;将读软盘写内存的程序写入0道0面1扇区
;怎么确定数据的结尾
mov ax, next
mov es,ax
mov bx,0
;2-4扇区的程序
mov al,3 ;几个扇区
mov ch,0 ;磁道号
mov cl,2 ;开始扇区号
mov dh,0 ;磁头号(面)
mov dl,0 ;驱动器号
mov ah,3 ;功能号
int 13h
;退出
mov ax,4c00h
int 21h
;------------------------第一步结束----------------------------
begin:
mov ax,2000h;?????????????错误一0:200处不能写入,不知道为什么
mov es,ax
mov bx,0
mov al,3;共3三个扇区
mov ch,0
mov cl,2;开始扇区
mov dl,0
mov dh,0
mov ah,2
int 13h ;将2-4扇区的子程序写入0:204
mov ax,2000h
push ax
mov ax,0
push ax
retf
;--------------------------第二步完成--------------------------
code ends
next segment
;用直接定址表
jmp main;错误二,如果使用直接定址表的话需要用段去封装以保证其偏移能对应上。并且必须把子程序放到段开始的位置
table dw rest,sys,clock,stck ;table的偏移为2
main:
call menu
mov ah,00h
int 16h
mov cx,1
mov ah,9
int 10h
sub al,31h;把ASCII转换成对应数字
cmp al,3
ja return
mov bx,0
mov bl,al
add bx,bx
call word ptr table[bx]
return:
jmp short main
;---------------------主菜单--------------------------------
datam db "1) reset pc#"
db "2) start system#"
db "3) clock#"
db "4) set clock#"
db "Please enter your choose$"
menu:
mov bh,2;清屏后为绿色
call clear
mov ax,cs
mov ds,ax
mov si,offset datam ;设置显示数据的指向
;设置光标
mov bh,0 ;0页
mov dh,5 ;行
mov dl,15 ;列
;显示属性
mov bl,2 ;字符属性
mov bh,0 ;第0页
s:
mov ah,2
int 10h ;置光标
mov al,[si]
inc si
cmp al,'$'
je ret1
cmp al,'#'
je special
mov cx,1
mov ah,9
int 10h ;显示字符
inc dl
jmp short s
special:
mov dl,15
add dh,3
jmp short s
ret1:
mov dh,19 ;行
mov dl,15 ;列
mov ah,2
int 10h
ret
;四个子程序
;---------------------重启子程序-----------------------
rest:
mov ax,0ffffh
push ax
mov ax,0
push ax
retf
;------------------引导原有操作系统-------------
sys:
mov ax,0
mov es,ax
mov bx,7c00h
mov al,1
mov ch,0
mov cl,1
mov dh,0
mov dl,80h ;硬盘
mov ah,2
int 13h
mov ax,0
push ax
mov ax,7c00h
push ax
retf
;----------------------显示时钟子程序----------------------------
clock:
push ax
push bx
push cx
push ds
push es
push si
push di;保护现场
push bp;保护现场
mov bh,1;清屏后为蓝色
call clear
mov bl,1;文字颜色
get_key:
call ok ;调用显示时间程序
mov ah,01h;检测键盘输入
int 16h
cmp al,0
je get_key;如果没有输入,继续检测。做成中断就比较好了
mov ah,0
int 16h;有输入的话,就分析安键
cmp ah,3bh;F1
je chgcolor
cmp ah,01h;ESC
je back
jmp get_key;其他按键忽略
;返回
back:
pop bp
pop di
pop si
pop es
pop ds
pop cx
pop bx
pop ax
ret
chgcolor:
mov ax,0b800h
mov ds,ax
mov si,1
mov cx,2000
inc bl
change:
mov [si],bl
add si,2
loop change
jmp get_key
ok:
push ax
push bx
push cx
push ds
push si
push es
push di
push bp ;保护现场
jmp begins
addre: db 9,8,7,4,2,0 ;单元地址;年月日时分秒
temp: dw 8 dup(0)
begins:
mov ax,cs
mov ds,ax
lea si,addre
lea bx,temp
mov bp,0
mov cx,6
;从端口里取数据,转换后放入temp里
s1:
mov al,[si]
out 70h,al
in al,71h
mov ah,al
and ah,00001111b
push cx
mov cl,4
shr al,cl
pop cx
mov [bx],ax
cmp bp,2
jb g ;/
ja d ;:
mov al,-10h
jmp cz
g: mov al,'/'-30h
jmp cz
d: mov al,':'-30h
jmp cz
cz:
mov [bx+2],al
inc si
inc bp
add bx,3
loop s1
mov ax,'$' ;结束标志
mov [bx],ax
;从temp里取出数据显示,遇到$结束
lea bx,temp
mov ax,0b800h
mov es,ax
mov di,160*7+30*2
s0:
mov al,[bx]
cmp al,'$'
je ret0
add al,30h
mov es:[di],al
inc bx
add di,2
loop s0
ret0:
mov al,20h
mov es:[di-2],al
pop bp
pop di ;恢复现场
pop es
pop si
pop ds
pop cx
pop bx
pop ax
ret
;设置时钟
stck:
jmp setk
addre2: db 9,8,7,4,2,0 ;单元地址;年月日时分秒
time db 16 dup(0)
mseg: db "Please enter time like:yy/mm/dd hh:mm:ss",'$'
setk:
mov bh,2
call clear
mov ax,cs
mov ds,ax
lea si,mseg;不同地方,lea还是比较好使的
mov ax,0b800h
mov es,ax
mov di,6*160+50
print:
mov al,[si]
cmp al,'$'
je retp
mov es:[di],al
add di,2
inc si
jmp print
retp:
add di,480-80
mov bx,0
intime:
mov ah,0
int 16h
cmp ah,0eh;退格键
je backsp
cmp ah,1ch
je set
cmp bx,12;只允许输入12个字符
je set
mov es:[di],al;显示
cmp al,'/';过滤字符
je guo
cmp al,' ';过滤字符
je guo
cmp al,':';过滤字符
je guo
mov time[bx],al;保存用户的输入time的段前缀使CS
inc bx
guo:
add di,2
jmp intime
backsp:
cmp bx,0
je intime;输入为空不能在减了
sub di,2;显示减2
mov al,es:[di]
cmp al,' '
je ca
cmp al,'/'
je ca
cmp al,':'
je ca
dec bx;存储减一
ca:
mov al,' '
mov es:[di],al
jmp intime
;设置栈,实现backspace,和字符的输入显示
;根据输入设置时钟
set: mov time[bx],'$';结束标志符,防止用户输入错误
lea si,time
lea bx,addre2
complex:
mov ax,[si];取出字符
cmp al,'$';检查边界
je retset
sub ax,3030h;ah存BCD码的个位,al存BCD码的十位
mov cl,4
shl al,cl;al左移四位
add ah,al;合成8位
mov al,[bx];取出地址
out 70h,al
mov al,ah
out 71h,al;写入内容
inc bx;指向下一个地址
add si,2;si指向下一个
jmp complex
retset:
ret
;读取键盘,返回主菜单
;----------------------清屏程序-----------------------------
clear:
mov al,0 ;滚动的行数,0为清屏
;mov bh,2 ;清屏后默认的属性
mov ch,0 ;左上角Y
mov cl,0 ;左上角X
mov dh,24 ;右下角y
mov dl,79 ;右下角X
mov ah,06h ;功能号06向上滚动,07向下滚动
int 10h
ret
delay:
push ax
push bx
push cx
mov bx,1
;执行完33144次是0.5s
again: mov cx,33144
waitf:
in al,61h ;跟61h端口的pb4有关
and al,10h
cmp al,ah
je waitf
mov ah,al
loop waitf
dec bx
jnz again
pop cx
pop bx
pop ax
ret
next ends
end start
- [cutebe] 相当牛,这个苦思冥想也值了。^_^ 11/30 00:00
- [parse] 如果忽略消息循环,那么操作系统加载的程序很快就执行完了,就像DOS程序一闪而过,所以CPU会空闲下来 06/30 09:04
- [游客] 楼主好厉害,挺一下! 01/19 08:43
- [游客] 很不错。 01/04 18:36
- [chinatree] 潜力贴留名,沙发。 11/08 12:58
- [youthangel] 恩,这次对了 10/30 18:56
- [fpamc] mov bx,18 在这条指令的上边是不是要加一条sub dx,dx? 10/30 10:03
- [fpamc] 对的 10/27 11:19
- [fpamc] 对的 10/27 09:00
- [fpamc] 哦,对不起,看错了。实验13也有一个7ch中断 10/27 08:52
- [游客] 现在急需一个汇编大作业。。。。。。可以么。。。。。如果今天之内看见留言 就加 1765496715 12/28 16:52
- [youthangel] 这算是对我学习的鼓励吗?谢谢!咱们这样交流就可以了 10/11 15:48
- [fpamc] 多日观察,你的学习积极性挺高的。可以来我们群了。群号:75916434 10/11 10:58