[Hb-IX] 编写子程序(显示字符串、数值,除法溢出问题)

来源:互联网 发布:同性题材网络剧泰国 编辑:程序博客网 时间:2024/05/14 18:53

《汇编语言·第三版》--王爽


1 显示字符串

(1) 问题

显示字符串是现实工作中经常要用到的功能,应该编写一个通用的子程序来实现这个功能。我们应该提供灵活的调用接口,使调用者可以决定显示的位置(行,列)、内容和颜色。


(2) 子程序描述

名称:show_str

功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串

参数:(dh) = 行号(取值范围 0 ~ 24),(dl) = 列号(取值范围0 ~ 79),(cl) = 颜色,ds:si指向字符串的首地址。

返回:无

应用举例:在屏幕的8行3列,用绿色显示data段中的字符串。

1.       assume  cs:code

2.        

3.       data       segment

4.              db   'welcome to masm!', 0

5.       data       ends

6.        

7.       code      segment

8.       start:      mov       dh,8

9.              mov       dl,3

10.          mov       cl,2

11.          mov       ax,data

12.          mov       ds,ax

13.          mov       si,0

14.         

15.          call show_str

16.         

17.          mov       ax,4c00h

18.          int   21h

19.   show_str:

20.                   ….

21.   code      ends

22.   end start


(3) 代码

1.       ;功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串

2.       ;参数:(dh) = 行号(取值范围 0 ~ 24),(dl) = 列号(取值范围0 ~ 79),(cl) = 颜色,ds:si指向字符串的首地址。

3.       ;返回:无

4.       show_str:    mov ax, 0b800h

5.                     mov es, ax           ;显存首段地址

6.                     mov       al, cl             ;保存颜色参数

7.                    

8.                     mov       bp, 0

9.                     mov       ch, 0

10.                 mov       cl, dh

11.   s0:          add bp, 160         ;行号对应的显存地址

12.                 loop       s0

13.                

14.                

15.                 mov       di, 0

16.                 mov       ch, 0

17.                 mov       cl, dl

18.   s1:          add di,2              ;列号对应的显存地址

19.                 loop       s1

20.                

21.                

22.   s2:          mov       cl,ds:[si]

23.                 jcxz s3           ;检测当前字符是否为0,如果为0则转移到s3处执行

24.                 mov      es:[bp + di],cl

25.                 inc  di

26.                 mov      es:[bp +di], al     ;字符前景色

27.                 inc  di

28.                 inc  si

29.                 loop       s2

30.  s3:          ret

(4) 运行结果

Figure1. 绿色welcome to masm!

将程序中的坐标,字符串,颜色的参数更换,如dh = 12, dl = 10, cl = 4,从新编译、运行程序得以下结果:


Figure2.更换参数显示不同颜色的字符串于不同的坐标上

用段寄存器表地址时,与对应的寄存器配对使用。


2 解决除法溢出的问题

(1) 问题

用div指令做除法的时候可能会产生除法溢出。由于这样的问题,在进行除法运算的时候要注意和被除数的值,比如1000000/10就不能用div指令来计算。编写divdw解决这个问题。


(2) 子程序描述

名称:divdw

功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。

参数:(ax) = dword型数据的低16位,(dx) = dword型数据的高16位,(cx) = 除数

返回:(dx) = 结果的高16位,(ax)= 结果的低16位,(cx) = 余数

应用举例:计算1000000/10(F4240H/0AH)

mov ax, 4240H

mov dx, 000FH

mov cx, 0AH

call   divdw
结果:(dx) =0001H,(ax) = 86A0H,(cx) = 0


(3) 提示

给出一个公式:

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指令来做,肯定不会导致除法溢出。


(4) 代码

1.        assume    cs:code

2.         

3.        code          segment

4.        start:        mov ax, 4240H

5.                 mov dx, 000FH

6.                 mov cx, 0AH

7.                 call   divdw

8.                

9.                 mov ax, 4c00h

10.             int    21h

11.            

12.    ;功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。

13.    ;参数:(ax) = dword型数据的低16位,(dx) =dword型数据的高16位,(cx) = 除数

14.    ;返回:(dx) = 结果的高16位,(ax) = 结果的低16位,(cx) = 余数

15.    divdw:

16.             mov bx,ax

17.             mov ax, dx

18.             mov dx, 0

19.            

20.             div    cx     ;ax = int(H/N), dx = rem(H/N)

21.             mov si, ax         ;si     =int(H/N), (dx) = rem(H/N) * 65536

22.            

23.             mov ax, bx

24.             div    cx     ;(rem(H/N) * 65536 + L) / N, ax保存的低16位商,(dx) = 余数

25.            

26.             mov cx, dx

27.             mov dx, si

28.            

29.             ret

30.    code          ends

31.    end         start
注意理解乘以65536的含义(与寄存器保存高16位的关系)。


(5) 运行结果

Figure3. divdw运行结果

3 数值显示

(1) 问题

编程,将data段中的数据以十进制的形式显示出来。

data segmemt

    dw 123, 12666,1, 8, 3, 38

data  ends

要将数据用十进制形式显示到屏幕上,要进行两步工作:

[1] 将用二进制信息存储的数据转变为十进制形式的字符串。

[2]显示十进制形式的字符串。


(2) 子程序描述

名称:dtoc

功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾符。

参数:(ax) = word型数据,ds:si指向字符串的首地址。

返回:无

应用举例:编程,将数据12666以十进制的形式在屏幕的8行3列,用绿色显示出来。在显示时调用本次实验中的第一个子程序show_str。


(3) 代码

按照子程序描述要求编写代码,将ax数转化为字符串进行显示。

1.        assume    cs:code

2.         

3.        data segment

4.                 db     10 dup (0)

5.        data ends

6.         

7.        code          segment

8.        start:        mov ax, 12666

9.                 mov bx, data

10.             mov ds, bx

11.             mov si, 0

12.            

13.             call   dtoc ;将ax的每一位转化为字符串

14.            

15.             mov dh, 8

16.             mov dl, 3

17.             mov cl, 2

18.             call   show_str ;显示data段的字符串

19.     

20.             mov ax, 4c00h

21.             int    21h

22.     

23.    ;功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾符

24.    ;参数:(ax) = word型数据,ds:si指向字符串的首地址

25.    ;返回:无

26.    dtoc:         mov dx, 0                   ;做除法的高16位

27.             mov bx, 10

28.    s4:    div    bx

29.             mov cx, ax                

30.             jcxz  s5              ;余数为0时函数退出返回

31.             add  dx, 30h              ;将余数转换为对应的ASCII值

32.             mov ds:[si], dl  ;除以10的余数存在dl中

33.             inc    si

34.             mov dx, 0                   ;上一次的商作为被除数

35.             mov cl, 2           ;保证余数为0时才退出

36.             loop s4

37.            

38.    s5:    mov ds:[si], dl  ;字符串以0为结尾符

39.             mov si, 0

40.             ret

41.     

42.    ;功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串

43.    ;参数:(dh) = 行号(取值范围 0 ~24),(dl) = 列号(取值范围0 ~ 79),(cl) = 颜色,ds:si指向字符串的首地址。

44.    ;返回:无

45.    show_str:        mov ax, 0b800h

46.                       mov es, ax                 ;显存首段地址

47.                       mov al, cl          ;保存颜色参数

48.                      

49.                       mov bp, 0

50.                       mov ch, 0

51.                       mov cl, dh

52.    s0:             add  bp, 160              ;行号对应的显存地址

53.                       loop s0

54.                      

55.                      

56.                       mov di, 0

57.                       mov ch, 0

58.                       mov cl, dl

59.    s1:             add  di, 2           ;列号对应的显存地址

60.                       loop s1

61.                      

62.                      

63.    s2:             mov cl, ds:[si]

64.                       jcxz  s3              ;检测当前字符是否为0,如果为0则转移到s3处执行

65.                       mov         es:[bp+ di],cl

66.                       inc    di

67.                       mov         es:[bp+di], al           ;字符前景色

68.                       inc    di

69.                       inc    si

70.                       loop s2

71.    s3:             ret   

72.    code          ends

73.    end         start

(4) 运行结果

Figure4. 数值显示
由于求余时首先得到的是低位,故而显示出66621,可再写点程序显示出正确的12666。

[2014.12.11 - 12:01]
R《Hb》Note Over.

0 0
原创粉丝点击