王爽-实验十
一.显示字符串
1.实验要求
2.程序代码:
;编写show_str子程序,指定位置和颜色,显示一个用0结尾的字符串
;dh显示行号,dl显示列号
;cl显示颜色
assume cs:code,ds:data,ss:stack
data segment
db 'Welcome to masm!',0
data ends
stack segment
db 16 dup(0)
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov dh,8
mov dl,3
mov cl,2
mov ax,data
mov ds,ax
mov si,0
call show_str
mov ax,4c00h
int 21h
show_str: push ax
push bx
push cx
push dx
push di
push si
mov ax,0b800h
mov es,ax
;ax现在没有使用到
mov al,dh
mov dh,160
mul dh
;现在ax存放的是结果
mov dh,0
add ax,dx
inc ax
;现在ax存放的是要存放字符的位置
mov bx,ax
mov di,0
mov al,cl
;di索引的是数据段
;si索引的是显存段
;al放属性,cx自由了
;bx为基址
;开始放字符
show: mov cl,[di]
mov ch,0
jcxz ok
mov es:[bx+si],cl
mov es:[bx+si+1],al
inc di
add si,2
jmp short show
;函数返回
ok: pop si
pop di
pop dx
pop cx
pop bx
pop ax
ret
code ends
end start
3.实验结果:
4.错误点:
没有注意到要显示字符串在显存中的放置顺序是:字符,属性,字符属性…,只将基址定位到了第8行的第四个位置,实际上第四个位置是第二个字符的属性,因此设置基址应该+1
二.解决除法溢出的问题
1.实验要求
公式:
2.分析过程
(1).首先计算int(H/N)
首先要进行除法,ax中要存放被除数,第一步要计算的是高16位的除法,所以低16位得暂存,因此有:
mov si,ax;
因为除数为16位,因此被除数需要在高16位设置为0,低16位设置为输入的高16位,即H,之后做除法,因此有:
mov ax,dx;这里低16位设置为原来的高16位,而高16位设置为0
mov dx,0
div cx;现在商在ax,余数在dx
除法结束之后,ax中存放这次除法的商,即int(H/N),dx中存放这次除法的余数,即rem(H/N),因为接下来还要进行除法运算,所以要保存ax中的值,而dx中的值下面还要用到,所以在进行第二步之前要保存ax
mov di,ax
*(2).[rem(H/N)65536+L]/N
首先是rem(H/N)*65536,这不计算实际上就是将前一步结果的余数左移16位,也即放在高16位的地方,刚好他在dx中,所以不同动他,后面加上L,也即原来输入的低16位,将他放回ax中就好,之后进行除法
mov ax,si
div cx
除法结束:现在余数在dx中,商在ax中,这里ax就是最后结果的低16位,而结果的高16位就在前面存放的di中,因为公式中是int(H/N)*65536,就是将第一步运算的商左移16位,即放在高16位中,因此只需将其放在dx中就好。
mov cx,dx
mov dx,di
3.程序代码
;实验10-2解决除法溢出的问题
assume cs:code,ss:stack
stack segment
db 16 dup(0)
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,4240h;低16位
mov dx,000fh;高16位
mov cx,0ah;除数
call divdw
mov ax,4c00h
int 21h
;子程序:解决除法溢出
;实现公式: X/N = int(H/N)*65536+[rem(H/N)*65536+L]/N
;输入:使用ax放低16位,dx放高16位
;使用cx放除数
;输入:使用ax放低16位,dx放高16位
;使用cx放余数
;
divdw: mov si,ax;暂时存放低16位
mov ax,dx;这里低16位设置为原来的高16位,而高16位设置为0
mov dx,0
div cx;现在商在ax,余数在dx
;因为要左移16位,所以商应该放在高16位中
;先暂存商
mov di,ax
;现在计算+后面的
;前面运算之后余数在dx中,也就是说rem(H/N)的结果在dx中
;dx刚好是存放高16位的地方,所以不用理
;+L就把原来输入的时候的低16位放在ax中就好了
mov ax,si
div cx
;除法结束:现在余数在dx中,商在ax中,这里ax就是最后结果的低16位
mov cx,dx
mov dx,di
ret
code ends
end start
4.实验结果
三.数值显示
1.实验要求
2.实验分析
1.做除法,将余数压入栈中,将商作为下次除法的被除数,并且将商传入cx中使得上为0时跳出
注意:
1.这一步需要在开始压0入栈中,作为结束标志
2.记得将余数加上30h转换为ASCII码
dtoc: mov bx,10;bx为除数
mov dx,0;高16位设置为0,因为除数是16位的
mov si,0;si作为后面的数据段的索引
push si;压一个0为结束符
begin: mov dx,0;高16位要清理,因为进行一次除法运算之后存放余数
div bx
mov cx,ax;使用商作为判断条件
add dx,30h;转换为ASCII码
push dx;余数压入栈中
jcxz ojbk
jmp short begin
2.弹出栈,并且将值放入data段中
ojbk: pop cx
jcxz okk
mov [si],cl
inc si
jmp short ojbk
okk: ret
3.程序代码
;数值显示:将data中的数据转换为ASCII码,
;之后调用show_str将其显示在屏幕上
assume cs:code,ds:data,ss:stack
data segment
db 10 dup(0)
data ends
stack segment
db 16 dup(0)
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,12666
mov bx,data
mov ds,bx
call dtoc
mov dh,8
mov dl,3
mov cl,2
mov si,0
call show_str
mov ax,4c00h
int 21h
show_str: push ax
push bx
push cx
push dx
push di
push si
mov ax,0b800h
mov es,ax
;ax现在没有使用到
mov al,dh
mov dh,160
mul dh
;现在ax存放的是结果
mov dh,0
add ax,dx
inc ax
;现在ax存放的是要存放字符的位置
mov bx,ax
mov di,0
mov al,cl
;di索引的是数据段
;si索引的是显存段
;al放属性,cx自由了
;bx为基址
;开始放字符
show: mov cl,[di]
mov ch,0
jcxz ok
mov es:[bx+si],cl
mov es:[bx+si+1],al
inc di
add si,2
jmp short show
;函数返回
ok: pop si
pop di
pop dx
pop cx
pop bx
pop ax
ret
;子函数转换数字为ASCII码
;ax为输入,结果放在ds段中
;不能放栈中,栈只能存放一个16位的数据
dtoc: mov bx,10;bx为除数
mov dx,0;高16位设置为0,因为除数是16位的
mov si,0;si作为后面的数据段的索引
push si;压一个0为结束符
begin: mov dx,0;高16位要清理,因为进行一次除法运算之后存放余数
div bx
mov cx,ax;使用商作为判断条件
add dx,30h;转换为ASCII码
push dx;余数压入栈中
jcxz ojbk
jmp short begin
ojbk: pop cx
jcxz okk
mov [si],cl
inc si
jmp short ojbk
okk: ret
code ends
end start