您的位置:首页 > 其它

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

2014-12-11 11:54 204 查看
《汇编语言·第三版》--王爽

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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: