写汇编程序真不容易,调试起来更是困难。光t就不知按了多少。总算完成了。
;主程序
DATAs segment
;以下来年份数据
db '1975','1976','1977','1978','1979'
db '1980','1981','1982','1983','1984'
db '1985','1986','1987','1988','1989'
db '1990','1991','1992','1993','1994'
db '1995'
;以下为收入数据
dd 16,22,382,1356,2390
dd 8000,16000,24486,50065,97479
dd 140417,197514,345980,590827,803530
dd 1183000,1843000,2759000,3753000,4649000
dd 5937000
;以下为人员数据
dw 3,7,9,13,28
dw 38,130,220,476,778
dw 1001,1442,2258,2793,4037
dw 5635,8226,11542,14430,15257
dw 17800
DATAS ends
;结果存储段
table segment
db 21 dup(' ') ;每行27个字节,共21行
table ends
STACKS SEGMENT
;此处输入堆栈段代码
dw 16 dup (0)
STACKS ENDS
CODES segment
ASSUME CS:CODES,DS:DATAS,SS:STACKS
start:
MOV AX,DATAS
MOV DS,AX
mov ax,STACKS
mov ss,ax
mov ax,table
mov es,ax ;将存储表格置es段
;此处输入代码段代码
;计算平均数
mov si,0 ;数据段偏移
mov di,0 ;数据段偏移
mov bx,0 ;计算行数
;循环
;mov cx,2 ;测试,先用两行,便于调试
mov cx,15h ;共21行
calavg: ;
;循环
;取各种数据
mov ax,[si] ;年
mov es:[bx],ax
mov ax,[si+2]
mov es:[bx+2],ax
mov es:[bx+4],20h ;空格
;收入
mov ax,[si+54h] ;低位 //收入
mov dx,[si+54h+2h] ;高位 //收入
push ds
push si
push bx
mov bx,es
mov ds,bx
pop bx
;add bx,5 ;
mov si,bx ;收入在表格中位置
add si,5 ;收入偏移
call ddtoc ;收入转
pop si
pop ds
mov es:[bx+0ch],20h ;空格
;人数
mov ax,[di+0a8h];
;
push ds
push si
push bx
mov bx,es
mov ds,bx
pop bx
mov si,bx ;+13
add si,0dh ;人数偏移
call dtoc ;人数转
pop si
pop ds
mov es:[bx+12h],20h ;空格
;求平均值
push cx ;用
;
mov ax,[si+54h]
mov dx,[si+54h+2]
mov cx,[di+0a8h] ;除数 //人数
call divdw ;计算平均数
push ds
push si
push bx
mov bx,es
mov ds,bx
;mov si,[bx+19]
pop bx
mov si,bx
add si,13h ;平均值偏移
call ddtoc ;平均数值转换
pop si
pop ds
mov es:[bx+1ah],0 ;停止符号,注意,此处写入一个word类型的0,不符合要求,应该写入一个byte类型
pop cx ;
;计算步长
add bx,27 ;行步进
add si,4 ;年份及收入步进
add di,2 ;人数步进
loop calavg ;
;
;以下为显示部分
showcom:
;mov cx,15h ;共21行数据
push ds
push bx
push es
push dx
push si
push ax
push cx
;showOneLine:
;
; push cx
;mov ax,15h ;共21行数据
;mov ax,2h ;先调试两行
;mov cx,2h ;调试2行
mov cx,15h ;共21行数据
;
mov bx,es
mov ds,bx ;ds:指向es段地址
mov bx,0
;
mov dh,1h ;第一行
;
showOneLine:
mov ax,cx ;保存循环变量
mov cl,2h ;绿字,黑底
mov dl,1h ;第一列
mov si,bx ;指向第一个字符
call show_str ;显示
add bx,1bh ;增27字节
inc dh ;行自增
inc dh ;行自增,在显示中,dh会被减1
;dec ax ;ax自减
mov cx,ax ;判断是否退出
;pop cx
loop showOneLine ;
;
pop cx
pop ax
pop si
pop dx
pop es
pop bx
pop ds
;返回到dos
mov ax,4c00h
int 21h
;显示字串子程序
;显示字符串到指定位置
;函数名称:show_str
;函数功能:在指定位置用指定颜色显示一个用0结束的字符串
;函数参数:(dh)=行号0-24,(dl)=列号0-79,(cl)=颜色,ds:si为字串首地址
show_str:
;入栈
push es
push ax
push bx
push di
push cx
;显存地址
mov ax,0B800H
mov es,ax
mov di,0 ;行列偏移地址
;
mov ax,0a0h ;行偏量
dec dh ;行减1
mul dh ;计算行偏移
mov di,ax ;将行偏移保存在di中
;
mov ax,2h
dec dl ;列减1
mul dl ;计算列偏移
add ax,di
mov di,ax
;
mov bh,cl ;属性
;
showOne:
mov bl,ds:[si] ;取一个字母
mov cl,bl ;判断是否为0
mov ch,0
jcxz OK
;mov es:[di+ax],bx ;显示到屏幕上
mov es:[di],bx
inc si ;到下一个字母位置
add di,2 ;列移2个位置到下一列
jmp showOne ;循环
OK:
;出栈
pop cx
pop di
pop bx
pop ax
pop es
;返回
ret ;显示字串子程序show_str结束
;显示子程序结束
;
;非溢出除法
;公式:X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N
;该公式的意思表示为:高16位除以除数时,得到其商和余数,其中的余数正好是下一次16位除法时的高16位。
;16位除法DX中为被除数高位(H);AX中为被除数低位(L);其结果中AX中为商,DX中为余数;
;参数:(ax)-被除数低位 (dx)-被除数高位 (cx)-除数
;返回值:(dx)商中高位,(ax)商中低位,(cx)余数
divdw:
;保存现场
push bx
;开始第一次除法
push ax ;保存被除数中的低16位,该数据在ax中
mov ax,dx ;将被除数中的高16位放在ax中,然后将dx置0,此时(dx)(=0)+(ax)即为第一次除法的被除数
mov dx,0 ;第一次除法时的被除数,高位置0
div cx ;第一次除法时的除数
;第一次除法结束时,ax中为商,即dx中余数,此时的余数就是第二次除法中的高16位
mov bx,ax ;保存第一次除法时的商,即总结果中的高16位商
pop ax ;总被除数中低16位出场
div cx ;第二次除法
mov cx,dx ;第二次除法中的余数,即总结果中的余数
mov dx,bx ;第一次结果中保存的商中的高16位
divExit: ;子程序退出
pop bx
ret ;divdw子程序结束
;非溢出除法子程序结束
;十进制转换字符串函数
;子程序名称:dtoc
;功能:将word型数据转变为十进制了字符串,以0为结束符
;参数:(ax)=Word型数据,ds:si字符串的首地址
;返回:无(void)
dtoc:
;保存现场
;入栈
push dx
push bx
push cx
push di
push si
;
mov di,0 ;计数器置0,用来计算余数的个数
mov bx,0ah ;除数10(0aH)
mov cx,0 ;清空
;
divone: ;除0ah,取余数
mov dx,0
div bx
mov cx,dx ;此时dx中为余数
push cx ;将余数入栈
inc di ;计数器自增
mov cx,ax ;此处将商赋值给 cx,以判断是否结束转换
jcxz divover ;跳至取余结束
;不能结束
jmp divone ;跳到取余动作
;
divover: ;取余结束
mov cx,di ;将余数的数量送入cx,以循环
stackOne:
;将保存的余数出栈
pop ax
add ax,30h ;将得到的数加30(1e)
mov [si],al ;将得到的数保存到指定内存地址
inc si ;内存地址自增1
loop stackOne
;将结束符号写入
;inc si
;mov [si],0
;出栈
pop si
pop di
pop cx
pop bx
pop dx
ret ;dtoc子程序结束,返回调用
;十进制转换字符串子程序结束
;十进制转换字符串函数
;子程序名称:ddtoc
;功能:将double word型数据转变为十进制了字符串,以0为结束符
;参数:(ax)=Word型数据的低16位,(dx)double word数据高16位,ds:si字符串的首地址
;返回:无(void)
ddtoc:
;保存现场
;入栈
push dx
push bx
push cx
push di
push si
;
mov di,0 ;计数器置0,用来计算余数的个数
;
ddivone: ;除0ah,取余数
mov cx,0ah ;除数
call divdw ;用非溢出除法子程序
;返回后商的高位在dx中,低位在ax中,而余数在cx中
push cx ;将余数入栈
inc di ;计数器自增
mov cx,ax ;将商放入cx中,以判断是否结束转换
jcxz ddivover ;跳至取余结束
;得新取被除数
jmp ddivone ;跳到取余动作
;
ddivover: ;取余结束
mov cx,di ;将余数的数量送入cx,以循环
dstackOne:
;将保存的余数出栈
pop ax
add ax,30h ;将得到的数加30(1e)
mov [si],al ;将得到的数保存到指定内存地址
inc si ;内存地址自增1
loop dstackOne
;将结束符号写入
;inc si
;mov [si],0
;出栈
pop si
pop di
pop cx
pop bx
pop dx
ret ;dtoc子程序结束,返回调用
;十进制转换字符串子程序结束
CODES ends
end start
- [sbjcm33] 原来你是把实验1和2放一起的,好办法,我怎么没想到呢,把它们分成了两个程序。 具体的内容我就不看了 12/06 01:34
- [rotapple] 却没有放入段地址,而此处要明确的是:seg code 的含义是指段地址 ============= 06/23 16:56
- [Wednesday] 分析透彻,收藏!哈哈 11/09 17:26
- [Wednesday] 公布答案了,哈哈。 11/05 23:03
- [mqmelon] 不用客气,共同进步! 11/02 10:03
- [feemess] 谢谢指点.我的下一次答题要在32个小时之后了.一直都认为第一题没错.看来.要认真看书才是 10/28 00:08
- [mqmelon] 谢谢,我会努力去做. 10/27 23:18
- [游客] mqmelon同学,你能有这样的认识首先说明你的学习态度是对的,只要有正确的学习态度,就能够学好,以 10/25 11:56
- [sunshine] 呵呵 10/25 09:49
- [mqmelon] 谢谢,十分谢谢。 10/24 17:10