設計子程序oop
子程序一:在指定的位置,用指定的顏色,顯示一個用0結束的字符串spa
舉例:在屏幕的8行3列,用綠色顯示data段中的字符串設計
assume cs:code data segment db 'Welcome to masm!',0 data ends code segment start: mov dh,8 ;行 mov dl,3 ;列 mov cl,2 ;顏色屬性 mov ax,data mov ds,ax mov si,0 call show_str ;子程序 mov ax,4c00h int 21h show_str: push dx ;避免寄存器衝突(雖然這個子程序沒有衝突,但爲了更好的使用,仍是加上了) push cx push si mov ax,0b800h mov es,ax ;顯示緩衝區段地址 mov al,dh mov bl,0a0h ;用於計算第八行的首地址 dec al mul bl ;首地址在ax中 mov bx,ax ;存在bx寄存器內 mov dh,0 mov di,dx ;用於計算列地址 dec di add di,di ;列地址就在di寄存器中 mov al,cl s: mov cl,ds:[si] ;取出字符,要判斷cx是否爲0 mov ch,0 jcxz ok ;終止指令跳轉的條件 mov dl,ds:[si] ;取出字符 mov es:[bx+di],dl ;將字符送入顯示緩衝區中 mov es:[bx+di+1],al ;設置字符屬性 inc si ;data段的地址偏移+1 add di,2 ;顯是緩衝區段地址+2 jmp short s ;指令跳轉 ok: pop dx ;恢復主程序中寄存器的值 pop cx pop si ret ;子程序返回 code ends end start
運行結果:(不知明緣由,第一行會被吃掉,所以實際顯示是在第七行)3d
子程序二:code
功能:解決除法溢出問題blog
應用舉例:計算1000000/10(F4240/0AH)內存
返回: (dx) = 結果的高16位,(ax)=結果的低16位,(cx)=餘數ci
結果:(dx) =0001H, (ax)=86A0H,(cx)=0 rem
公式:字符串
H:X的高16位
L:X的低16位
N:除數
X/N = int(H/N)*65535 + [rem(H/N*65535)+L]/N
(對公式的理解很重要!!!我看了半天,纔看懂了)
assume cs:code code segment start: mov ax,4240h ;存放被除數(dword類)的低16位地址 mov dx,000fh ;存放被除數(dword類)的高16位地址 mov cx,0ah ;存放除數 call divdw divdw: push ax ;把ax(即低16位地址先存入棧中,以後要用到) mov ax,dx ;對高16位地址進行16位除法 mov dx,0 div cx mov bx,ax ;bx的值爲int(H/N),將除法所得商移入bx中 pop ax ;取出低16位地址
div cx ;對低16位地址進行16位除法,結果的低16位商位於ax寄存器中 mov cx,dx ;將餘數移入cx中 mov dx,bx ;將結果的高16位商移入dx中 ret code ends end start
運行結果:
子程序設計三:
功能:將word型數據轉變爲表示十進制數據的字符串,字符串以0結尾
應用舉例:將12666以十進制的形式在屏幕的8行3列,用綠色顯示出來(顯示時調用子程序一)
assume cs:code data segment db 10 dup(0) ;保存字符串的內存地址段 data ends code segment start: mov ax,12666 mov bx,data mov ds,bx mov si,0 call dtoc ;調用子程序 mov ax,4c00h int 21h dtoc: mov bx,10 ;bx爲除數 mov dx,0 div bx ;對ax進行16位除法 mov cx,ax ;商保存在cx中,用於結束除法的繼續,當商爲0時,表明全部餘數已求出 add dx,30h ;利用十進制對應的ascii碼=十進制數值碼+30H,得出字符並存在寄存器dx中 push dx ;將字符結果保存在棧中,由於餘數結果相對於自己字符的順序是逆序,所以咱們要利用棧來逆序 add si,1 ;記錄除的次數,也就是字符的個數 jcxz s1 ;若cx即商爲0,則調到s1處 jmp short dtoc ;循環除法 s1: mov bl,0 mov ds:[si],bl ;在data段的即將放入字符的末尾,將0存入 mov cx,si ;將字符的個數存取cx中 mov si,0 ;si寄存器表示data段的偏移地址 s2: pop ds:[si] ;取出放在棧中的數據 add si,1 ;偏移地址+1 loop s2 ;循環 mov dh,8 ;顯示字符串 mov dl,3 mov cl,2 mov si,0 call show_str ret show_str: push dx push cx push si mov ax,0b800h mov es,ax mov al,dh mov bl,0a0h dec al mul bl mov bx,ax mov dh,0 mov di,dx dec di add di,di mov al,cl s: mov cl,ds:[si] mov ch,0 jcxz ok mov dl,ds:[si] mov es:[bx+di],dl mov es:[bx+di+1],al inc si add di,2 jmp short s ok: pop dx pop cx pop si ret code ends end start
運行結果:(仍是同樣,第一行顯示的會被吃掉,因此實際在第七行)