王爽老师版汇编语言课程设计2

一、虚拟环境架设
    1、安装虚拟机VM6.03(vmware)
    2、创建虚拟机,客户机操作系统 类型“其它”MS-DOS,用光盘镜像安装DOS622。
       下载地址 http://205.196.120.225/1ycwwydjjw1g/00007135820/filefront/dos6.22.iso.rar
    3、使用 WinImage 工具,创建一张1.44M的软盘IMG文件,并加载到虚拟机的软驱中,做为实验软盘。

二、编写代码及测试
    注意环节
    1、代码长度与磁盘扇区要相匹配,代码如果长度超过了512K,磁盘上就要用2个扇区来存放。
    2、7C00H内存空间的问题,由于程序功能2,需要读入C盘1扇区,重写7C00H,所以我们的主程序一定要避开7C00H的使用,在其中只放入引导程序,将主程序写入其它的内存空间,并设置CS:IP到主程序处。
    3、由于需要多次安装程序,一次为将代码写入磁盘(安装主程序到磁盘),一次为从磁盘将程序读入内存(从磁盘引导系统),因此如需要在程序中使用直接定址表,则一定要手工指定具体地址(编译器编译时只根据CODE段来计算数据标号,但安装在磁盘上的程序并不是从CODE初始位置开始的,因此需要手工计算他的位置),或者尽量不使用它,以免引起不必要的麻烦(DOS下的调试真的是太麻烦了,出错也不容易查出)。
    4、注意栈平衡,注意CALL中使用到的寄存器数据的PUSH和POP,CALL中重写了数据使用程序出错,不易查出。
    5、最重要的就是多看教材,实验中所用到的内容都在书中(废话HEHE)。王老师的教材逻辑性很强,是站在学习者角度出发循序渐进编写的(非常佩服),因此要比其它的教材容易入手。我是先看了一遍,只做课中检测点,意在了解书的大致内容,第二遍看书认真把检测点做过的题再分析下,查出了不少错误(有些错误在看了后边章节内容后会有更多的理解),并认真将书中所出现代码一一在虚拟机中调试实验,由其要做好每一个实验程序(其实每个实验王老师都把思路写的非常清晰了,我们需要的只是具体实施)。这些实验全做完后,我觉得我的汇编是入了门了,谢谢王老师。
三、具体代码,简单做了注释(请多指正)
assume  cs:code,ss:stack,ds:datas

stack segment
        db 128 dup(0)
stack ends

datas segment
        mess1 db 'Disk I/O Error!!!!'
        mess2 db 'Disk Write OK !!!!'
datas ends
        
code segment
        
start:    
;==============================安装引导程序==============================

        mov ax,stack
        mov ss,ax
        mov sp,128

        push cs
        pop ds

        push cs
        pop es

        
        ;往 A: 0面0道1扇处写入程序,共4个扇区7C00=主引导区  7E00=主程序区1 8000=主程序区2 8200=数据区
        mov bx,offset RUN
        mov ah,3
        mov al,4
        mov ch,0
        mov cl,1
        mov dh,0
        mov dl,0

        int 13h
        
        ;对写盘操作后反馈的信息进行处理
        push ax                                ;清屏
        mov ax,datas
        mov ds,ax
        mov si,0

        mov ax,0b800h
        mov es,ax
        mov di,0
        mov cx,2000
  stas: mov byte ptr es:[di],0
        add di,2
        loop stas

        pop ax
        cmp ah,0                        ;比较int 13h返回情况,提示是否写盘成功
        je stend


        mov di,160*12+30*2
        mov cx,18
  stars:mov al,byte ptr mess1[si]
        mov byte ptr es:[di],al
        inc si
        add di,2
        loop stars
        jmp staend
  stend:
        mov di,160*12+30*2
        mov cx,18
  starss:mov al,byte ptr mess2[si]
        mov byte ptr es:[di],al
        inc si
        add di,2
        loop starss
        
  staend:                                ;主程序安装磁盘完成后设置 CS:IP 到 FFFF:0000,重启计算机
        mov ax,0ffffh
        mov bx,0
        push ax
        push bx
        retf

        mov ax,4c00h
        int 21h

;============================磁盘中写入的内容==============================
;============================0面0道1扇区 7C00H =============================
RUN:    mov ax,0                ;将主程序1区2区 及数据区读入内存
        mov es,ax
        mov bx,7e00h
        mov ah,2
        mov al,3
        mov ch,0
        mov cl,2
        mov dh,0
        mov dl,0
        int 13h

        mov ax,0                ;CS
        mov bx,7e00h            ;IP
        push ax
        push bx
        retf

        db 510-($-RUN) dup(0)                ;这两句将代码 引导部分 长度扩充为 512 字节,直接占满 0面0道1扇区
        dw 0aa55h
;以上共计512字节,最后以 AA55封闭1扇区   
;============================0面0道2--3扇区,自助系统位置 7E00H  8000H=============================
MENU:   call clear
        mov ax,0b800h
        mov es,ax
        mov di,160*3+20*2

        mov ax,cs
        mov ds,ax
        
        mov bx,0
        mov cx,10
  men2: push cx
        push di

        mov si,0
        mov cx,39
  men1: mov al,byte ptr ds:[8200h+bx+si]        ;显示 处于8200H处的主菜单
        mov byte ptr es:[di],al
        add di,2
        inc si
        loop men1
        pop di
        pop cx
        add di,160
        add bx,39
        loop men2
        
        

GOGO:   call input                                ;功能选择部分,利用 16H 中断,读取键盘缓冲区,根据字符确定 功能

        mov ah,0
        int 16h

        cmp al,'1'
        je GO1
        cmp al,'2'
        je GO2
        cmp al,'3'
        je GO3
        cmp al,'4'
        je gog4                                        ;这里JE 的转移是不能直接转移到GO4的,因为长度超过范围了,因此做了个 gog4:jmp GO4

        jmp GOGO
   gog4:jmp GO4

GO1:    mov ax,0ffffh                                ;这里使用ret的 pop ip  pop cs 功能改变 CS:IP指向需要位置
        mov bx,0
        push ax                                        
        push bx
        retf

GO2:    call clear                
        mov ax,0
        mov es,ax
        mov bx,7c00h

        mov ah,2                                ;这里将读取C盘1扇区内容到7C00H,如果主程序在这个位置,则全部被改写,不能正确运行,因此我们应该把主程序放在第1扇区之后.
        mov al,1
        mov ch,0
        mov cl,1
        mov dh,0
        mov dl,80h

        int 13h

        mov ah,2                ;置光标在 25行 8列  (一直没有解决好光标随字符串移动,有兴趣者可继续研究下)
        mov bh,0
        mov bl,0
        mov dh,0
        mov dl,0
        int 10h

        mov ax,0
        mov bx,7c00h
        push ax
        push bx
        retf

GO3:
        mov ax,0b800h                                ;从15行起划个框框美化一下
        mov es,ax
        mov bx,39
        mov di,160*15+20*2
        mov cx,2
 go3s4: push cx
        push di
        mov si,0
        mov cx,39
 go3s2: mov al,byte ptr ds:[8200h+bx+si]        
        mov byte ptr es:[di],al
        add di,2
        inc si
        loop go3s2
        pop di
        add di,320
        pop cx
        loop go3s4

        

        mov bx,83C2H                                ;BX为 读取COMS的地址 直接定址表,一定要手工指向目标内存
        mov di,160*16+31*2
        
        mov cx,6
 go3s1: push cx
        mov al,byte ptr ds:[bx]                ;读取COMS中的时间日期,使用 70H 端口
        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 es:[di],ah
        add di,2
        mov byte ptr es:[di],al
        add di,2
        pop cx
        cmp cx,4
        ja go31

        cmp cx,1
        je go33

        cmp cx,4
        jb go32

   go33:mov byte ptr es:[di],0                        ;写入美化字符
        jmp goend

   go31:mov byte ptr es:[di],'/'
        jmp goend

   go32:mov byte ptr es:[di],':'
        jmp goend

  goend:add di,2
        inc bx
        loop go3s1

        in al,60h
        
        cmp al,03Bh              ;F1改变颜色,这里直接用60H端口读取键扫描码,根据扫描码处理无需改写 INT 9中断即可达到目的,但按次数多了,会报警键盘缓冲区满 
        jne go3esc
        push ax
        mov di,160*16+1
        mov cx,80
 go3col:mov al,byte ptr es:[di]
        inc al
        and al,00001111B
        mov byte ptr es:[di],al
        add di,2
        loop go3col                        
        pop ax
                       
 go3esc:cmp al,81h                ;ESC跳出时间日期显示  AX 由上边 60H 端中获取
        jne gogo3

        jmp MENU
  
  gogo3:mov ax,0
        jmp GO3


GO4:                            
        mov di,160*23                        ;输入格式提示字符  'INPUT: YY/MM/DD HH:MM:SS'
        mov si,838Dh
        mov cx,24
  go4s:        mov al,byte ptr ds:[si]
        mov byte ptr es:[di],al        
        inc si
        add di,2
        loop go4s


        mov bp,0                        ;BP 内存变量,存着字符串的长度 所有寄存器都有用了,只有它闲着 这里使用书上代码,定址表会出错,手动指定变量和目标位置即可
        mov si,83E0H                        ;DS:SI 指向字符串存放的内存位置
        call GETSTR                        ;GETSTR 一定要与上面两句配合使用,上边给了他 参数
        jmp MENU


clear:  push es                        ;清屏命令
        mov ax,0b800h
        mov es,ax
        mov di,0
        mov cx,2000
   cles:mov byte ptr es:[di] ,0
        mov byte ptr es:[di+1],00000111B
        add di,2
        loop cles

        pop es
        ret



input:        push es                        ;用于设置菜单界面的输入提示及光标位置
        push cx
        push ax
        mov ax,0b800h
        mov es,ax
        mov di,160*24
        
        mov si,8386h
        mov cx,7
  inps:        mov al,byte ptr ds:[si]
        mov byte ptr es:[di],al        
        inc si
        add di,2
        loop inps

        mov ah,2                ;置光标在 25行 8列
        mov bh,0
        mov bl,0
        mov dh,24
        mov dl,7
        int 10h

        pop ax
        pop cx
        pop es
        ret

CHARSK:        push bx                                ;字符串处理 注意定址表的使用方式
        push dx
        push di
        push es
        

        cmp ah,3
        ja cret


        mov bl,ah
        mov bh,0
        add bx,bx

        jmp word ptr ds:[83C8H+bx]        ;跳到功能 0 1 2 3功能入口 0=入栈 1=出栈 2=显示 3=清除
        ;mov bp,83E0H

  pushc:mov bx,bp                      ;TOP 中存着当前 栈的指针位置  功能0
        mov [si][bx],al
        inc bp
        jmp cret

  popc: cmp bp,0                       ;TOP =0 则说明栈空了             功能1
        je cret
        dec bp
        mov bx,bp
        mov al,[si][bx]        
        jmp cret
 
 charsh:;mov bx,0b800h                        ;功能2
        ;mov es,bx
        
        mov al,160
        mov ah,0
        mul dh
        add dl,dl
        mov dh,0
        add ax,dx
        mov di,ax                        ;DI=AH*160+AL+AL 就是文字显示的位置 

        mov bx,0
  chars:cmp bx,bp
        jne noemp
        mov byte ptr es:[di],20h        ;如果 栈为空,则显示一个空格
        jmp cret

  noemp:mov al,[si][bx]
        mov es:[di],al
        mov byte ptr es:[di+2],20h        ;显示当前字符后自动将光标输入位置后移一个字符,这个字符用空格表示
        inc bx
        add di,2
        jmp chars

 charcl:;mov bx,0b800h                        ;功能3
        ;mov es,bx
        mov al,160
        mov ah,0
        mul dh
        add dl,dl
        mov dh,0
        add ax,dx
        mov di,ax

        mov cx,80
  chcls:mov byte ptr es:[di],0
        mov byte ptr es:[di+1],00000111B
        add di,2
        loop chcls

        
  cret: 
        pop es
        pop di
        pop dx
        pop bx
        ret

GETSTR:        push ax

 getstrs:mov ah,0
        int 16h
        cmp al,20h                        ;小于20H说明不是字符
        jb nocahr
        mov ah,0
        call CHARSK                        ;入栈
        mov ah,2                        
        mov dh,24
        mov dl,7
        call CHARSK                        ;显示字符在 第25行 第8列
        jmp getstrs

 nocahr:cmp ah,0eh                        ;BACKSPACE键
        je back
        cmp ah,1ch                        ;ENTER
        je enter
        

        jmp getstrs

 back:        mov ah,1
        call CHARSK
        mov ah,2                        
        mov dh,24
        mov dl,7
        call CHARSK
        jmp getstrs

  enter:mov ah,0
        mov al,0                        ;输入回车,在字符串尾压入一个0
        call CHARSK
        call writes                        ;写COMS
        
        mov ah,3                            ;3功能为清屏             
        mov dh,24
        mov dl,7
        call CHARSK        

  gnret:pop ax
        ret        
        
writes:        push si
        push di
        mov di,83C2H 
        mov si,83E0H
        mov ax,bp                          ;把输入的参数写到CMOS中 
        mov cl,3                        ;'YY/MM/DD HH:MM:SS',0 输入字符串+回车补0,共计18位,每3位为一组做为处理,BP为长度18 / 3,为处理6次
        div cl 
        mov cl,al 
        mov ch,0 
        jcxz wriend                        ;如果输入字符串长度低于3,则直接跳走

           
 write: push cx 
        mov al,[si] 
        sub al,30h 
        mov cl,4 
        shl al,cl 
        mov ah,[si+1] 
        sub ah,30h 
        add ah,al                         ;处理SI与SI+1,存放在一个字节内 AH中 写入CMOS
            
        mov al,[di]                         ;DI为CMOS内存地址 定址表
        out 70h,al 
        mov al,ah 
        out 71h,al 
            
        add si,3 
        inc di 
        pop cx 
        loop write 

 wriend:pop di
        pop si
        ret 


        db 1024-($-MENU) dup(0)                ;这句将代码 引导部分 长度扩充为 1024 字节,直接占满 0面0道2-3扇区,为准确定位 4扇区的DATA部分奠定基础
 
;以上共计1024字节 
;============================0面0道2扇区,自助系统数据位置8200H=============================
;8200H 为菜单显示区
mnu1    db '********** MASA for GengLei **********',0
mnu2    db '**************************************',0
mnu3    db '*****                            *****',0
mnu4    db '*****      1 -> Reset PC         *****',0
mnu5    db '*****      2 -> Start System     *****',0
mnu6    db '*****      3 -> Clock            *****',0
mnu7    db '*****      4 -> Set clock        *****',0
mnu8    db '*****                            *****',0
mnu9    db '**************************************',0
mnu0    db '**************************************',0
;标志 8386H
baozi        db 'GENG:\>'
mesg        db 'INPUT: YY/MM/DD HH:MM:SS'
;83C1H 前封闭为显示数据区  8200H+450 
data    db 450-($-mnu1) dup(0)
;8200H+450 共计 6 字节 存放 年 月 日 时 分 秒  83C2H
days        db 9,8,7,4,2,0
;83C8H 起为功能入口
char    dw offset pushc-offset MENU+7E00H,offset popc-offset MENU+7E00H,offset charsh-offset MENU+7E00H,offset charcl-offset MENU+7E00H
        db 480-($-char) dup(0)
;83E0H 起为字符
top        db 0

code ends
end start
   

 

个性签名:一个人在年轻的时候浪费自己的才华与天赋是一件非常可惜的事情

     如果觉得这篇文章对你有小小的帮助的话,记得在右下角“点赞”~“评论”  “收藏”哦,博主在此感谢!

 

万水千山总是情,打赏5毛买辣条行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!

©️2020 CSDN 皮肤主题: 点我我会动 设计师:上身试试 返回首页