《汇编语言》课程设计2

 

assume cs:code,ss:stack
stack segment
    db 128 dup (0)
stack ends
code segment
start:
    mov ax,stack
    mov ss,ax
    mov sp,128
    
    call copy_boot
    
    ;设置CS:IP为0:7e00h
    mov ax,0
    push ax
    mov ax,7e00h
    push ax
    retf
    
    mov ax,4c00h
    int 21h
;org 7e00h
;引导程序
boot:
    jmp boot_begin
    func0    db 'Hk_Mayfly----XIUXIUXIU~',0
    func1    db '1) reset pc',0
    func2    db '2) start system',0
    func3    db '3) clock',0
    func4    db '4) set clock',0
    ;相减得到的是标号的相对位置,+7e00h得到的绝对位置
    func_pos    dw offset func0-offset boot+7e00h
                dw offset func1-offset boot+7e00h
                dw offset func2-offset boot+7e00h
                dw offset func3-offset boot+7e00h
                dw offset func4-offset boot+7e00h
    time    db 'YY/MM/DD hh:mm:ss',0
    cmos    db 9,8,7,4,2,0
    clock1    db 'F1----change the color        ESC----return menu',0
    clock2    db 'Please input Date and Time,(YY MM DD hh mm ss):',0
    change    db 12 dup (0),0

boot_begin:
    call init_boot
    call cls_screen
    call show_menu 
    jmp choose
    mov ax,4c00h
    int 21h

choose:
    call clear_kb_buffer
    ;获取我们输入的操作,跳转到对于函数
    mov ah,0
    int 16h
    cmp al,'1'
    je choose_func1
    cmp al,'2'
    je choose_func2
    cmp al,'3'
    je choose_func3
    cmp al,'4'
    je choose_func4
    
    jmp choose

;在题中提到了,开机后进入到ffff:0处执行指令
;那我们也可以把重启理解为,跳转到ffff:0执行指令
;所以我们利用jmp dword跳转到ffff:0地址,模拟重启
choose_func1:
    mov bx,0ffffh
    push bx
    mov bx,0
    push bx
    retf
    
    jmp choose

;题中对引导现有的操作系统的描述是调用int 19,这里为了方便就直接写成函数了
choose_func2:
    mov bx,0
    mov es,bx
    mov bx,7c00h
    
    mov al,1;扇区数
    mov ch,0
    mov cl,1;扇区
    mov dl,80h
    mov dh,0
    mov ah,2;读取
    int 13h
    
    mov bx,0
    push bx
    mov bx,7c00h
    push bx
    retf
    
    jmp choose

;获取时间
choose_func3:
    call show_time
    
    jmp choose

show_time:
    call init_boot
    call cls_screen
    ;显示按键信息
    mov si,offset clock1-offset boot+7e00h
    mov di,160*14+10*2;在14行10列显示
    call show_line
show_time_start:
    ;获取时间信息,并显示(将time中的未知字符替换为当前时间)
    call get_time_info
    mov di,160*10+30*2;屏幕显示的偏移地址
    mov si,offset time-offset boot+7e00h;time标号的偏移地址
    call show_line
    
    ;获取键盘缓存区的数据
    mov ah,1
    int 16h
    ;没有数据就跳回show_time_start
    jz show_time_start
    ;判断是否按下F1
    cmp ah,3bh
    je change_color
    ;判断是否按下ESC
    cmp ah,1
    je Return_Main
    ;有数据,但是是无用的键盘中断,清除
    cmp al,0
    jne clear_kb_buffer2
    ;返回开始,重复之前的操作,达到刷新时间的效果。
    jmp show_time_start

change_color:
    call change_color_show
clear_kb_buffer2:
    call clear_kb_buffer
    jmp show_time_start
Return_Main:
    ;返回到开始,重新打印菜单
    jmp boot_begin
    ret

choose_func4:
    call set_time
    jmp boot_begin
    
set_time:
    call init_boot
    call cls_screen
    call clear_stack
    
    ;设置提示信息显示位置
    mov di,160*10+13*2
    mov si,offset clock2-offset boot+7e00h
    call show_line
    ;显示修改后change中的内容
    mov di,160*12+26*2
    mov si,offset change-offset boot+7e00h
    call show_line
    
    call get_string

get_string:
    mov si,offset change - offset boot + 07e00H
    mov bx,0
getstring:
    ;获取键盘输入的时间信息
    mov ah,0
    int 16h
    
    ;输入的时间为数字0~9
    cmp al,'0'
    jb error_input
    cmp al,'9'
    ja error_input
    ;将我们输入的时间字符入栈
    call char_push
    ;不能超过输入的数量
    cmp bx,12
    ja press_ENTER
    mov di,160*12+26*2
    call show_line
    jmp getstring
error_input:
    ;判断是不是按下退格或回车键
    cmp ah,0eh
    je press_BS
    cmp ah,1ch
    je press_ENTER

    jmp getstring
;按下回车
press_BS:
    call char_pop
    mov di,160*12+26*2
    call show_line
    jmp getstring
;按下enter就退出
press_ENTER:
    ret

char_push:
    ;只能最多输入12个梳子
    cmp bx,12
    ja char_push_end
    ;将数值移动到对应位置
    mov ds:[si+bx],al
    inc bx;表示我们输入了多少个字符
char_push_end:
    ret

char_pop:
    ;判断是否输入了设置时间的数值,没有就相当于删完了
    cmp bx,0
    je char_pop_end
    ;否则用星号替换,相当于删除
    dec bx
    mov byte ptr ds:[si+bx],'*'
char_pop_end:
    ret

clear_stack:
    push bx
    push cx
    
    mov bx,offset change-offset boot+7e00h
    mov cx,12
cls_stack:
    ;替换change段中内容
    mov byte ptr ds:[bx],'*'
    inc bx
    loop cls_stack
    
    pop cx
    pop bx
    ret
    

;获取时间
get_time_info:
    ;从cmos ram获取年月日,时分秒6个数据
    mov cx,6
    ;获取存放单元地址
    mov bx,offset cmos - offset boot + 7e00H
    ;通过替换来显示
    mov si,offset time - offset boot + 7e00H
next_point:   
    push cx
    ;获取单元号
    mov al,ds:[bx]
    ;向70h端口写入要访问的单元地址,并从71h端口读取数据
    out 70H,al
    in al,71H
    ;右移4位获取十位
    mov ah,al
    mov cl,4
    shr al,cl
    and ah,00001111b
    ;将BCD码转换为ASCII码
    add ax,3030H
     ;写入time中
    mov word ptr ds:[si],ax
    ;下一单元号
    inc bx
    ;每个数据之间距离都是3
    add si,3
    pop cx
    loop next_point
    ret

;改变颜色
change_color_show:
    push bx
    push cx
 
    mov cx,2000
    mov bx,1
next:
    ;属性值+1,改变颜色
    add byte ptr es:[bx],1
    ;当超出字体颜色的数值(0~111h)时,将数值重置
    cmp byte ptr es:[bx],00001000b
    jne change_end
    ;因为背景是黑色,所以文字颜色就不设置成黑色了
    mov byte ptr es:[bx],1
change_end:
    add bx,2
    loop next
 
    pop cx
    pop bx
    ret

clear_kb_buffer:
    ;1号程序,用来检测键盘缓冲区是否有数据
    ;如果有的话ZF!=0,没有,ZF=0
    mov ah,1
    int 16h
    ;通过ZF判断减缓缓冲区是否有数据,没有就跳出
    jz clear_kb_bf_end
    mov ah,0
    int 16h
    jmp clear_kb_buffer
clear_kb_bf_end:
    ret

init_boot:
    ;基本设置,注意:程序的直接定址表默认段地址是CS
    ;当程序转移到7c00h时,代码中CS值未发生改变,
    ;所以需要我们指明段地址
    mov bx,0b800h
    mov es,bx
    mov bx,0
    mov ds,bx
    ret
    
;清屏
cls_screen:
    mov bx,0
    mov cx,2000
    mov dl,' '
    mov dh,2;字体为绿色,不设置的话,在我们显示菜单时,字体和背景颜色相同
s:    mov es:[bx],dx
    add bx,2
    loop s
sret:
    ret

;展示界面
show_menu:
    ;在10行,30列显示菜单
    mov di,160*10+30*2
    ;保存在直接定址表的绝对位置
    mov bx,offset func_pos-offset boot+7e00h
    ;菜单有5行
    mov cx,5
s1:
    ;这里相当于外循环,每次一行
    ;获取func_pos中每行的保存位置的偏移地址
    mov si,ds:[bx]
    ;调用内循环函数,输出一行的每个字符
    call show_line
    ;下一行偏移地址
    add bx,2
    ;下一行显示
    add di,160
    loop s1
    ret
    
show_line:
    push ax
    push di
    push si
show_line_start:
    ;获取这一行的第si+1个字符
    mov al,ds:[si]
    ;判断是否到末尾
    cmp al,0
    je show_line_end
    ;保存字符到显示缓冲区
    mov es:[di],al
    add di,2
    inc si
    jmp show_line_start
show_line_end:
    pop si
    pop di
    pop ax
    ret

boot_end:nop

;转存引导程序
copy_boot:
    ;将引导程序储存到指定位置
    mov ax,0
    mov es,ax
    mov di,7e00h
    
    mov ax,cs
    mov ds,ax
    mov si,offset boot
    mov cx,offset boot_end-offset boot
    cld
    rep movsb
    
    ret

code ends
end start

 

具体的在注释中都说明了。

jz指令:https://zhidao.baidu.com/question/564008138.html

int 16的1号程序:https://zhidao.baidu.com/question/511189643.html

 

总结

  汇编的难度并不大,我认为在有编程的基础上,学习汇编要做到细致,细致的理解计算机编程的编译过程,对于我理解其他编程语言也有很大的帮助。欢迎大家关注,一起交流。

转载于:https://my.oschina.net/hkmayfly/blog/3081209

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
阅读下面的材料 : 开机后, CPU 自动进入到 FFF0:0 单元处执行,此处有一条跳转指令。 CPU 执行该指令后,转去执行 BIOS 中的硬件系统检测和初始化程序。 初始化程序将建立 BIOS 所支持的中断向量,即将 BIOS 提供的中断历程的入口地址登记在中断向量表中。 硬件系统检测和初始化完成后,调用 INT 19H 进行操作系统的引导。 如果设为从软盘启动操作系统,则 INT 19H 将主要完成一下工作: ( 1 )控制 0 号软驱,读取软盘 0 道 0 面 1 扇区的内容到 0 : 7C 00 。 ( 2 )将 CS:IP 指向 0 : 7C 00 。 软盘的 0 道 0 面 1 扇区中装有操作系统引导程序。 INT 19H 将其装到 0 : 7C 00 处后,设置 CPU 从 0 : 7C 00 开始执行此处的引导程序,操作系统被激活,控制计算机。 如果在 0 号软驱中没有软盘,或发生软盘 I/O 错误,则 INT 19H 将主要完成以下工作 ; (1) 读取硬盘 C 的 0 道 0 面 1 扇区的内容到 0 : 7C 00 ; (2) 将 CS:IP 指向 0 : 7C 00 。 这次课程设计的任务是编写一个可以自行启动计算机,不需要在现有操作系统环境中运行的程序。 改程序的功能如下: ( 1 )列出功能选项,让用户通过键盘进行选择,界面如下: 1 ) reset pc ; 重新启动计算机 2 ) Start system ; 引导现有的操作系统 3 ) Clock ; 进入时钟程序 4 ) Srt clock ; 设置时间 ( 2 )用户输入“ 1 ”后重新启动计算机。(提示:考虑 FFFF:0 ) ( 3 )用户输入“ 2 ” 后引导现有的操作系统。(提示:考虑硬盘 C 的 0 道 0 面 1 扇区) ( 4 )用户输入“ 3 ”后,执行动态现实当前日期,时间的程序。 现实格式如下:年 / 月 / 日 时:分:秒 进入此项功能后,一直动态现实当前的时间,在屏幕上将出现时间按秒变化的效果。(提示:循环读取 CMOS ) 当按下 F1 键后,改变现实颜色;按下 ESC 键后,返回到主选单。(提示:利用键盘中断) ( 5 )用户输入“ 4 ”后可更改当前的日期,时间,更改后返回到主选单。(提示:输入字符串) 下面给出的几点建议: ( 1 )在 DOS 下编写安装程序,在按转程序中包含任务程序; ( 2 )运行安装程序,将任务程序写到软盘上; ( 3 )若要任务程序可以在开机后自行执行,要将它写到软盘的 0 道 0 面 1 扇区上。如果程序长度大于 512B ,则需要用多个扇区存放,这种情况下,处于软盘 0 道 0 面 1 扇区中的程序就必须负责将其他扇区中的内容读入内存。 这个程序较为复杂,它用到了我们所学到的所有技术,需要进行仔细地分析和耐心地调试。这个程序对于我们的整个学习过程是具有总结性的,希望读者能够尽力完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值