汇编语言期末编程题(王爽书实验十)

第一题

编程,显示字符串
名称:show_str
功能:在指定的位置,用指定的颜色,显示一个用 0 结束的字符串。
参数:(dh)=行号(取值范围 0~24),(dl)=列号(取值范围 0~79)
(cl)=颜色,ds:si 指向字符串的首地址
返回:无
应用举例:在屏幕的 8 行 3 列,用绿色显示 data 段中的字符串。

首先要明白两个点:

  1. 显存的物理地址是B8000~BFFFF,一般用es:di来存储,di偏移地址存储在屏幕上的位置,如:8行3列应该这样存:[di] == 8 * 160 + 3 *2
  2. 显示字符的属性(颜色)用8位二进制来表示,具体如下:
[di+1] ==  L R G B I R G B 
    	 高亮 	  闪烁

下面来看思路:

assume cs:code
data segment
             db 'This is my assembly thing 612348',0
data ends
code segment
        start:   
                 设置题干里的参数
                 ds和data关联
                 调用show_str
        show_str:
                 保护数据(push)
                 处理显存的逻辑地址:先b800h放入es
                 处理显存的偏移地址:放入di
                 这里需要释放cx用于循环判定
                 mov  dl,cl
        s:       
                 将ch置0,cl读出data数据,然后用jcxz判定,这样只要读到了最后的0就能退出程序了
                 将数据写到显存中
                 inc si
                 add di,2
                 jmp short s
        exit:    释放保护数据(pop)
                 ret
code ends
end start

具体代码如下

assume cs:code
data segment
             db 'This is my assembly thing 612348',0
data ends
code segment
        start:   
                 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 si

                 mov  ax,0b800h
                 mov  es,ax

                 mov  ah,dh
                 mov  dh,160
                 mul  dh
                 mov  bx,0
                 mov  bl,dl
                 add  ax,bx
                 add  ax,bx
                 mov  di,ax

                 mov  dl,cl

        s:       
                 mov  ch,0
                 mov  cl,[si]
                 jcxz exit
                 mov byte ptr es:[di],cl
                 mov byte ptr es:[di+1],dl
                 inc si
                 add di,2
                 jmp short s

        exit:    pop  si
                 pop  dx
                 pop  cx
                 pop  bx
                 pop  ax
                 ret

code ends
end start

第二题

编程,解决除法溢出的问题
名称:divdw
功能:进行不会产生溢出的除法运算,被除数为 dword 型,除数为 word 型,结果为 dword
型。
参数:(ax)=dword 型数据的低 16 位
 (dx)=dword 型数据的高 16 位
 (cx)=除数
返回:(dx)=结果的高 16 位,(ax)=结果的低 16 位
(cx)=余数
应用举例:计算 1000000/10(F4240H/0AH)
提示
给出一个公式:
X:被除数,范围:[0, FFFFFFFF]
N:除数,范围:[0, FFFF]
H:X 高 16 位,范围:[0, FFFF]
L:X 低 16 位,范围:[0, FFFF]
int():描述性运算符,取商,比如,int(38/10) =3
rem():描述性运算符,取余数,比如,rem(38/10)= 8
公式:X/N = int(H/N) * 65536 +[rem(H/N) * 65536 + L] / N
这个公式将可能产生溢出的除法运算:X/N,转变为多个不会产生溢出的除法运算。公式中,
等号右边的所有除法运算都可以用 div 指令来做,肯定不会导致除法溢出。

首先要明白的几个点:

  1. 本题是16位除数(cx),所以被除数就是32位,其中dx是高位,ax是低位;在进行div cx后,ax存的是商,dx存的是余数,具体的div指令见王爽书169页
  2. 题干中的公式不必深究,否则很容易绕晕,我们用十进制除法来类比,比如做97 / 2
    想想我们列竖式是怎么做的:先商一个4,用9 - 2 * 4得到高位的余数 1,然后将低位的7移下来,注意这个移下来,在程序里面我们需要将高位的余数 1放到高位寄存器dx,低位寄存器ax此时是7,然后做17 / 2,然后商8,17 - 2 * 8得到最终余数 1

思路:(建议先把下面的代码实现复制到记事本,然后一步一步跟着思路来理解)

start中做的事情:
		定义被除数、除数、商:
						dx				ax		 /  	 cx
					   000fh		   4240h	/	     0ah
		做完这些之后就调用了divdw
		
divdw中做的事情:
		三个push用来保护数据,这其实算是一个好的变成习惯,在子程序中修改了哪些参数,在一开始先放到栈中保护起来
		接着把被除数、除数、商复制一份
						dx				ax		  /  	 cx
						si				di		 /  	 bx
					   000fh		   4240h	/	     0ah
		然后进入do标号(do标号实际上没任何作用,只是区分一下上面的步骤):
				mov  ax,dx
              	mov  dx,0
              	上面这两句把原始数据的高位放入ax进行div运算,意在得到高位的余数
              	而由于做的是32位除法运算,所以dx不设0的话会干扰运算
              	div  cx
              	div运算后就得到了高位的余数,并且自动存在dx中
              	在上面的第2点中的“移下来”这个说法中解释了,在程序中就是把高位的余数放到dx中
              	而程序自动帮我们做了这件事,所以直接进入下一步
              	mov  ax,di	;把我们提前复制的一份数据拿出来用
                div  cx		;“dx ax / cx”
                这一步得到了真正的余数,存在dx中;得到了低位的商,存在ax中
                这是我们要的数据所以把他们放到栈中保护起来
		至此低位已经搞定,下面来搞高位:
				mov  ax,si
              	mov  dx,0			;同样防止dx影响运算
              	div  cx				;这一步得到了高位的商,存在ax中
		我们需要将最终的结果高位保存在dx中,低位保存在ax中
				所以:
				mov  dx,ax
              	pop  ax
结束

具体代码如下

assume cs:code 
code segment
        start:
              mov  ax,4240h
              mov  ds,000fh
              mov  cx,0ah
              call divdw

              mov  ax,4c00h
              int  21h

        divdw:
              push bx
              push si
              push di

              mov  si,dx
              mov  di,ax
              mov  bx,cx

          do: mov  ax,dx
              mov  dx,0
              div  cx
              mov  ax,di
              div  cx

              push ax
              push dx

              mov  ax,si
              mov  dx,0
              div  cx
              mov  dx,ax
              pop  cx
              pop  ax

              pop  di
              pop  si
              pop  bx
              ret
code ends
end start

第三题

数值显示
名称:dtoc
功能:将 word 型数变为表示十进制数的字符串,字符串以 0 为结尾符
参数:(ax)=word 型数据,ds:si 指向字符串的首地址
返回:无
应用举例:编程,将数据 12666 以十进制的形式在屏幕的 8 行 3 列,用绿色显示出来。在显
示我们调用本次实验的第一个子程序 show_str。
assume cs:code,ds:data
data segment
           db 10 dup (0)
data ends
code segment
      start:   
               mov  ax,12666
               mov  bx,data
               mov  ds,bx
               mov  si,0
               call dtoc
               mov  dh,8
               mov  dl,3
               mov  cl,2
               call show_str
               mov  ax,4c00h
               int  21h

      dtoc:    
               push ax
               push cx
               push dx
               push si

            s1:      
               mov  cx,ax
               jcxz exit
               mov  cx,10
               mov  dx,0
               call divdw
               add  cl,30h
               push cx                         ;每次把ax的末位数字压入栈
               inc  si
               jump short s1
            ok:      
               mov  cx,si
               mov  si,0                       ;data0号开始存
            s2:      
               pop  dx
               mov  [si],dl
               inc  si
               loop s2

               pop  si
               pop  dx
               pop  cx
               pop  ax

               ret
      divdw:   
               push bx
               push si
               push di

               mov  si,dx
               mov  di,ax
               mov  bx,cx

               mov  ax,dx
               mov  dx,0
               div  cx
               mov  ax,di
               div  cx

               push ax
               push dx

               mov  ax,si
               mov  dx,0
               div  cx
               mov  dx,ax
               pop  cx
               pop  ax

               pop  di
               pop  si
               pop  bx
               ret

      show_str:
               push ax
               push bx
               push cx
               push dx
               push si

               mov  ax,0b800h
               mov  es,ax

               mov  ah,dh
               mov  dh,160
               mul  dh
               mov  bx,0
               mov  bl,dl
               add  ax,bx
               add  ax,bx
               mov  di,ax

               mov  dl,cl

            s:       
               mov  ch,0
               mov  cl,[si]
               jcxz exit
               mov  byte ptr es:[di],cl
               mov  byte ptr es:[di+1],dl
               inc  si
               add  di,2
               jmp  short s

            exit:    
               pop  si
               pop  dx
               pop  cx
               pop  bx
               pop  ax
               ret

code ends
end start
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值