王爽《汇编语言》第十章实验十 子程序3(dtoc) 题目解答

时间:2021-01-02 00:42:02


; 子程序:dtoc
; 功能:将word型数据转变成表示十进制的字符串,字符串以0结尾
; 参数:(ax) = word 型数据
;  ds:si 指向字符串首地址
; 返回:无
; 应用举例,将12666以10进制的形式显示在屏幕的8行3列,用绿色显示出来,显示用到第一个子程序show_str


assume cs:code

data segment
 db 10 dup(0)
data ends

stack segment
 db 16 dup(0)
stack ends

code segment
start:
 mov ax, data
 mov ds, ax

 mov ax, stack
 mov ss, ax
 mov sp, 16

 mov dx, 0c1h
 mov ax, 76f3h
 mov si, 0

 call dwtoc

 mov dh, 8
 mov dl, 3
 mov cl, 2
 
 call show_str

 mov ah, 01h
 int 21h

 mov ax, 4c00h
 int 21h

; 子程序:dwtoc
; 功能:将dword型数据转变成表示十进制的字符串,字符串以0结尾
; 参数:(ax) = dword 型数据的低16位
;  (dx) = dword型数据的高16位
;  ds:si 指向字符串首地址
; 返回:无
dwtoc:
 mov cx, 0
 push cx

 s_dwtoc:
  mov cx, 10 ; 除数
  call divdw ; 余数在cx中

  add cx, 30h
  push cx  ; 保存余数的ASCII形式

  ; 判断是否商为0,如果高低16位都为0,则返回
  mov cx, dx
  jcxz ok_dxz;
  
  ; 高位不为0,则直接跳回,继续执行运算
  jmp short s_dwtoc

 ; 商的高位为0
 ok_dxz:
  mov cx, ax
  jcxz ok_axz
  jmp short s_dwtoc

 ; 商的低位为0
 ok_axz:
  ; 赋值到 ds:[si]
  mov dx, si ; 保存si,si为字符串的首地址
  loop_dtoc:
   pop cx
   mov ds:[si], cl
   jcxz end_dwtoc
   inc si
   jmp short loop_dtoc

  mov si, dx
 
 end_dwtoc:
 mov si, dx
 ret

dtoc:
 ; 先把一个0放进堆栈,在后面s2从堆栈中取出的时候,可以根据cx为0跳转
 mov cx, 0
 push cx
 s1_dtoc:
  mov dx, 0
  mov cx, 10
  div cx

  mov cx, dx  ; dx余数
  add cx, 30h
  push cx   ; 保存在堆栈

  mov cx, ax  ; ax为商,当商为0的时候,各位的值就已经得到了,就可以跳出循环
  jcxz ok1_dtoc

  jmp short s1_dtoc
 
 ok1_dtoc:
  mov ch, 0
  s2_dtoc:
   ; 从堆栈中取出
   pop cx
   jcxz ok2_dtoc
   mov ds:[si], cl
   inc si
   jmp short s2_dtoc

  ok2_dtoc:
   ret
 
show_str:
  push ax
  push bx
  push cx
  push dx
  push es
  push si

  ; 计算好字串开始显示的地址Y = 160*(行数-1) + 列数*2-2, B800 : Y
  ; 循环将参数里的字串写进显卡内存,并检测到0就返回
  
  ; bx = 160*(行数-1)
  mov bh, dh
  sub bh, 1
  mov al, 160
  mul bh
  mov si, ax ; si 为根据行数算出来的偏移值

  ; ax = 列数*2-2
  mov bl, dl
  mov al, 2
  mul bl
  sub ax, 2 ; 根据列数算出来的偏移值 
  add si, ax ; 行数和列数的和存在SI中了

  mov ax, 0b800h
  mov es, ax
  
  mov bx, si ; 将si 的值保存在bx中,bx为显存显示偏移值
  mov si, 0 ; 题目要求。。。

  mov dl, cl ; 保存字体颜色属性
  mov ch, 0
 s:
  mov  cl, ds:[si]
  mov  es:[bx], cl
  jcxz ok

  mov es:[bx+1], dl

  inc si
  add bx, 2
  jmp short  s
 ok:
  pop si
  pop es
  pop dx
  pop cx
  pop bx
  pop ax

  ret

; 子程序:divdw
; 要求:进行不会除法溢出的除法运算,被除数为dword,除数为word,结果为dword
; 参数:(ax) = 被除数dword型的低16位
;  (dx) = 被除数dword型的高16位
;  (cx) = 除数
;
; 返回:(dx) = 结果的高16位
;  (ax) = 结果的低16位
;  (cx) = 余数
divdw:
 mov bx, ax ; 缓存ax——被除数的低16位
 mov ax, dx ; ax = H, 被除数的高16位
 mov dx, 0
 div cx  ; ax 为商,dx为余数 = rem(H/N) * 65536
 
 push ax  ; 结果的商,也就是最后要放在dx中的

 mov ax, bx ; dx为 rem(H/N) * 65536, 为高16位,ax为低16位,再进行一次除法运算
 div cx  ; ax 为商——最后结果的低16位,dx为余数——为最后结果,应赋给cx

 mov cx, dx
 pop dx

 ret

code ends
end start