汇编语言-王爽-课程设计2——并使用Bochs实现演示效果

使用工具:

1、DOSBox 0.74,用于编译程序,测试程序主要功能

2、Bochs 2.6.9,用于模拟加载软盘,使用软盘或者硬盘启动系统

3、Linux虚拟机,用于虚拟软化读写,实现和bochs中的dos虚拟机进行数据交互

演示结果:

程序1效果:

程序2效果:

程序4效果:

程序3效果:

操作流程:

1、DOSBox编译程序生成kcsj2.exe

2、可以使用Bochs中的虚拟盘创建工具bximage.exe创建虚拟软盘a.img

3、Bochs中设置dos系统虚拟软盘(freedos.img)为A软盘挂载,同时挂载B软盘(a.img),系统虚拟软盘A为引导盘

# freedos.bxrc
###############################################################
# Configuration file for Bochs
###############################################################

# how much memory the emulated machine will have
megs: 32

# filename of ROM images
romimage: file=$BXSHARE/BIOS-bochs-latest
vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest

# what disk images will be used
floppya: 1_44=freedos.img, status=inserted
floppyb: 1_44=a.img, status=inserted

# hard disk
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
# !! Remember to change these if the hd img is changed:
#    1. include/sys/config.h::MINOR_BOOT
#    2. boot/include/load.inc::ROOT_BASE
#    3. Makefile::HD
#    4. commands/Makefile::HD
# ata0-master: type=disk, path="c.img", mode=flat, cylinders=162, heads=16, spt=63

# choose the boot disk.
# boot: floppy
boot: a

# where do we send log messages?
# log: bochsout.txt

# disable the mouse
mouse: enabled=0

# enable key mapping, using US layout as default.
keyboard: keymap=$BXSHARE/keymaps/x11-pc-us.map

# set up IPS value and clock sync
# cpu: ips=1000000

4、在freedos中格式化B软盘

5、使用Linux将生成的kcsj2.exe拷贝到B软盘(a.img)

sudo mount -o loop a.img /mnt/floppy
sudo cp kcsj2.exe /mnt/floppy -v
sudo ls -l /mnt/floppy
sudo umount /mnt/floppy

6、在freedos系统中运行kcsj2.exe程序,程序会将引导程序写入到B软盘

7、修改freedos的启动文件freedos.bxrc,设置a.img为A软盘,freedos.img为B软盘,可启动后使用kcsj2.exe中的引导程序启动

; [xyz]*:$
assume cs:code

data segment
	db 64 dup (0)
data ends

code segment
start:
	;jmp setup
	mov ax, data
	mov ss, ax
	mov sp, 64

	mov ax, cs
	mov es, ax
	mov bx, offset setup

	mov dx, 0
	mov ax, offset setupend - offset setup
	mov cx, 512
	div cx	
	cmp dx, 0
	je setpre
	inc ax

setpre:
	mov si, offset disknum
	mov es:[si], ax	
	mov ah, 1
	mov al, 1	; 写b
	mov dx, 0
	mov cx, ax

lwdisk:
	call rwdisk
	inc dx
	add bx, 512
	loop lwdisk

	mov ax, 4c00h
	int 21h

org 7c00h
setup:
	jmp near ptr setup_start
	nop

; bochs虚拟机需要识别软盘的文件系统格式才能启动系统,所以将写入软盘
; 第一个扇区引导程序模拟为FAT12的文件系统格式

; FAT12 磁盘的头
; ----------------------------------------------------------------------
BS_OEMName	DB 'HuxBoot!'	; OEM String, 必须 8 个字节

BPB_BytsPerSec	DW 512		; 每扇区字节数
BPB_SecPerClus	DB 1		; 每簇多少扇区
BPB_RsvdSecCnt	DW 1		; Boot 记录占用多少扇区
BPB_NumFATs	DB 2		; 共有多少 FAT 表
BPB_RootEntCnt	DW 224		; 根目录文件数最大值
BPB_TotSec16	DW 2880		; 逻辑扇区总数
BPB_Media	DB 0f0h		; 媒体描述符
BPB_FATSz16	DW 9		; 每FAT扇区数
BPB_SecPerTrk	DW 18		; 每磁道扇区数
BPB_NumHeads	DW 2		; 磁头数(面数)
BPB_HiddSec	DD 0		; 隐藏扇区数
BPB_TotSec32	DD 0		; 如果 wTotalSectorCount 是 0 由这个值记录扇区数

BS_DrvNum	DB 0		; 中断 13 的驱动器号
BS_Reserved1	DB 0		; 未使用
BS_BootSig	DB 29h		; 扩展引导标记 (29h)
BS_VolID	DD 0		; 卷序列号
BS_VolLab	DB 'HuxBootSect'; 卷标, 必须 11 个字节
BS_FileSysType	DB 'FAT12   '	; 文件系统类型, 必须 8个字节  
;------------------------------------------------------------------------

disknum		dw 0
stacktop:	dw 64 dup (0)
stackend:	

setup_start:
	mov ax, offset stacktop
	mov ss, ax
	mov sp, offset stackend - offset stacktop
	mov ax, cs
	mov ds, ax
	
	cmp disknum, 1
	jb initscreen

	; 加载大于512的数据
	mov ax, 7c0h
	mov es, ax
	mov bx, 512
	mov ah, 0
	mov al, 0	; 读a
	mov dx, 1
	mov cx, disknum
	sub cx, 1
loaddisk:
	call rwdisk
	inc dx
	add bx, 512
	loop loaddisk

initscreen:
	call choice_option

	mov ax, 4c00h
	int 21h


; =================================================================
; 读写磁盘;
; Para: (ah)=寄存器传递功能号,0表示读,1表示写;
;	(dx)=寄存器传递要读写的扇区的逻辑扇区号;
;	(al)=驱动器号 0:软驱A,1:软驱B,80h:硬盘C,81h:硬盘D
;	es:bx指向存储读出的数据或写入数据的内存区;
rwdisk:
	push ax
	push bx
	push cx
	push dx
	push si
	push di

	cmp ah, 1
	ja rwdiskret

	push bx
	mov bl, al	;驱动器号
	mov bh, ah	;读写标志	
	
	mov cx, 1440
	mov ax, dx
	mov dx, 0
	div cx
	mov di, dx
	mov dx, 0
	mov dh, al ;面号

	mov cx, 0
	mov cl, 18
	mov ax, di
	div cl
	mov cl, ah
	mov ch, al ;磁道号

	add cl, 1 ;扇区号
	
	mov dl, bl	;驱动器号
	mov al, 1	;读取扇区数
	mov ah, 2	;2表示读扇区,3表示写扇区
	add ah, bh	

	pop bx
	int 13h
rwdiskret:
	pop di
	pop si
	pop dx
	pop cx
	pop bx
	pop ax
	ret


;----------------------------------------------------------------------------
sectorend:
db 510 - (offset sectorend - offset setup) dup (0)
dw 	0aa55h				; 结束标志

; =================================================================
message:
s0	db 'Select options!', 0
s1	db '1) reset pc', 0
s2	db '2) start system', 0
s3	db '3) clock', 0
s4	db '4) set clock', 0
s5	db 'Input choice q or 1~4:', 0
s6	db 'Set clock format yy/mm/dd hh:mm:ss', 0
s7	db 'Input Esc back, F1 change color!', 0
cmoss1	db '/', '/', ' ', ':', ':', 0
cmoss2	db 9, 8, 7, 4, 2, 0
srow	dw s0, s1, s2, s3, s4, s5, s6, s7
func	dw fun1, fun2, fun3, fun4
dsdata	db 64 dup (0)

; =================================================================
show_screen:
	push ax
	push bx
	push cx
	push dx

	; 清屏
	call cls

	mov dh, 4
	mov dl, 30
	mov cx, 5
	mov bx, 0
lshowms:
	call show_message
	inc dh
	inc bx
	loop lshowms

	mov si, offset s5
	mov dh, 9
	mov dl, 0
	mov ch, offset s6 - offset s5 - 1
	call choice_option

	pop si
	pop ds
	pop dx
	pop cx
	pop bx
	pop ax
	ret

; =================================================================
; 选择子程序
choice_option:
	push ax
	push bx
	push cx
	push dx

choice:
	; 清屏
	call cls

	mov dh, 4
	mov dl, 30
	mov cx, 5
	mov bx, 0
lcshowms:
	call show_message
	inc dh
	inc bx
	loop lcshowms

	mov dl, 0
	call show_message

	add dl, offset s6 - offset s5 - 1
	call setcursor

lreadkey:
	; 读取键盘
	mov ah, 0
	int 16h
	
	; 比较判断
	cmp al, 'q'
	je choiceret
	cmp al, '4'
	ja lreadkey
	cmp al, '1'
	jb lreadkey

	; 显示输入
	mov bl, 3
	mov cl, 1
	call showbyte

	; 调用子函数
	mov bx, 0
	mov bl, al
	sub bl, '1'
	add bx, bx
	call word ptr func[bx]
	jmp short choice

choiceret:
	pop dx
	pop cx
	pop bx
	pop ax
	ret


; =================================================================
; 输出选项信息
; Para: (dh)=光标起始行,(dl)=光标起始列
;		(bx)=第几条消息
show_message:
	push ax
	push bx
	push cx
	push ds
	push si

	mov ax, cs
	mov ds, ax
	add bx, bx
	mov si, srow[bx]

	mov cl, 2	
	call show_str

	pop si
	pop ds
	pop cx
	pop bx
	pop ax
	ret

; =================================================================
fun1:
	add sp, 2
	mov ax, 0ffffh
	push ax
	mov ax, 0
	push ax
	retf

fun2:
	;call start_old_system

	mov bx, 0
	mov es, bx
	mov bx, 7c00h
;
;	mov ah, 0
;	mov al, 1h	;读b
;	mov dx, 0
;	call rwdisk 

	mov al,1
	mov ch,0
	mov cl,1
	mov dl,1h     ;0h代表a盘,80h代表C盘
	mov dh,0
	mov ah,2
	int 13h

	add sp, 2
	mov bx, 0
	push bx
	mov bx, 7c00h
	push bx
	retf

fun3:
	push ax
	push bx
	push cx
	push dx
	push ds
	push es
	push si
	push di

	; 设置int9
	mov ax, cs
	mov ds, ax
	mov ax, 0
	mov es, ax

	mov si, offset int9
	mov di, 206h
	mov cx, offset int9end - offset int9
	cld
	rep movsb

	push es:[9*4]
	pop es:[200h]
	push es:[9*4+2]
	pop es:[202h]

	mov word ptr es:[204h], 0

	cli
	mov word ptr es:[9*4], 206h
	mov word ptr es:[9*4+2], 0
	sti
	
	call cls
	mov dh, 7
	mov dl, 25
	mov bx, 7
	call show_message

	; 读取cmos时间
	mov cx, cs
	mov ds, cx
	mov si, offset dsdata
	
	mov dh, 8
	mov dl, 30
	mov cl, 2
lfun3s:
	call readcmos	
	call show_str
	mov bx, es:[204h]
	cmp bx, 0
	je lfun3s
	mov word ptr es:[204h], 0
	cmp bl, 01h	; 判断是否是ESC
	je fun3ret
	cmp bl, 3bh	; 判断是否是F1
	jne lfun3s
	inc cl
	jmp lfun3s
	
fun3ret:
	call clear_buff
	; 恢复int9
	cli
	push es:[200h]
	pop es:[9*4]
	push es:[202h]
	pop es:[9*4+2]
	sti
	pop di
	pop si
	pop es
	pop ds
	pop dx
	pop cx
	pop bx
	pop ax
	ret

fun4:
	push ax
	push cx
	push dx
	push ds
	push si

	call cls
	mov dh, 8
	mov dl, 20
	mov bx, 6
	call show_message

	mov dh, 9
	mov dl, 30
	call setcursor
	call getstr

	call writecmos

	pop si
	pop ds
	pop dx
	pop cx
	pop ax
	ret


start_old_system:
    mov bx,0
	mov es,bx
	mov bx,7c00h

	mov al,1
	mov ch,0
	mov cl,1
	mov dl,1h     ;0h代表a盘,80h代表C盘
	mov dh,0
	mov ah,2
	int 13h

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


clear_buff:
	mov ah, 1
	int 16h
	jz clearbuffret
	mov ah, 0
	int 16h
	jmp clear_buff
clearbuffret:
	ret

; 中断9
int9:
	push ax

	in al, 60h
	mov cs:[204h], ax

	pushf
	call dword ptr cs:[200h]	

int9ret:
	pop ax
	iret

int9end: nop
   

; 设置当前页的光标位置;
; Para: (dh)=行,(dl)=列
setcursor:
	push ax
	push bx
	mov ah, 2
	mov bh, 0
	int 10h
	pop bx
	pop ax
	ret

; 在光标位置显示字符;
; Para: (al)=字符,(bl)=颜色属性,(cx)=字符重复个数
showbyte:
	push ax
	push bx
	mov ah, 9
	mov bh, 0
	int 10h
	pop bx
	pop ax
	ret

; 在光标位置显示字符串;
; Para: ds:si指向字符串,需要用"$"作为结束符
showstr:
	push ax
	push dx
	mov dx, si
	mov ah, 9
	int 21h
	pop dx
	pop ax
	ret

; 清屏
cls:
	push ax
	push bx
	push cx
	push es

	mov ax, 0b800h
	mov es, ax
	mov bx, 0	
	mov ah, ' '
	;mov al, 0
	mov cx, 2000
lcls:
	mov byte ptr es:[bx], ah
	add bx, 2
	loop lcls

	pop es
	pop cx
	pop bx
	pop ax
	ret

; Info: 在指定的位置,用指定的颜色,显示一个字符
; Para: (dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),
;		(cl)=颜色
;		(al)=字符
; Ret: 无
show_byte:
	push ax
	push bx
	push cx
	push dx
	push es
	
	mov ch, cl
	mov cl, al

	mov ax, 0b800h
	mov es, ax
	mov bl, 0a0h
	mov al, dh
	mul bl
	mov dh, 0
	add dl, dl
	add ax, dx
	mov bx, ax

	mov word ptr es:[bx], cx

	pop es
	pop dx
	pop cx
	pop bx
	pop ax
	ret

; Info: 在指定的位置,用指定的颜色,显示一个用0结束的字符串
; Para: (dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),
;		(cl)=颜色,ds:si指向字符串的首地址
; Ret: 无
show_str:
	push ax
	push bx
	push cx
	push dx
	push es
	push si
	
	mov ax, 0b800h
	mov es, ax
	mov bl, 0a0h
	mov al, dh
	mul bl
	mov bh, 0
	mov bl, dl
	add bl, bl
	add ax, bx
	mov bx, ax
	mov al, cl

show_str_change:
	mov ch, 0
	mov cl, [si]
	jcxz show_str_ok
	mov ch, al
	mov word ptr es:[bx], cx
	add bx, 2
	inc si
	jmp short show_str_change
show_str_ok:
	pop si
	pop es
	pop dx
	pop cx
	pop bx
	pop ax
	ret


;读取CMOS时间;
;Para: ds:si指向读取数据内存
readcmos:
	push ax
	push bx
	push cx
	push si

	mov bx, 0
	mov cx, 6
lcmos:
	push cx

	mov al, cmoss2[bx]
	out 70h, al
	in al, 71h

	mov ah, al
	mov cl, 4
	shr al, cl
	and ah, 00001111b

	add al, 30h
	add ah, 30h
	
	mov [si], ax
	add si, 2
	mov al, cmoss1[bx]
	mov [si], al
	inc bx
	inc si
	pop cx
	loop lcmos
	
	;mov byte ptr [si], 0

	pop si
	pop cx
	pop bx
	pop ax
	ret

;写入CMOS时间;
;Para: ds:si指向写入数据内存
writecmos:
	push ax
	push bx
	push cx
	push si

	mov bx, 0
	mov cx, 6
wlcmos:
	push cx

	mov ax, [si]
	sub al, 30h
	sub ah, 30h
	mov cl, 4
	shl al, cl
	and ah, 00001111b
	or ah, al	

	mov al, cmoss2[bx]
	out 70h, al

	mov al, ah
	out 71h, al

	inc bx
	add si, 3
	pop cx
	loop wlcmos

	pop si
	pop cx
	pop bx
	pop ax
	ret

; 字符栈的入栈、出栈和显示
; Para: (ah)=功能号,0表示入栈,1表示出栈,2表示显示,3当前数据长度;
;		ds:si指向字符栈空间
;		0号功能:(al)=入栈字符;
;		1号功能:(al)=返回的字符;
;		2号功能:(cl)=字符颜色属性,(dh)、(dl)=字符串在屏幕上显示的行、列位置;
;		3号功能:(al)=返回的长度;
charstack:
	jmp short charstart
chartable	dw charpush, charpop, charshow, charlen
chartop		dw 0
charstart:
	push bx
	push dx
	push di
	push es

	cmp ah, 3
	ja sret
	mov bl, ah
	mov bh, 0
	add bx, bx
	jmp word ptr chartable[bx]

charpush:
	mov bx, chartop
	mov [si][bx], al
	inc chartop
	jmp sret

charpop:
	cmp chartop, 0
	je sret
	dec chartop
	mov bx, chartop
	mov al, [si][bx]
	jmp sret

charshow:
	mov bx, 0b800h
	mov es, bx
	mov al, 160
	mov ah, 0
	mul dh
	mov di, ax
	add dl, dl
	add al, dl
	mov dh, 0
	add di, dx

	mov bx, 0

charshows:
	cmp bx, chartop
	jne noempty
	mov byte ptr es:[di], ' '
	jmp sret
noempty:
	mov al, [si][bx]
	mov es:[di], al
	mov es:[di+1], cl
	mov byte ptr es:[di+2], ' '
	inc bx
	add di, 2
	jmp charshows

charlen:
	mov bx, chartop
	mov al, bl
	jmp sret
sret:
	pop es
	pop di
	pop dx
	pop bx
	ret

; 获取字符并显示
; Para: ds:si指向字符栈空间
;		(dh)、(dl)=字符串在屏幕上显示的行、列位置;
getstr:
	push ax
	push cx
	push dx
	mov cl, 4
getstrs:
	mov ah, 0
	int 16h
	cmp al, 20h
	jb nochar
	mov ah, 0
	call charstack
	mov ah, 2
	call charstack
	mov ah, 3
	call charstack
	add dl, al
	call setcursor
	sub dl, al
	jmp getstrs
nochar:
	cmp ah, 0eh	;退格键扫描码
	je getbackspace
	cmp ah, 1ch	;Enter键扫描码
	je getenter
	jmp getstrs
getbackspace:
	mov ah, 1
	call charstack
	mov ah, 2
	call charstack
	mov ah, 3
	call charstack
	add dl, al
	call setcursor
	sub dl, al
	jmp getstrs
getenter:
	mov al, 0
	mov ah, 0
	call charstack
	mov ah, 2
	call charstack
	pop dx
	pop cx
	pop ax
	ret

setupend: nop

code ends
end start
;end setup


注:

在实现子程序2时使用rwdisk子程序加载软驱数据,发现无法正常跳转到freedos操作系统,后只能使用中断程序加载扇区可正常跳转到dos系统。原因未知。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值