在辅导学长的带领下,三个一工程的第一大阶段已经结束,对于这段时间所学的汇编知识做一个总结,我将几个难点实验和综合研究写成博客既是总结,也方便学习汇编语言的你们拿去参考。
课程设计一:
1.分析:
1)在实验七中,已经实现了将这些数据写入到了table段内存中;现在我们要的就是将table段内存读取出来后,有的数据不是字符串,需要将数字转换成字符串形式;写入显存。直接将实验七的程序改造成一个子程序,在主程序中直接调用。
2)table段数据的读取并写入一个临时的内存存储段—data段:对于字符串(例如:年份),我们直接写入目标内存,并加入0标记;对于其他的数值,我们调用实验10中的dtoc子程序,转换成字符串后写入目标内存段。此时在data段中存储的都是字符串形式的,并且以0为结尾。此处,得用新的32位转换子程序ddtoc。在ddtoc子程序中,会用到除法,而由于对应 “收入”的数据,采用的是dd类型,在dtoc子程序中,除法指令div运算的结果ax已经放不下,调用divdw子程序来实现。
3)程序的大体框架是:将实验七的程序作为一个子程序—to_table;主程序调用to_table子程序将表格数据写入内存,然后再将表格型数据从内存中取出放入data段,读取的数值需调用ddtoc将数字转换成字符串,转换时又会调用divdw子程序,读取的字符串就直接放入,最后调用show_str来显示字符串。
2.程序:
assume cs:code
data1 segment
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995'
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 45980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
data1 ends
table segment
db 21 dup ('year summ ne ?? ')
table ends
data segment
db 10 dup (0)
data ends
code segment
start:
mov ax,data1
mov ds,ax
mov ax,table
mov es,ax
call to_table ;调用子程序
call cls ;清屏子程序
mov ax, table
mov es, ax
mov bx, 0
mov ax, data
mov ds, ax
mov si, 0
mov cx, 21
mov dh, 1 ;show_str的入口参数。
show_info:
push cx
;显示年份
mov ax, es:[bx]
mov ds:[si], ax
mov ax, es:[bx+2]
mov ds:[si+2], ax
mov byte ptr ds:[si+4], 0 ;以0作为字符串结尾。
mov dl, 3 ;设置入口参数:所在行的列数,从第几列开始显示
mov ch, 0 ;ch清零,防止高8位不为零。
mov cl, 2
call show_str
;显示总收入
push dx ;后面要使用dx变量,先保存dx
mov ax, es:[bx+5] ;将总收入的低16位送入ax
mov dx, es:[bx+7] ;将总收入的高16位送入dx,ddtoc的入口参数
call ddtoc
pop dx ;恢复寄存器dx,此时dh也就恢复了。
mov dl, 14 ;所在行的列数
mov ch, 0 ;ch清零,防止高8位不为零。
mov cl, 2
call show_str
;显示公司总人数
push dx
mov ax, es:[bx+10]
mov dx, 0
call ddtoc
pop dx
mov dl, 34 ;所在行的列数
mov ch, 0 ;ch清零,防止高8位不为零。
mov cl, 2
call show_str
;显示人均收入
push dx
mov ax, es:[bx+13]
mov dx, 0
call ddtoc
pop dx
mov dl, 50 ;所在行的列数
mov ch, 0 ;ch清零,防止高8位不为零。
mov cl, 2
call show_str
add bx, 10H ;bx指向下一行。(table中16字节是一行)
mov si, 0
add dh, 1 ;累加dh(下一行显示)
pop cx ;弹栈到cx,计数器自动减1.
loop show_info ;循环,直到cx=0
mov ax, 4c00H
int 21H
to_table:
;保护寄存器变量
push ax
push ds
push es
push bx
push si
push di
push cx
mov bx,0
mov si,0
mov di,0
mov cx,21 ;初始化计数器
s66:
;写入年份
mov ax,0[bx]
mov es:0[si],ax
mov ax,2[bx]
mov es:2[si],ax
;写入空格
mov al,20H
mov es:4[si],al
;写入收入
mov ax,84[bx]
mov es:5[si],ax
mov ax,86[bx]
mov es:7[si],ax
;写入空格
mov al,20H
mov es:9[si],al
;雇员数
mov ax,168[di]
mov es:10[si],ax
;写入空格
mov al,20H
mov es:12[si],al
;除法后写入人均收入
mov ax,[bx+84]
mov dx,[bx+86]
;没有办法,用个bp变量吧
mov bp,[di+168]
div bp
mov es:13[si],ax
;写入空格
mov al,20H
mov es:15[si],al
;bx、si、di变量的递增
add bx,4
add si,16
add di,2
loop s66
;恢复寄存器变量,并返回主调程序
pop cx
pop di
pop si
pop bx
pop es
pop ds
pop ax
ret
ddtoc:
push ax
push cx
push bx
push si
push bp
push dx
mov si, 0
change: mov cx, 10 ;设置除数cx=10
mov bx, 0 ;divdw中导致bx变化,故清零
mov bp, 0 ;余数bp=0
call divdw ;将(dx+ax)/cx求余数bp
push ax ;将ax和dx压栈保护
push dx
add ax, dx ;(dx)+(ax)整个的商的值
mov cx, ax ;将商赋值给cx,判断整个的商是否为0?
pop dx ;将ax和dx弹栈恢复
pop ax
jcxz last
add bp, 30H
push bp
inc si
jmp short change
last: ;最后一次也要转换并压栈
add bp, 30H
push bp
inc si
;将栈中数据倒序写入内存data段中
mov cx, si
mov si, 0
write: pop ds:[si]
inc si
loop write
mov byte ptr ds:[si], 0 ;以0作为字符串结尾。
;恢复寄存器,并返回主调程序。
pop dx
pop bp
pop si
pop bx
pop cx
pop ax
ret
divdw:
push ax ;将被除数低16位先压栈保存。
mov ax, dx ;(ax)=(dx)
mov dx, 0000H ;
div cx ;被除数dx+ax(组合),除数cx。
mov bx, ax ;将H/N结果的商先保存在bx中,(bx)=0001H
pop ax ;将L值弹栈到ax
div cx
mov bp, dx ;返回值(cx)等于最终结果的余数
mov dx, bx ;最终结果高16位值=(bx)
ret
cls: push cx
push di
push si
mov ax, 0b800H
mov es, ax
mov cx, 80*24 ;设置循环次数,屏幕是24行80列
mov di, 0
scr_cls: mov byte ptr es:[di+0], ' ' ;第一个字节写入空格,
mov byte ptr es:[di+1], 0 ;第二个字节写入字符属性0(代表黑色无底)
inc di
inc di
loop scr_cls
;恢复寄存器
pop si
pop di
pop cx
ret
show_str: push dx
push cx
push si
push bx
push es
mov ax, 0b800H
mov es, ax ;设置显示缓冲区内存段
mov ax, 0 ;(ax)= 0,防止高位不为零
mov al, 160 ;0a0H- 160字节/行
mul dh ;相对于0b800:0000第dh行偏移量
mov bx, ax ;将第(dh)行的偏移地址送入bx,bx代表行偏移
mov ax, 0
mov al, 2 ;列的标准偏移量是2个字节
mul dl ;同一行列的偏移量,尽量使用乘法,(al)=列偏移
add bx, ax ;最终获得偏移地址(bx)=506H
mov di,0
mov al, cl
mov ch, 0
show: mov cl, ds:[si]
jcxz ok
mov es:[bx+di+0], cl
mov es:[bx+di+1], al
add di, 2
inc si
jmp short show
ok:
pop es
pop bx
pop si
pop cx
pop dx
ret
code ends
end start
3.运行结果:

实验分析结束,如果大家进行到这个阶段的话,想必DosBox和masm已经安装,后续课程设计2所需要的Windows xp镜像和综合研究阶段会使用的tc2.0我已经上传网盘,免费分享给大家,关注我的公众号,菜单栏–>技术相关–>免费资源即可领取,还有网课查答案,包括学习通、智慧树、mooc,内容涵盖计算机、政治等等,还有其他资源(简历模板、电子版书籍和考试资料等等),说不准大家会有用(分享干货)!

本文总结了汇编语言课程设计第一阶段的学习成果,详细介绍了如何将数据转换为字符串并显示,涉及子程序调用、数据类型转换及屏幕输出等关键技术。

2419

被折叠的 条评论
为什么被折叠?



