IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> (王爽)汇编语言-课程设计二完整版 -> 正文阅读

[Java知识库](王爽)汇编语言-课程设计二完整版

前言

刚刚把lab2调试完,2021年10月12日 16:26:36,本来是打算在onenote上记笔记的,但是做这个实验以来走了很多的弯路,费了很多时间,不妨把这些坑在此记录一下,能帮助有缘看到此文章的小伙伴节省一点时间,可使得所浪费的时间更有价值不是,本编文章属于有感而发,排版和字体如有不合适的地方,还请海涵

特别感谢

感谢这个小伙伴的思路:
写的非常好的课程设计二完整版链接之王爽《汇编语言》课程设计二续(包含软盘操作)

实验结果

展示过程:
1、功能三:显示时间,F1改变颜色,Esc退出到菜单
2、功能四:修改时间为080808080808,然后Esc退出到菜单,通过功能三验证时间修改
3、功能一:重启系统
4、功能二:重新引导现有操作系统,也就是xp
在这里插入图片描述

实验思路

首先做这个课设千万不要着急,因为它的周期相对于书本上的检测点以及实验来说,是长很多的,就像书本中最后建议说的:该程序较为复杂,使用到了我们的毕生所学,需要进行仔细的分析和耐心调试。
大伙都晓得,王爽这本书讲究的是循序渐进,那么既然学到了最后一节,就需要验证我们循序渐进解决问题的能力了,所以这里我是按阶段进行的,每完成一个阶段保存当前的代码,做好笔记,方便后续回看和出错时进行比对:

  1. 阶段一 :实现引导程序
    这里的难点在于环境的部署,也就是虚拟机下xp系统的安装,以及引导程序的理解,其中安装环境参考这里,引导程序的理解参考这里
    为了方便理解,这里先把引导程序称为lead,任务程序称为boot,简单说就是系统会自动把0道0面1扇区的程序放到0:7c00h处执行,所以我们只要往0道0面1扇区写入boot程序即可,但是实际上boot程序是大于512字节的,也就是系统只会把boot程序的前512个字节复制到内存,而后面的就不复制了,这样肯定是不行的,所以就需要我们再写一个lead程序,lead程序是肯定在512字节以内,让系统把lead程序复制到内存,然后我们lead程序的功能就是把boot程序复制到接下来要执行的内存空间,就实现了让系统执行大于512字节的boot程序了
    在这里插入图片描述

  2. 阶段二 :实现功能一二
    考察retf指令的使用,以及13h中断的使用,dl为0表示软驱A,80h表示硬盘C,这里看书就能解决

  3. 阶段三 :实现功能三
    难点在于程序实时显示时间的过程中,还要在任意情况下能响应键盘中断,这里没有采用重新安装int 9中断实现,而是采用了上述小伙伴的方法,通过int 16h0号和1号功能配合,实现清空缓冲区,但是弊端就是书本上没有说16h的1号功能,而是采用int 9去实现esc改变颜色的,如果按书本重新安装int 9中断实现,那么就不只功能三,在所有按键中断中都会通过esc改变颜色,请各位自行取舍,实现方法应该不唯一

  4. 阶段四 :实现功能四
    难点在于调试,因为这个无法在dos下验证时间是否修改成功,在虚拟机下可能会导致写cmos错误引起必须注册windows xp的问题,严重可能导致重新安装xp,所以建议各位克隆一份虚拟机留条后路,同时这里也提供进入安全模式重置时间的方法去解决激活问题

  5. 阶段五 :优化界面与提示
    这个就没啥好说的你们自行发挥就是了

如何优化调试流程以节省时间

1、这个实验光调试我就进行了200次左右了,如果反复masm link是肯定不行的,参考这里设置自动挂载,我的文件名是lab2,所以如下设置
在这里插入图片描述
实际效果,一打开dos就自动执行,如果不想自动执行可以自己跳转语句,通过#注释即可
在这里插入图片描述
2、 代码中通过条件编译指令IFDEF、IFNDEF,与伪指令org的配合,来实现最小改动情况下实现双环境编译调试,避免了每个偏移量计算时都要频繁的改动offset 某标号 - offset boot + 7e00h
比如这样表示dos调试,在这种情况下编译运行的程序可以在dos环境下通过debug验证
在这里插入图片描述
在这里插入图片描述
只需添加一个’;’,注释掉该语句,再编译运行,即可在虚拟机环境下运行
在这里插入图片描述

源码

编码不太规范,请多指教,如果造成困扰十分抱歉

;2021年10月12日 10:20:41

;难点:如何实现在任意情况下都能响应键盘中断
;解决方案:
;1、采用重新安装int 9中断的方法,因为任意外设的输入都要调用int 9中断,
;通过int 9可随时获取键盘输入
;弊端:该中断会影响所有的外设输入,而不仅仅是时钟程序
;2、采用int 16h的0号和1号功能配合,清空键盘缓冲区,通过1号功能查询,
;非有效输入再通过0号功能读取,用于预防键盘缓冲区为空时,调用0号功能
;导致程序阻塞
;清空缓冲区功能面临的主要问题:在键盘缓冲区为空时调用0号功能会导致程序阻塞
;1号功能简述:当缓冲区为空时,ZF标志位为1;当缓冲区非空时,ZF标志位为0

assume cs:code

code segment
;================主程序================
start:

;DOS:nop         ;开启表示dos调试/注释表示虚拟机调试
    IFDEF DOS
    call boot
    ELSE
    call lead_to_disk
    call boot_to_disk
    ENDIF

    mov ax,4c00h
    int 21h
;=====================================

;================引导程序==============
lead:
    mov ax,0    ;尝试将栈顶设置为0:210出错
    mov ss,ax   
    mov sp,7c00h 

    call boot_to_memory

    mov ax,0    ;cs
    push ax
    mov ax,7e00h;ip
    push ax

retf            ;通过retf设置cs:ip
;-------------------------------------
;读到0:7e00h
boot_to_memory:
    mov ax,0    ;es:bx表示内存地址,2将磁盘数据读入内存/3将内存数据写入磁盘
    mov es,ax   ;将0道0面1扇区数据读入内存0:7e00h
    mov bx,7e00h

    mov ah,2    ;2读/3写
    mov al,2    ;扇区数
    mov ch,0    ;磁道号
    mov cl,2    ;扇区号
    mov dh,0    ;面号
    mov dl,0    ;0软驱A/80h硬盘C

    int 13h

ret
;-------------------------------------
lead_to_disk:
    mov ax,cs   ;es:bx表示内存地址,2将磁盘数据读入内存/3将内存数据写入磁盘
    mov es,ax   ;将内存代码段中的lead程序写入0道0面1扇区
    mov bx,offset lead

    mov ah,3    ;2读/3写
    mov al,1    ;扇区数
    mov ch,0    ;磁道号
    mov cl,1    ;扇区号
    mov dh,0    ;面号
    mov dl,0    ;0软驱A/80h硬盘C

    int 13h

ret
;-------------------------------------
boot_to_disk:
    mov ax,cs   ;es:bx表示内存地址,2将磁盘数据读入内存/3将内存数据写入磁盘
    mov es,ax   ;将内存代码段中的boot程序写入0道0面2扇区
    mov bx,offset boot

    mov ah,3    ;2读/3写
    mov al,2    ;扇区数
    mov ch,0    ;磁道号
    mov cl,2    ;扇区号
    mov dh,0    ;面号
    mov dl,0    ;0软驱A/80h硬盘C

    int 13h

ret
;=====================================
IFNDEF DOS
    org 7e00h
ENDIF
;================boot程序==============
boot:
    jmp boot_start
    MENU_1:    	db 'Please Enter Your Choose(1~4):',0    
    MENU_2:     db '1) reset pc',0
    MENU_3:     db '2) start system',0
    MENU_4:     db '3) clock',0
    MENU_5:     db '4) set clock',0
    MENU_6:     db 'SC From Mr.Kang & Learn By Mr.Liang 0.0',0

    MENU_ADD:   dw offset MENU_1
    	        dw offset MENU_2
                dw offset MENU_3
                dw offset MENU_4
                dw offset MENU_5
                dw offset MENU_6

    CMOS_RAM:   	db 9,8,7,4,2,0
    TIME_FORMAT:	db 'yy/mm/dd hh:mm:ss',0    ;于11行30列绘制时间,13行15列绘制提示
    TIME_STRING:	db 12 dup('*'),0
    TIME_SHOW_TIPS:	db 'Enter F1 to change the color,and enter Esc to exit',0
    TIME_SET_TIPS:	db 'Enter [0~9] to set the time,and enter Esc to exit',0

boot_start:
    mov ax,0    	;参考书本中retf指令的使用,需要设置栈顶指针
    mov ss,ax   
    mov sp,7c00h 

    call show_menu
    call choose_option

    mov ax,4c00h
    int 21h
;-------------------------------------
show_menu:
    push bx
    push di     ;显示位置
    push si     ;字符地址

    call clear_screen

    mov bx,0b800h
    mov es,bx
    mov di,9*160+23*2
    mov bx,offset MENU_ADD

    mov cx,6    ;显示6行
    loop_to_draw_menu:
        mov si,cs:[bx]
        call draw_string_end_in_0
        add di,160      ;控制下一行
        add bx,2        ;下一行字符串的地址
        loop loop_to_draw_menu

    pop si
    pop di
    pop bx

ret

;绘制以0为结尾的字符串
draw_string_end_in_0:
    push di     ;显示位置
    push si     ;字符地址

    draw_char:
        mov al,cs:[si]
        cmp al,0
        je draw_char_over
        mov es:[di],al
        add di,2
        inc si
        jmp draw_char

draw_char_over:
    pop si
    pop di

ret
;-----------------------------------
choose_option:  				;参考书本16章
    call clear_keyboard_buffer  ;清除键盘缓冲区,然后再通过阻塞方式等待用户输入 

    mov ah,0    				;读取键盘缓冲区,不用担心缓冲区为空时阻塞
    int 16h     				;因为阻塞等待用户输入也符合程序的设计

    cmp al,'1'
    je choose_one
    cmp al,'2'
    je choose_two
    cmp al,'3'
    je choose_three
    cmp al,'4'
    je choose_four   

    jmp choose_option           ;继续等待用户输入

    choose_one:
        call ResetPC
        jmp short choose_ret    ;实际未跑到,因为系统已重启

    choose_two:
        call StartSystem
        jmp short choose_ret    ;实际未跑到,因为已正常进入xp系统

    choose_three:
        call Clock
        jmp short choose_ret    ;实际未跑到,Esc会重新返回主菜单

    choose_four:
        call SetClock
        jmp short choose_ret    ;实际未跑到,Esc会重新返回主菜单

    choose_ret:
ret
;-----------------------------------
ResetPC:
    mov ax,0ffffh
    push ax
    mov ax,0
    push ax

retf 
;-----------------------------------
StartSystem:
    mov ax,0
    mov es,ax
    mov bx,7c00h

    mov ah,2    ;2读/3写
    mov al,1    ;扇区数
    mov ch,0    ;磁道号
    mov cl,1    ;扇区号
    mov dh,0    ;面号
    mov dl,80h  ;0软驱A/80h硬盘C

    int 13h

    mov ax,0
    push ax
    mov ax,7c00h
    push ax

retf
;-----------------------------------
Clock:
    push di    ;显示位置
    push si    ;字符地址

    mov ax,0b800h
    mov es,ax

    call clear_screen               ;首先清屏并绘制提示信息
    mov di,13*160+15*2              
    mov si,offset TIME_SHOW_TIPS
    call draw_string_end_in_0       

    mov di,11*160+30*2              ;给draw_line_end_with_0传参
    mov si,offset TIME_FORMAT

    loop_to_draw_time:
        call key_interrupt          ;其次判断是否有esc和f1键盘中断
        call update_time_data       ;没有中断则更新时间数据
        call draw_string_end_in_0   ;绘制时间数据字符串
        jmp loop_to_draw_time

    pop si
    pop di

ret

;处理F1与Esc键盘中断
key_interrupt:
    mov ah,1                    	;通过1号功能查询
    int 16h

    jz key_interrupt_ret        	;缓冲区为空则退出,防止调用0号导致阻塞

    mov ah,0                    	;跑到这里表示缓冲区不为空,可以调用0号功能
    int 16h                     	;用扫描码判断,ASCII码无法区分Esc和F1非单字符

    cmp ah,3Bh                  	;3Bh为F1按下时的扫描码
    je change_foreground        	;函数内有ret返回

    cmp ah,01h                  	;01h为Esc按下时的扫描码
    je esc_function

    call clear_keyboard_buffer  	;非F1和Esc输入,清除键盘缓冲区

    key_interrupt_ret:
ret

;更新代码段TIME_FORMAT时间格式字符串
update_time_data:
    push cx
    push bx
    push di

    mov bx,offset CMOS_RAM
    mov di,offset TIME_FORMAT
    mov cx,6

    loop_to_read_cmos:
        push cx                 	;位移指令更改了cl的值,要记得保存cx
        mov al,cs:[bx]          	;读cmos中年月日的数据
        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 byte ptr cs:[di],ah 	;更新代码段TIME_FORMAT时间格式字符串
        inc di                  	;更新下个字符           
        mov byte ptr cs:[di],al

        add di,2                	;跳过年月日间隔符'/'和时分秒间隔符':',以及年月日与时分秒之间的空格间隔符
        inc bx                  	;CMOS_RAM为db定义,所以inc即可
        pop cx
        loop loop_to_read_cmos

    pop di
    pop bx
    pop cx

ret

;清除键盘缓冲区
clear_keyboard_buffer:
    mov ah,1                    
    int 16h

    jz clear_keyboard_buffer_over

    mov ah,0
    int 16h
    jmp clear_keyboard_buffer   	;通过1号查询,缓冲区非空,再通过0号取出

    clear_keyboard_buffer_over:
ret     

;改变前景色
change_foreground:              	;参考书本16章
    push bx
    push cx
    push es

    mov bx,0b800h
    mov es,bx
    mov bx,1
    mov cx,2000

    change_fore_color:
        inc byte ptr es:[bx]    	;该语句参考书本,已优化,功能为随机改变颜色
        add bx,2
        loop change_fore_color

    pop es
    pop cx
    pop bx
ret

;esc按键退出主菜单处理
esc_function:
    mov bx,offset top
    mov byte ptr cs:[bx],0      	;设置top为0

    call clear_time_string
    call clear_keyboard_buffer
    jmp boot_start              	;这里跳转会导致之前压栈的数据没有弹栈处理,但boot_start中又重新初始化栈
                                	;再次压栈则会替换掉旧栈中的数据
;-----------------------------------
SetClock:
    push di
    push si

    mov ax,0b800h
    mov es,ax

    call clear_screen           ;清屏并绘制*号提示

    mov di,13*160+15*2			;绘制提示
    mov si,offset TIME_SET_TIPS
    call draw_string_end_in_0

    mov di,11*160+30*2
    mov si,offset TIME_STRING
    call draw_string_end_in_0

    call clear_keyboard_buffer
    call getstr

    pop si
    pop di
ret

getstr:
    push ax

getstrs:
    mov ah,0                        ;清空键盘缓冲区并阻塞等待用户输入
    int 16h

    cmp al,'0'
    jb nonumber
    cmp al,'9'
    ja nonumber
    mov ah,0
    call charstack
    mov ah,2
    call charstack
    jmp getstrs

    nonumber:
        cmp ah,0eh                  ;退格键扫描码
        je backspace
        cmp ah,1ch                  ;Enter键扫描码
        je input_end
        cmp ah,01h                  ;Esc键扫描码
        je esc_function

        jmp getstrs

    backspace:
        mov ah,1
        call charstack
        mov ah,2
        call charstack
        jmp getstrs

    input_end:
        call set_cmos_ram
        jmp esc_function

    pop ax
ret

;将代码段TIME_STRING中的ASCII码转换为BCD码值的数据
;比如字符'12'实际为31h和32h,还原为BCD码00010010,见书本14章
set_cmos_ram:
    mov bx,offset CMOS_RAM
    mov si,offset TIME_STRING
    mov di,0

    mov cx,6  	
    loop_to_write_cmos:  
        push cx

        mov dx,cs:[si]

        cmp dl,'0'
        jb	not_number     ;有效性判断
        cmp dl,'9'  
        ja  not_number	
        cmp dh,'0'
        jb 	not_number
        cmp dh,'9'
        ja  not_number  

        sub dx,3030H
        mov cl,4
        shl dl,cl
        and dh,00001111B
        or dl,dh

        mov al,cs:[bx]
        out 70H,al      	;将al送入地址端口70h

        mov al,dl
        out 71H,al      	;将数据写入CMOSRAM时钟

        inc bx
        add si,2

        pop cx
    	loop loop_to_write_cmos

    not_number:
    	jcxz set_cmos_ram_ret
    	pop cx				;如果因为字符原因退出循环,则压栈的cx没有pop处理,直接ret会异常
	set_cmos_ram_ret:
ret

;清除代码段TIME_STRING中的字符串缓存
clear_time_string:
    push bx
    push cx

    mov bx,offset TIME_STRING
    mov cx,12

    init_time_string:
        mov byte ptr cs:[bx],'*'
        inc bx
        loop init_time_string

    pop cx
    pop bx
ret
;-----------------------------------
charstack:
    jmp short charstart
    top dw 0                			;参考书本17章设置栈顶

charstart:
    push bx
    push dx
    push di
    push es

    cmp ah,0
    je charpush
    cmp ah,1
    je charpop
    cmp ah,2
    je charshow
    jmp charstack_ret

    mov si,offset TIME_STRING

    charpush:
        cmp top,11						;只记录12个字符
        ja charstack_ret

        mov bx,top
        mov cs:[si][bx],al
        inc top
        jmp charstack_ret

    charpop:
        cmp top,0
        je charstack_ret
        dec top
        mov bx,top
        mov al,cs:[si][bx]
        jmp charstack_ret

    charshow:
        mov bx,0b800h
        mov es,bx
        mov di,11*160+30*2   

        mov bx,0
        charshows:
            cmp bx,top
            jne noempty

            cmp top,11                  ;第12个字符输入后直接退出
            ja charstack_ret      

            mov byte ptr es:[di],'*'    ;字符串为空时用*代替空格显示
            jmp charstack_ret

        noempty:
            mov al,cs:[si][bx]
            mov es:[di],al
            ;mov byte ptr es:[di+2],'*'  ;输入的有效字符的下个字符用*显示,比如1*
            inc bx
            add di,2
            jmp charshows

    charstack_ret:
    pop es
    pop di
    pop dx
    pop bx
ret
;-----------------------------------
clear_screen:
    push bx
    push cx
    push es

    ;全屏清屏
    mov bx,0b800h
    mov es,bx
    mov cx,2000
    mov bx,0

    clear:
        mov byte ptr es:[bx],' '
        mov byte ptr es:[bx+1],07h  ;黑底白字
        add bx,2
        loop clear

    pop es
    pop cx
    pop bx

ret
;----------------------------------- 

;-----------------------------------
boot_end:
    nop
;=====================================
code ends
end start

未完成部分

功能四参考书本中使用了字符串进行实现,实际的使用并不人性化,也没有光标提示,UI采用了密码式的提示方式,也没有对年与日与时分秒的输入进行相关限制,建议使用者小心谨慎的调试功能四,简单说本课程设计的功能四仅实现了课设要求,能用但不好用

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章           查看所有文章
加:2021-10-14 08:12:33  更:2021-10-14 08:12:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 21:48:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码