这里为后面的课程设计一做准备,贴一篇子程序的设计思路:


  • 我们要实现三个功能:
  • 显示字符串
  • 解决除法溢出问题
  • 数值显示

    展示功能:

  • 显示字符串

    子程序的参数接口
                  mov ch, 0
                  mov di, 16*1+1          ;指定字符串
                  mov cl, ds:[di]         
                  mov si, 900             ;指定位置
                  mov bl, ds:[16*3+1]     ;指定颜色
                  mov ax, 0b800h          ;输出位置
                  mov es, ax
                  call show_str     
    程序结构
          show_str:       
                  jcxz back
                  mov es:[si], cl
                  mov es:[si+1], bl
                  add si, 2
                  inc di
                  mov cl, ds:[di]
                  jmp show_str
    
          back:   ret

    QQ截图20230323174647.png

    更改参数,我们也可以得到另一些结果:
    字符串位置di:16*0+0
    显示位置si:1500
    指定颜色bl:ds:[16*3+0]
    QQ截图20230323174916.png

  • 解决除法溢出问题

    书中提供了这样一个公式,其原理是:高16位和低16位分别做除法运算,高位除法产生的余数放到低16位再做除法,这样就能得到最终的余数
    这样,在除数为16位的前提下,任何一种情况都已经囊括其中
    微信图片_20230323175539.jpg
    这里我对高、低16位都进行的是32位的除法,如果我使用16位除法,会导致无法存储商大于FFH的情况,
          div_dw: 
                  ;(输入):ax低16位,dx高16位,cx为16位除数
                  ;(输出):dx结果高16位,ax结果低16位,cx为余数
                  push bx
                  mov bx, ax      ;暂存ax,低位
                  mov ax, dx      
                  mov dx, 0
                  div cx          ;高16作除法,余数并到低16位
                  push ax         ;暂存高16位除法结果中的商
          
                  mov ax, bx
                  div cx          ;低16位除法
    
                  mov cx, dx
                  pop dx
    
                  pop bx
                  ret
    输入内容:
    高16位:0fh,低16位:4240h,除数cx:0ah
    QQ图片20230323183004.png

QQ截图20230323183236.png

  • 数值显示 (于23327针对中间数字含0的情况进行修改)

    根据输入的十六进制数,转化成十进制数的字符串形式
    这里使用了很多的栈操作,是因为得暂时存放数据,避免程序内的操作对外面程序产生影响
         dtoc:
                  ;X输入ax,(16位)
                  ;结果保存在number字段
                  ;注意,检测商为0才跳出!!
                  push bx
                  push cx
                  push dx
                  push ds
                  push si
    
                  mov bx, number          
                  mov ds, bx              ;目标地址
    
                  mov si, 0               ;偏移指针,个数
                  mov bx, 10              ;除数
                  mov dx, 0               ;32位除法,但这里只有ax参与,dx得置0
                  
          in_num: 
                  div bx
                  push dx
                  inc si
                  mov cx, ax              ;这里没有loop循环,cx可放心使用
                  jcxz in_num_exit
                  mov dx, 0
                  jmp in_num
    
          in_num_exit:
                  mov cx, si
                  mov si, 0
                  mov bx, 0
          set_num:
                  pop bx
                  add bx, 30h
                  mov ds:[si], bl
                  inc si
                  loop set_num
                  mov byte ptr ds:[si], 0         ;末尾添0,表示字符串结束
    
                  pop si
                  pop ds
                  pop dx
                  pop cx
                  pop bx
                  ret 

错误版本,引以为鉴

aaa1QQ截图20230327145129.png

aaa2QQ截图20230327145154.png

这里传入的参数ax值为65535,修改显示字符串程序中的di为40h,即可在屏幕中展示
QQ截图20230323180938.png
  • 清屏操作

    原理是对首页数据全部清零
          clear_screen:
                  push bx
                  push cx
                  push es
                  push si
    
                  mov bx, 0b800h
                  mov es, bx
                  mov cx, 4096
                  mov si, 0
          swap:   mov byte ptr es:[si], 0
                  inc si
                  loop swap
    
                  pop si
                  pop es
                  pop cx
                  pop bx
                  ret

最后附上整个代码,各个功能需自行改动

(于23327针对中间数字含0的情况进行修改)

assume cs:code ds:data ss:stack
data segment
        ;   0123456789ABCDEF
        db 'fishing is funny',0
        db 'welcome to masm!',0
data ends

color segment
        db 00000100B ;红色
        db 00000010B ;绿色
        db 00000001B ;蓝色
color ends

number segment
        db 512 dup(255)
number ends

stack segment stack
        db 128 dup(0)
stack ends

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

                call clear_screen

                mov ch, 0
                mov di, 16*0+0          ;指定字符串
                mov cl, ds:[di]         
                mov si, 1500             ;指定位置
                mov bl, ds:[16*3+1]     ;指定颜色
                mov ax, 0b800h          ;输出位置
                mov es, ax
                call show_str     

                mov ax, 4240h           ;除法,低16位
                mov dx, 000fh           ;除法,高16位
                mov cx, 0ah             ;除法,除数,16位
                call div_dw


                mov ax, 65535           ;要转换的十六进制数
                call dtoc

                mov ax, 4c00h
                int 21h
        
        div_dw: 
                ;(输入):ax低16位,dx高16位,cx为16位除数
                ;(输出):dx结果高16位,ax结果低16位,cx为余数
                push bx
                mov bx, ax      ;暂存ax,低位
                mov ax, dx      
                mov dx, 0
                div cx          ;高16作除法,余数并到低16位
                push ax         ;暂存高16位除法结果中的商
        
                mov ax, bx
                div cx          ;低16位除法

                mov cx, dx
                pop dx

                pop bx
                ret

        dtoc:
                ;X输入ax,(16位)
                ;结果保存在number字段
                ;注意,检测商为0才跳出!!
                push bx
                push cx
                push dx
                push ds
                push si

                mov bx, number          
                mov ds, bx              ;目标地址

                mov si, 0               ;偏移指针,个数
                mov bx, 10              ;除数
                mov dx, 0               ;32位除法,但这里只有ax参与,dx得置0
                
        in_num: 
                div bx
                push dx
                inc si
                mov cx, ax              ;这里没有loop循环,cx可放心使用
                jcxz in_num_exit
                mov dx, 0
                jmp in_num

        in_num_exit:
                mov cx, si
                mov si, 0
                mov bx, 0
        set_num:
                pop bx
                add bx, 30h
                mov ds:[si], bl
                inc si
                loop set_num
                mov byte ptr ds:[si], 0         ;末尾添0,表示字符串结束

                pop si
                pop ds
                pop dx
                pop cx
                pop bx
                ret 

        show_str:       
                jcxz back
                mov es:[si], cl
                mov es:[si+1], bl
                add si, 2
                inc di
                mov cl, ds:[di]
                jmp show_str

        back:   ret

        clear_screen:
                push bx
                push cx
                push es
                push si

                mov bx, 0b800h
                mov es, bx
                mov cx, 4096
                mov si, 0
        swap:   mov byte ptr es:[si], 0
                inc si
                loop swap

                pop si
                pop es
                pop cx
                pop bx
                ret

code ends
end start