《汇编语言·第三版》--王爽
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) 运行结果
将程序中的坐标,字符串,颜色的参数更换,如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 |
(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 |
(5) 运行结果
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 |