16位汇编课程设计

来源:互联网 发布:广电网络20m宽带怎么样 编辑:程序博客网 时间:2024/04/27 07:45

                      编写一个可以自行启动的计算机,不需要在现有操作系统环境中运行的程序
-----王爽汇编语言  课程设计2
一、相关资料






二、设计思路
(1)首先思考引导程序是干什么的?
答:引导计算机找到用户代码(引导程序就是把用户代码读到相应内存中,因为软(硬)盘的第一个扇区只有512个字节,有些稍大的程序不可能一次性就能放到第一扇区里面的,更多的是放在其它扇区,然后由引导程序(第一扇区的程序)负责把其它扇区的代码读到内存中,所以我们写的引导程序任务就是利用int13中断把我们的主程序读到内存中,然后跳转并执行)
(2)怎么把程序写入软盘?
答:首先我们利用int 13把引导程序写入软盘第一扇区,然后再把主程序写入其它扇区(引导程序应该知道在哪些扇区,好读取代码)
(3)怎么完成代码编写?
答:知道我们可以先编写功能3,4,(4的改时间功能在虚拟8086模式下不能真正改时间),然后在写功能1,2,当完成一个
小任务(或函数)时就及时测试,减少后面的负担,最后在真正真机测试,修改,测试。。。成功!

三、测试环境
虚拟机+win7 32位+一个u盘+dos系统
说明:因为虚拟机里装了一个win7所以就直接用它来测试了,首先我从网上下载了一个U盘dos系统制作工具,将下载的msdos7.1写入了u盘,然后制作一个软盘镜像,可以网上下载工具进行制作,我用的是自带的软盘镜像,准备工作做好后就可以开始了(当然还有写好的程序),设置虚拟机从u盘启动,然后进入dos系统,在纯dos系统下,运行编写好的程序(exe文件),将程序写入软盘扇区,最后设置虚拟机从软盘启动,如果一切顺利,那么就会进入的写的程序的主界面,当然也许运气不好,没法一次性成功,那么就只有检查程序,有可能把软盘写“坏”了,没关系,格式化一下就好,重复以上工作就好了。
(当然也可以不用win7系统,直接在虚拟硬盘里面装dos,这样就不需要u盘了,在dos下写扇区,这样引导的也就是dos系统了而不是win7系统)

注:不能在windos系统下直接运行程序写扇区,因为此时运行在虚拟8086模式,在windos系统保护下,没法写软盘。
下图节选自Windows环境下32位汇编语言程序设计.罗云彬.第三版


我的程序运行效果如下:
(1)写软盘(从u盘启动)


(2)从软盘启动后的主界面


(3)功能3(显示时间)
(4)功能3--q功能(改变颜色)


(5)功能4(设置时间)


修改后的效果



功能4中的数据合法性检测


1号功能就是重启,再次出现主程序界面(应该太快,没有截图)
2号功能就会引导win7系统,进入win7系统

四:程序源码参考
.model small.dataerror  db 'fail'   ;写入软盘是否成功ok     db 'success'.codestart:   mov ax,cs    mov es,ax ;es:bx指向要写的数据开始位置  ;==================================把引导程序写入磁盘的程序  lea bx,boot  ;引导程序的偏移地址  mov al,1;写入的扇区数  mov ch,0;磁道号  mov cl,1;扇区号  mov dl,0;驱动器号(软驱从0开始,0:软驱A,1:软驱B,硬盘从80h开始,80h:硬盘C,81h:硬盘D)  mov dh,0;磁头号(面)  mov ah,3;int 13h的功能号,3表示写入扇区    int 13h  cmp ah,0  jne showerror     ;============================把主程序写入磁盘的程序===============    ;算出需要写入的写入的扇区数  lea bx,Main    lea ax,MainEnd  sub ax,bx  xor dx,dx  mov bx,512  div bx  add ax,1         lea bx,Main ;引导程序的偏移地址  mov ch,0;磁道号  mov cl,2;扇区号  mov dl,0;驱动器号(软驱从0开始,0:软驱A,1:软驱B,硬盘从80h开始,80h:硬盘C,81h:硬盘D)  mov dh,0;磁头号(面)  mov ah,3;int 13h的功能号,3表示写入扇区  int 13h  cmp ah,0  jne showerror  ;================写入软盘成功   mov ax,@data   mov ds,ax   mov si,offset ok   mov di,160*7+26*2   mov cx,7   call print     over:  mov ax,4c00h   int 21h;===============写入软盘失败   showerror:       mov ax,@data   mov ds,ax   mov si,offset error   mov di,160*7+26*2   mov cx,4   call print     jmp over     ;==================================引导程序===========================   org 7c00hboot:     jmp BootStart    no   db 'failure'BootStart:  xor ax,ax      mov es,ax      mov bx,7e00h          mov al,4;读入的扇区数  (前面计算所得)  mov ch,0;磁道号  mov cl,2;扇区号  mov dl,0;驱动器号  mov dh,0;磁头号(面)    mov ah,2;int 13h的功能号,2表示从扇区读进内存  int 13h  cmp ah,0  je continue  call fail  jmp $ ;无限循环  continue: jmp bx  ;================================磁盘读写失败显示===========================fail   proc  push ax          push es          push si          push bx          push cx       mov ax,0b800h      mov es,ax      xor si,si      lea bx,no      mov cx,7  ;字符串长度FailStart:      mov al,cs:[bx]  mov es:[si],al  add si,2  inc bx      loop FailStart                    pop cx      pop bx      pop si      pop es      pop ax  retfail endp  lea ax,boot          db 510-($- boot) dup(0)           dw 0aa55h ;以aa55结尾             ;=========================================主程序===========================  ORG 7e00h  Main: jmp  MainStart       ;子功能直接定址表         keyNum dw resetPC,startSys,Clock,SetClock                        ;菜单字符串 str0 db '                  System Startup Options: Made By ztgreat 2015/02/1 ',0 str1 db '                 ===================================================',0 str2 db '                       1. Restart The Computer                      ',0 str3 db '                       2. Guide The Current System                  ',0             str4 db '                       3. Into Clock Program                        ',0 str5 db '                       4. Set Time                                  ',0 str6 db 'Please input the number of the menu:                                ',0 stringtable dw offset str0,offset str1,offset str2,offset str3,offset str4,offset str5,offset str6MainStart:        call clearScreen  ;清屏             mov ax,cs             mov ds,ax                          mov cx,68            xor bx,bx            mov di,160*2 ;提示信息首句,第2行第7列起                 printf: mov si,cs:[stringtable+bx]                  call print            add bx,2            add di,160+160;换两行            cmp bx,14            jne printf                                    ;设置光标位置             mov ah,2         mov bh,0   ;页号         mov dh,13   ;行号         mov dl,116  ;列号         int 10h                     ; --------接收键盘输入 checkKey : mov ah,0            int 16h                mov bx,0b800h            mov es,bx            mov es:[14*160+36*2],al  ;显示输入结果            call delay  ;便于看到输入结果                        ;----------------数据合法性判断------------            cmp al,31h             jb checkKey             cmp al,34h             ja checkKey                                  xor bx,bx            mov bl,al            sub bl,30h ;将数字1~4的ASCII码转换为0~3             dec bl                        add bx,bx    ;bx=bx*2  换算出定址表地址             call clearScreen              call word ptr cs:keyNum[bx]   ;根据直接定址表跳转到相应功能区                          ;若调用返回则重新生成菜单                         jmp near ptr MainStart  ;从头开始                                 ;================字符串显示函数===========================;入口参数说明:;ds:si指向字符串地址;di显存偏移地址;cx字符长度print  procpush di        push cx        push ax        push es        mov ax,0b800h        mov es,ax  @@ :  mov al,[si]        mov byte ptr es:[di],al        inc si        inc di        mov byte ptr es:[di],00000010b        inc di        loop @B        pop es        pop ax        pop cx        pop di        ret         print endp                           ;=======================================重启计算机===============================           resetPC: jmp reset     p dw 0,0ffffh   reset: jmp dword ptr  p;========================================引导现有操作系统===========================startSys:         mov ax,0         mov es,ax         mov bx,7c00h                  mov al,1         mov ch,0         mov cl,1         mov dl,80h   ;硬盘C         mov dh,0         mov ah,2         int 13h         push es         push bx                  retf  ;跳转到操作系统引导程序所在内存区:0:7c00h          ;=================================循环显示时钟===========================Clock    proc         push ax           xor al,al         call setframe       C_S:     call showClock    ;显示时钟函数      in al,60h         ;读取60h端口的键盘输入      cmp al,10h         ;q键的扫描码为10h  (因为电脑原因,改为q键)     je setcolor      cmp al,01h       ;Esc键的扫描码为01h      jne C_S     pop ax     ret  setcolor:       push bx      push cx   mov ax,0b800h  mov es,ax  mov bx,160*12+30*2+1  mov cx,17   @@:inc byte ptr es:[bx]      add bx,2      loop @B      pop cx      pop bx  jmp C_S   Clock endp   ;=================================设置显示时间边框============================;al=0 时钟显示边框,否则为时钟设置时的边框setframe proc          push cx        push ds        push di        push bx        push si        push cs        pop ds                xor bx,bx        mov cx,8               mov di,160*7+26*2   ;定位边框显示位置       lea bx,frametable     ;时钟显示时的边框地址偏移       cmp al,0              je frame        lea bx,frametable2   ;时钟设置时的显示边框地址偏移        add cx,2        mov di,160*5+26*2   ;定位边框显示位置        jmp frame        framea db '   [<--]   move left     ',0         frameb db '   [-->]   move right    ',0         framec db '   [Esc]   return menu   ',0         framed db '   [Enter] set over      ',0                 frame0 db '    [q]   change color   ',0         frame1 db '    [Esc] return menu    ',0         frame2 db '                         ',0         frame3 db '=========================',0         frame4 db '==                     ==',0         frame5 db '==                     ==',0         frame6 db '==                     ==',0         frame7 db '=========================',0         frametable dw offset frame0,offset frame1,offset frame2,offset frame3,offset frame4,offset frame5,offset frame6,offset frame7         frametable2 dw offset framea,offset frameb,offset framec,offset framed,offset frame2,offset frame3,offset frame4,offset frame5,offset frame6,offset frame7      frame:push cx        mov cx,25        mov si,[bx]        call print        add bx,2        add di,160        pop cx        loop frame                                          pop si        pop bx        pop di        pop ds        pop cx        ret        setframe endp                   showClock proc       push ax       push si       push bx       push dx       push di       push cx          jmp ShowStart          ;日期时间单元号列表           cmos db 9,8,7,4,2,0      ;年,月,日,时,分,秒           signs db '/','/',' ',':',':',' '  ;分隔符 ShowStart:    xor si,si   xor di,di      mov ax,0b800h   mov es,ax       xor bx,bx       mov cx,6       show:   push cx   mov al,cmos[si]   out 70h,al   in al,71h      ;将BCD码转换为相应字符的ASCII码   mov ah,al   mov cl,4   shr ah,cl;右移4位让高4位变为第4位(得到0-9之间的数)   and al,00001111b ;获得低4位   add ah,30h ;获得各字相应的ASCII码   add al ,30h      mov byte ptr es:[160*12+30*2+bx],ah   mov byte ptr es:[160*12+30*2+bx+2],al      mov ah,signs[di]   mov byte ptr es:[160*12+30*2+bx+4],ah   add bx,6   inc di   inc si   pop cx   loop show   ShowRet:           pop cx                    pop di           pop dx           pop bx           pop si           pop ax           retshowClock endp;===================================时间设置================================      SetClock  proc near          push ax          push si          push es          push dx          push di                    mov al,1  call setframe          call showclock           jmp set       bit db 0,2,6,8,12,14,18,20,24,26,30,32    set:  mov si,0          mov ax,0b800h        mov es,ax         xor dh,dh     settime:          mov di,160*12+30*2          mov dl,bit[si]              add di,dx                           ;es:dx指向屏幕要修改的日期和时间的单元地址         mov byte ptr es:[di+1],97h          ;控制移动当前要修改的日期和时间的单元地址,背景色为蓝色闪烁         mov ah,0           int 16h                              ;读取键盘缓冲区第一个字单元中的键盘输入           cmp ah,01h                            ;Esc键的扫描码为01h           jne next          jmp clockretnext:          cmp ah,1ch                            ;enter键的扫描码为1ch          jne next_left         jmp befor_enter next_left:         cmp ah,4bh                            ;←键的扫描码为4bh         jne next_right        jmp left next_right:         cmp ah,4dh                              ;→键的扫描码为4dh         jne next_1         jmp right next_1:         cmp al,30h                           ;数字0的ASCⅡ码为30h         jb  settime        cmp al,39h                           ;数字9的ASCⅡ码为39h         ja settime next_2:         mov byte ptr es:[di],al                 ;修改当前的日期和时间的单元内容         mov al,0                              ;清空al值,防止right重复检测al         jmp right                           ;修改完成自动跳向下一个修改字单元         jmp settime clockret:pop di       pop dx       pop es       pop si       pop ax        ret    ;------------------------方向键向左移动-------------------------------- left:         cmp al,34h                          ;判断是否为数字键盘4,数字键盘ah=4bh,al=34h         jne lefts         jmp next_2 lefts:         mov byte ptr es:[di+1],02h         ;恢复当前字节的背景色         cmp si,0         je lefte         dec si         jmp settimelefte:         mov si,11                                ;移动超界跳到最右边         jmp settime;------------------------方向键向右移动-------------------------------- right:         cmp al,36h                          ;判断是否为数字键盘6,数字键盘ah=4dh,al=36h         jne rights         jmp next_2rights:                 mov byte ptr es:[di+1],02h          ;恢复当前字节的背景色         cmp si,11         je righte         inc si         jmp settimerighte:         mov si,0                                  ;移动超界跳到最左边         jmp settime befor_enter:    mov si,0    mov cx,6    mov ax,0b800h        mov es,ax        xor dh,dh        xor bx,bxenters:      push cx         mov di,160*12+30*2        mov dl,bit[si]            add di,dx         mov ah,byte ptr es:[di]                sub ah,30h                                    ;十位显示字符转化为数字         mov al,byte ptr es:[di+2]         sub al,30h                                    ;个位显示字符转化为数字         mov ch,cmos[bx]          ;ch指向CMOS RAM中要修改的单元地址        mov cl,4         shl ah,cl        add ah,al                ;ah指向CMOS RAM中要修改的单元数据                  call checktime          ;时间设置错误检测               cmp cl,1        je  setagain            ;如果数据不合法则重新输入        mov al,ch        out 70h,al                ;向地址端口70h写入要访问的单元地址         mov al,ah        out 71h,al              ;向数据端口71h写入指定单元的数据         inc bx        add si,2        pop cx        loop enters        jmp clockretsetagain:pop cx                 ;把刚刚push的cx出栈,否则没有平衡栈,将会出错 jmp set                     SetClock endp    ;------------------------范围检测函数---------------------------------- ;功能:(1) (bx)=9,代表年份,ah代表数据,不需要检测 ;     (2) (bx)=8,代表月份,ah取值范围(01-12) ;     (3) (bx)=7,代表天数,ah取值范围(01-31) ;     (4) (bx)=4,代表小时,ah取值范围(00-23) ;     (5) (bx)=2,代表分钟,ah取值范围(00-59) ;     (6) (bx)=0,代表秒钟,ah取值范围(00-59) bcd_12        equ 00010010b bcd_23        equ 00100011b bcd_31        equ 00110001b bcd_59        equ 01011001b checktime proc                 push bx         xor bh,bh         mov bl,ch         mov cl,0  ;0表示没有问题,1表示出现问题         cmp bx,8         je checkmouth   ;检测月                   cmp bx,7         je checkday     ;检测日                            cmp bx,4         je checkhour    ;检测时                            cmp bx,2         je checkminute   ;检测分                            cmp bx,0         je checksecond  ;检测秒                  jmp  checkret                checkmouth:            ;检查月份                  cmp ah,1                  jb moutherror                  cmp ah,bcd_12                  ja moutherror                  jmp checkret     checkday:                  ;检查日合法性                  cmp ah,1                  jb dayerror                  cmp ah,bcd_31                  ja dayerror                  jmp checkret     checkhour:         ;检查时合法性                  cmp ah,0                  jb hourerror                  cmp ah,bcd_23                  ja hourerror                  jmp checkret     checkminute:;检查分合法性                  cmp ah,1                  jb minerror                  cmp ah,bcd_59                  ja minerror                  jmp checkret     checksecond:                    ;检查秒合法性                  cmp ah,1                  jb secerror                  cmp ah,bcd_59                  ja secerror                  jmp checkret                         moutherror: mov bx,0     ;月份出现问题,bx对应月份错误代码号                  mov cl,1     ;标志置1        call error2  ;显示错误                  jmp checkret                                           dayerror:  mov bx,2         mov cl,1         call error2                  jmp checkret                                           hourerror: mov bx,4         mov cl,1         call error2                  jmp checkret                         minerror:  mov bx,6         mov cl,1         call error2                  jmp checkret                          secerror:  mov bx,8             mov cl,1         call error2                                       checkret: pop bx      ret           checktime endp;==========================时间错误提示==============================error2 proc    jmp errorstarterrort db 'mouth error,please change again!  ',0 errord db 'day error,please change again!    ',0 errorh db 'hour error,please change again!   ',0 errorm db 'minute error,please change again! ',0 errors db 'second error,please change again! ',0 errorkey dw offset errort,offset errord,offset errorh,offset errorm,offset errors errorstart:   push ax              push ds              push si              push cx              push di  push cs  pop ds          mov si,cs:[errorkey+bx]          mov cx,34          mov di,160*17+23*2                       call print              pop di              pop cx              pop si              pop ds              pop ax              ret    error2 endp  ;=======================================清屏函数===========================clearScreen procpush ax        push es        push di        push cx            mov ax,0b800h        mov es,ax        mov di,0        mov cx,2000 clear: mov byte ptr es:[di],' '        add di,2        loop clear            pop cx        pop di        pop es        pop ax        retclearScreen endp            ;===============================延时程序==============================        delay proc             push ax       push dx       mov dx,10h       mov ax,0   s1: sub ax,1     sbb dx,0     cmp ax,0     jne s1     cmp dx,0     jne s1     pop dx     pop ax     retdelay endp      MainEnd:nopend start


0 0