课程设计1
题目要求
实验7
实验10
当然在做了课程设计1后 实验10中只有“数值显示”是比较成功的
分析
将数据存储在table中
('year summ nn ave ')
table格式(‘88484’)数字代表字节数 共32字节
大致步骤如下
1.传入字符
2.传入收入
人数为数据 需要转换为字符dtoc
dtoc过程中需要用到divdw但不是所有数据都需要
由于之前的经验不足 这次直接重写两个函数
divdw改为div_plus使之能够判断被除数是否需要进行32位除法
dtoc直接包含div_plus 并且参数更加明确 能够被直接调用
3.传入人数
4.计算人均收入传入
5.将数据以十进制显示在屏幕上show_str
那么重点问题就在第二步上 这里先给出代码
要注意子程序传入的参数若不是空闲寄存器需要入栈保存数值
dotc
功能
将dword或word数据转换为字符
参数
ax 高16位
dx 低16位
ds:[si] 空闲内存
返回si地址 便于后续的调用
dtoc:
psi:
push si
re:
mov cx,0ah
push bx
call div_plus ;执行完后cx为余数 ax低位 dx高位
pop bx
add cx,30h
mov ds:[si],cl
inc si
mov cx,ax ;判断最后一位
jcxz finsh
jmp short re
finsh:
mov cx,si
pop si
sub cx,si
mov dx,si
s1:
mov al,ds:[si] ;栈一次传一个字节
push ax
inc si
loop s1
mov cx,si
sub cx,dx
mov si,dx
s2:
pop ds:[si]
inc si
loop s2
mov si,dx
ret
div_plus
功能
判断被除数以进行32或16位除法 被除数位16位时返回dx为0
参数
ax 低16位
dx 高16位
cx 除数
返回
ax 低16位
dx 高16位
cx 余数
div_plus:
push ax
push cx
mov cx,dx
jcxz divd
pop cx
mov ax,dx
mov dx,0
div cx
mov bx,ax ;商高位
pop ax
div cx
mov cx,dx ;输出结果
mov dx,bx
div_ends:
ret
divd:
pop cx
pop ax
div cx
mov cx,dx
mov dx,0
jmp short div_ends
程序代码
assume cs:codesg,ds:datasg,es:table,ss:stack
datasg 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 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000
dw 3, 7, 9, 13, 28, 38, 130, 220, 475, 778, 1001, 1442, 2258, 2793, 4037, 5635, 8226
dw 11542, 14430, 15257, 17800
dw 16 dup(0)
datasg ends
table segment
db 21 dup('year summ nn ave ')
table ends
stack segment
dw 16 dup(0)
stack ends
codesg segment
start:
mov ax,datasg
mov ds,ax
mov ax,table
mov es,ax
mov ax,stack
mov ss,ax
mov sp,32
mov bx,0
mov cx,21
mov dx,0
mov si,0
call s21
mov ax,es
mov ds,ax
mov dh,3 ;行
mov dl,0
mov cl,7h
mov ch,0
call show_list
mov ax,4c00h
int 21h
s21:
push cx ;!!!!!!!!!!!!!!
mov cx,4
mov di,0
s21_4_1:
mov al,ds:[si]
mov es:[bx+di],al
inc si
inc di
loop s21_4_1
call salary
mov cx,2
to_char: ;传入总收入和人数
push si ;!!!!!!!!!!!!!!
jcxz avg
mov si,0e0h ;空闲内存
push cx ;!!!!!!!!!!!!!!
call clean
call dtoc
mov cx,4
s21_4_2:
mov ax,ds:[si]
mov es:[bx+di+4],ax
add si,2
add di,2
loop s21_4_2
pop cx ;line 68
pop si ;line 53
push cx
call half
mov cx,si
mov si,ax
mov ax,ds:[si+0a6h]
mov si,cx
pop cx
mov dx,0h
add di,4
dec cx
jmp short to_char
avg: ;di 1c si 15
call half
mov cx,ax ;人数在ds占两个字节
call salary
mov si,cx
div word ptr ds:[si+0a6h]
mov dx,0
mov si,0e0h
call clean
call dtoc
mov ax,ds:[si]
mov es:[bx+di],ax
mov ax,ds:[si+2]
mov es:[bx+di+2],ax
pop si ;!!!!!!!!!!!!!!
pop cx ;line 39
add bx,20h
loop s21
ret
salary: ;求收入
mov ax,ds:[si+50h] ;第一次结束为4
mov dx,ds:[si+52h]
ret
show_list:
mov ax,cx
mov cx,21
mov bx,0
SL_21:
push cx
mov cx,31 ;20h个数据是32 最后一个为0
mov si,0
SL_21_31:
push cx
mov cl,ds:[bx+si]
jcxz space
continue:
inc si
pop cx ;3数据循环
loop SL_21_31
mov cl,al
inc dh
mov si,bx
push ax
push bx
call show_str
pop bx
pop ax
add bx,20h
pop cx ;行循环cx
loop SL_21
ret
space: ;空数据替换空格
push ax
mov ax,20h
mov ds:[bx+si],al
pop ax
jmp short continue
dtoc:
psi:
push si
re:
mov cx,0ah
push bx
call div_plus ;执行完后cx为余数 ax低位 dx高位
pop bx
add cx,30h
mov ds:[si],cl
inc si
mov cx,ax ;判断最后一位
jcxz finsh
jmp short re
finsh:
mov cx,si
pop si
sub cx,si
mov dx,si
s1:
mov al,ds:[si] ;栈一次传一个字节
push ax
inc si
loop s1
mov cx,si
sub cx,dx
mov si,dx
s2:
pop ds:[si]
inc si
loop s2
mov si,dx
ret
div_plus:
push ax
push cx
mov cx,dx
jcxz divd
pop cx
mov ax,dx
mov dx,0
div cx
mov bx,ax ;商高位
pop ax
div cx
mov cx,dx ;输出结果
mov dx,bx
div_ends:
ret
divd:
pop cx
pop ax
div cx
mov cx,dx
mov dx,0
jmp short div_ends
show_str:
mov ax,0b800h
mov es,ax
mov bh,dh
mov bl,dl
mov ax,0a0h
mul bh
push si
mov si,ax ;行
mov ax,2
mul bl
mov di,ax ;列
add si,di
mov bx,si
pop si
mov di,0
s:
push cx
mov cl,ds:[si]
jcxz ok
mov al,ds:[si] ;字符及属性
pop cx
mov ah,cl
mov es:[bx+di],ax
inc si
add di,2
jmp short s
ok:
pop cx
ret
clean: ;使用ax si 8个字节取0 清空内存
push ax
push cx
push si
mov cx,8
s_c:
mov ax,0
mov ds:[si],ax
inc si
loop s_c
pop si
pop cx
pop ax
ret
half: ;除2
mov ax,si
mov dx,0
mov cx,2
div cx
ret
codesg ends
end start
结果
问题
作为第一个综合性程序,水平不足 着实被难倒了。基本上一个小时写完10倍的时间debug。
1.主程序里call之前不要push 因为最后用到需要的某个值其实是执行call后push的ip
2.push pop对应着,写代码的时候就应该直接成对写出来 不然写着写着就混掉
3.在跳转里面的栈操作要注意执行了几次
4.调用子程序或者编写子程序时,对于在子程序中需要用到的reg应该提前push 调用完后即时pop,非常简单且必要的事情
5.代码长度超过jmp shotr最大字节256,解决这个问题可以用push ip 然后jmp far的操作,但是也可以把某一段改为子程序 然后调用,half salary clean子程序都是由s_21调用以减少内存
6.承接4 在写show_list的时候调用show_str忘记了虽然它不需要传入bx这个参数,但是用到了bx。也就是除了注意4外还有考虑该程序中某个寄存器是否和子程序中需要用到的寄存器冲突
7.在转换收入 人数时用一段空闲内存暂时存储 收入为16 两个字节 而人数为3 一个字节,后面传数据就不可避免的把6也当作人数传了过去,所以在调用空闲内存的时候需要确保其中没有其他数据干扰(子程序 clean) 就是初始化 当然各寄存器的初始化也不能忘