将实验 7 改进 输出成如下图
assume cs:codesg,es:tablesg,ss:stacksg
data segment
datasg segment
db '1975','1976','1977','1978','1979','1980','1981','1982','1983','1984','1985'
db '1986','1987','1988','1989','1990','1991','1992','1993','1994','1995'
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514,345980,590827
dd 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
datasg ends
tablesg segment
db 21 dup ('year summ ne ?? ')
tablesg ends
datax segment
dw 21 dup (0)
datax ends
stacksg segment
dw 0,0,0,0,0,0,0,0
stacksg ends
codesg segment
start:
mov ax,datasg
mov ds,ax
mov ax,stacksg
mov ss,ax
mov sp,10h
mov ax,tablesg
mov es,ax
mov di,0
mov bx,0
mov cx,21
s0:
mov ax,4
mul di
push di;保存到 寄存器 后面再恢复
mov di,ax ; 由于年份 每次加四个字节 所以 公式是 di*4
push dword ptr [di+0] ;数据段 + 字段 定位 压入 4个字节
pop dword ptr es:[si+0] ; 弹出4个字节附加寄存器指向要写入的table si指向第几条 数据 0指向第几个字段开始处
pop di ;将di恢复
mov ax,4 ;同上
mul di
push di
mov di,ax
push dword ptr [di+84] ;总共21年每个字段占 4个字节 21 * 4 = 84 所以收入其实地址 就是 84 di用来控制第条收入
pop dword ptr es:[si+5]
pop di
mov ax,2
mul di
push di
mov di,ax
push [di+168]
pop es:[si+10]
pop di
mov dx,es:[si].7 ;dx高位 存放让在内存高地址
mov ax,es:[si].5 ;低位存放在低地址
mov bx,es:[si].10 ;除数 上面2个是被除数
div bx ;对 dx,ax做除法
mov es:[si+13],ax ; ax存放商 dx存放余数 取出余数写入 es表段的第si条数据的第 13个字节处
inc di
add si,16 ;每家16就是 下一条数据开始地址
loop s0
mov cx,21
mov dh,2;行数
mov dl,0;初始列数
mov si,0
s1:
push cx
mov ax,tablesg
mov ds,ax
mov dl,4;每次加4列
mov cx,4;循环输出4个字节
push dx
mov ax,2;显示模式
mov di,ax
call show_str
pop dx
add dl,8;列数加7
push dx
add si,1
mov dx,[si+2]
mov ax,[si]
mov bx,datax;改变段寄存区
mov ds,bx
mov si,0;初始化si---------
call dtoc
mov ax,2;显示模式
mov di,ax
pop dx
add dl,8;列数加8
push dx
mov cx,0;循环输出4个字节
call show_str
mov si,ds:[20h];得到si
add si,10
mov ax,tablesg
mov ds,ax;改变成table段
mov dx,0;参数1
mov ax,[si];参数2
mov bx,datax;改变段寄存区
mov ds,bx
mov si,0;初始化si---------
call dtoc
mov ax,3;显示模式
mov di,ax
pop dx
add dl,8;列数加8
push dx
mov cx,0;循环输出4个字节
call show_str
mov si,ds:[20h];得到si
add si,13
mov ax,tablesg
mov ds,ax;改变成table段
mov dx,0;参数1
mov ax,[si];参数2
mov bx,datax;改变段寄存区
mov ds,bx
mov si,0;初始化si---------
call dtoc
mov ax,4;显示模式
mov di,ax
pop dx
add dl,8;列数加8
push dx
mov cx,0;循环输出4个字节
call show_str
pop dx;恢复
inc dh
pop cx
mov ax,ds:[20h]
add ax,16
mov ds:[20h], ax
mov si,ax
sub cx,1
jcxz end
jmp s1
end:
mov ax,4c00h
int 21h
dtoc:
mov cx,10
call divdw
add cx,030h;转ASCII码
push cx
inc si
mov bx,0
mov cx,ax;判断 余数是否为0 则除尽
add cx,dx
jcxz ok
jmp short dtoc;失败跳转循环
ok:
pop ax
mov byte ptr [bx],al
inc bx
sub si,1
mov cx,si
jcxz rtu
jmp short ok
rtu:
ret
divdw:
push ax
mov ax,dx
mov dx,0
div cx;H/N
mov bx,ax;保存商 作为最后 32位的前16位
pop ax;//L 此时 余数在dx 相当于 dx:rem(H/M) ax:L 乘以 65536相当于 进位>一个寄存器 所以rem(H/M)在 dx高位寄存器中
div cx ;对 dx ax /N
mov cx,dx ;将余数 赋值给cx
mov dx,bx;将
ret
show_str:
mov ax,0b800h
mov es,ax;指向显卡缓存开始
mov al,0a0h ;第一行 160字节
mul dh;结果放在ax
mov dh,0
add dl,dl;一列占2个字节
add ax,dl;计算行列偏移
mov bx,ax;写入的显卡缓存起始偏移
mov ax,di
jcxz prtz;cx为 0 使用自动截止
jmp prtf
prtf:
mov ah,[si];取出字节
mov byte ptr [si],0;清理
mov es:[bx + 0],ah;显示内容
mov es:[bx + 1],al;显示模式
add bx,2;写入显卡缓存偏移+2
inc si;取出数据地址偏移+1
loop prtf
ret
prtz:
mov ch,0
mov cl,[si]
inc cl
mov ah,[si];取出字节
mov byte ptr [si],0;清理
mov es:[bx + 0],ah;显示内容
mov es:[bx + 1],al;显示模式
add bx,2;写入显卡缓存偏移+2
inc si;取出数据地址偏移+1
loop prtz
ret
codesg ends
end start
可以看到 能实现对第七章内容的输出了,这个实验用到了第十章 和第七章的代码。