王爽《汇编语言》第 3 版 实验 课程设计 1
warning:
这篇文章距离上次修改已过710天,其中的内容可能已经有所变动。
assume cs:codesg
stacksg segment stack
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
stacksg ends
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,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
datasg ends
dataview segment
db 16 dup (0)
db 16 dup (0)
dataview ends
table segment
db 21 dup ('????????????????'),0
table ends
codesg segment
start:
mov ax,datasg
mov ds,ax
mov ax,table
mov es,ax
mov ax,stacksg
mov ss,ax
mov sp,64
mov cx,21 ;设置循环次数为 21 次
mov bx,0 ;每个循环加 4
mov si,0 ;每个循环加 2
mov di,0 ;每个循环加 16
s1:
;1 处理年份
mov ax,ds:[bx]
mov dx,ds:[bx+2]
mov es:[di],ax
mov es:[di+2],dx
;2 处理收入
mov ax,ds:[bx+84]
mov dx,ds:[bx+86]
mov es:[di+5],ax
mov es:[di+7],dx
;3 处理雇员数量
mov ax,ds:[si+168]
mov es:[di+10],ax
;4 处理人均收入
mov ax,es:[di+5]
mov dx,es:[di+7]
div word ptr es:[di+10]
mov es:[di+13],ax
;处理 4 个 空格
mov al,' '
mov es:[di+4],al
mov es:[di+9],al
mov es:[di+12],al
mov es:[di+15],al
;循环计数器累加
add si,2
add bx,4
add di,16
loop s1
mov cx,21 ;设置循环次数为 21 次
mov bx,0 ;每个循环加 16
mov ax,table
mov es,ax
mov ax,dataview
mov ds,ax
mov dh,4
mov dl,1
s2:
mov bp,cx ;备份 cx
mov dl,1
;打印年份
mov ax,es:[bx+0]
mov ds:[0],ax
mov ax,es:[bx+2]
mov ds:[2],ax
mov byte ptr ds:[4],0h
mov cl,2
mov si,0
call show_str
;打印 收入
mov cx,dx
mov ax,es:[bx+5]
mov dx,es:[bx+7]
call fn_dtoc
mov dx,cx
add dl,16
mov si,0
mov cl,2
call show_str
;打印 雇员数量
mov cx,dx
mov ax,es:[bx+10]
mov dx,0h
call fn_dtoc
mov dx,cx
add dl,16
mov si,0
mov cl,2
call show_str
;打印 人均收入
mov cx,dx
mov ax,es:[bx+13]
mov dx,0h
call fn_dtoc
mov dx,cx
add dl,16
mov si,0
mov cl,2
call show_str
;循环计数器累加
add bx,16
inc dh
mov cx,bp ;还原 cx
loop s2
;call show_str
mov ax,4c00H
int 21H
;把给定的字符串交换位置 比如: 1234 变成 4321
;段地址放 ds 起始地址放 si 长度放 cx
fn_chang_str:
;如果字符串长度为 1 就返回
sub cx,1
jcxz label_fn_chang_str_return_now
inc cx
push ax
push dx
push bx
push bp
mov ax,cx ;这里做除法用
mov dx,cx ;这里把长度放的 bx 中后面要用
mov ch,0
mov cl,2
div cl ;这时 al=商 ah = 余数
sub dx,1
mov cl,al
mov bp,0
label_fn_chang_str_3:
mov ah,ds:[bp+si]
mov bx,dx
sub bx,bp
mov al,ds:[si+bx]
mov ds:[bp+si],al
mov ds:[si+bx],ah
inc bp
loop label_fn_chang_str_3
label_fn_chang_str_return:
pop bp
pop bx
pop dx
pop ax
label_fn_chang_str_return_now:
ret
;把一个数值变成可以显示的 ascii 码
;高位放 dx
;低位放 ax
;无返回, 结果直接写到 dataview:[0]
fn_dtoc:
push cx
push bx
push ds
push si
mov bx,dataview
mov ds,bx
mov si,0
label_fn_dtoc_j:
mov cx,10
call fn_divdw
mov bx,cx
add bx,30h
mov ds:[si],bx
add si,1
mov cx,ax
jcxz label_fn_dtoc_return
jmp short label_fn_dtoc_j
label_fn_dtoc_return:
;翻转
mov cx,si
mov byte ptr ds:[si],0
mov si,0
call fn_chang_str
pop si
pop bx
mov ds,bx
pop bx
pop cx
ret
;不会溢出的除法
; 被除数低位放 ax, 被除数高位放 dx,除数放 cx
; 结果: 高16 位放 dx,低 16 位放 ax, 余数放 cx
fn_divdw:
;备份 reg
push bp
push bx
;1 算 H/N
;备份 被除数低 16 位放到 bp 中
mov bp,ax
mov ax,dx
div cl
mov bx,ax ;这时候 bl 是 H/N 的商,bh 是 H/N 的余数
;算 [rem(h/n)*65536+L]/N
mov dh,0
mov dl,bh
mov ax,bp
div cx ; ax=商,dx=余
;把结果放到相关寄存器中
mov cx,dx
mov dh,0
mov dl,bl
pop bx
pop bp
ret
; 在指定的位置打印指定的字符串
; dh = 行号 dl= 列号 cl = 颜色 si = 要打印的字符串地址
show_str:
;1 暂存子程序用到的寄存器
push ax ;备份 ax
push bx ;备份 bx
push cx ;备份 cx
push dx ;备份 dx
push es ;备份 es
;2 设置显存地址,段地址放入 es 中
mov ax,0b800h
mov es,ax ;设置显存段地址
;3 设置指定的行和列的显示偏移地址放入 bx 中
push cx ;因为后面 loop 要用到 cx ,所以再备份一次
mov ch,0
mov cl,dh ;把参数行号放入 cx 中准备 loop
mov bx,0 ;要把实际的行偏移地址放在 bx 中,所以清理 bx 准备放数据
sub cx,1 ;cx-1 是因为要在第 8 行显示的话,地址加到第 7 行就行了
setrows:
add bx,160 ;这里加 160 是一行显示 80 个字符,每个字符占用 1 个字
loop setrows
mov ch,0
mov cl,dl
sub cx,1
setcols:
add bx,2
loop setcols
pop cx
mov dh,cl
mov ch,0
mov ax,16 ; 如果不够 20 个字符就用空格补齐
;3 读取 data 中的字符, 直到读取到 0 为止
readdata:
mov cl,ds:[si]
jcxz next_01
mov dl,cl
mov es:[bx],dx
inc si
add bx,2
sub ax,1
jmp short readdata
next_01:
mov cx,ax
mov dl,20h
addspace:
jcxz return_show_str
add bx,2
mov es:[bx], dx
sub cx,1
jmp short addspace
;返回
return_show_str:
pop es
pop dx
pop cx
pop bx
pop ax
ret
codesg ends
end start
1719309261605.png寄存器太少, 很多还指定寄存器, 要不停的备份,还原