1. 程式人生 > >彙編課程設計:閏年判斷程式詳解

彙編課程設計:閏年判斷程式詳解

程式說明:
這是一個判斷某一年是否為潤年的程式,執行可執行程式Ifleap.exe後,輸入具體的年份,
可輸出是本年是否為閏年的提示資訊。
函式圖:
子函式流程圖

data segment    ;定義資料段
    infon db 0dh,0ah,'Please input a year: $'	;infon ,雙位元組,回車換行,內容
    Y db 0dh,0ah,'This is a leap year! $'	;y ,雙位元組,回車換行,內容
    N db 0dh,0ah,'This is not a leap year! $' 	;n ,雙位元組,回車換行,內容($是結束符)
    w dw 0		;w為雙字型別
    buf db 8		;開闢8個雙位元組型別的緩衝區,未賦值
        db ?		
        db 8 dup(?)		
data ends

stack segment stack
    db 200 dup(0)	;開闢200個雙位元組型別的儲存空間。(保護現場用到)
stack ends

code segment
          assume ds:data,ss:stack,cs:code
    start:mov ax,data	;暫存器間的資料交換,把data給了資料段
          mov ds,ax
          
          lea dx,infon  ;在螢幕上顯示提示資訊
          mov ah,9
          int 21h

          lea dx,buf    ;從鍵盤輸入年份字串
          mov ah,10
          int 21h
          
          mov cl, [buf+1] 	;把buf+1地址指向的內容給cl,buf長度
          lea di,buf+2		;把buf+2的地址給di,buf偏移地址
          call datacate  ;呼叫函式datacate,傳遞引數
          call ifyears	;呼叫函式ifyears,由引數判斷是否為閏年
          jc a1			;若產生進位就跳到a1處
          
          lea dx,n		;dx載入n的地址'This is not a leap year!'
          mov ah,9		;顯示dx內的內容
          int 21h
          jmp exit		;跳到exit
    a1:   lea dx,y		;dx載入y的地址'This is a leap year!'
          mov ah,9
          int 21h
    exit: mov ah,4ch	;結束本程式,返回 DOS 作業系統
          int 21h
       
 
;實現將字串的閏年轉換為數字儲存在ax中
datacate proc near;	;段內呼叫,子函式1
          push cx;      ;保護現場                                               
          dec cx		
          lea si,buf+2	;把buf+2的地址給si
     tt1: inc si		;移動到字串指定位置
          loop tt1		;迴圈函式是個遞增函式, loop指令的格式是:loop標號,cpu執行loop指令的時候,要進行兩步操作
						;1:(cx)=(cx)-1    
						;2:判斷cx中的值,不為零則轉至標號處執行,如果為零,則向下執行
          ;lea si,cx[di]
          pop cx		;恢復現場
     
      
          mov dh,30h	
          mov bl,10		;乘數設定為10
          mov ax,1		
      l1: push ax		;保護現場
          sub  byte ptr [si],dh		;沒有暫存器參與的記憶體單元訪問指令(DMA),si-dh儲存在si中
          mul  byte ptr [si]		;沒有暫存器參與的記憶體單元訪問指令(DMA),ax*si,結果放在eax中,這裡的暫存器si是16位,被乘數在ax中也是16位。
          							;MUL r/m(暫存器或者記憶體)  ;mul是字內乘法,把si對應的地址內一個字的長度賦給
									;如果引數是 r8/m8,   將把 AL 做乘數, 結果放在 AX
									;如果引數是 r16/m16, 將把 AX 做乘數, 結果放在 EAX
									;如果引數是 r32/m32, 將把 EAX 做乘數, 結果放在 EDX:EAX
          add w,ax		;w+ax,結果存入w,存入的是數字
          pop ax		;恢復現場
          mul bl		;bl*al,結果存放在ax中
          dec si		;si中的內容減一
          loop l1		;l1迴圈,cx判斷次數
          ret
 datacate endp

;實現ax中年份的判斷
   ifyears proc near		;段內呼叫,子函式2
           push  bx 		;保護現場(保護誰,就用到誰)
           push  cx
           push  dx
           mov ax,w			;把w值賦給cx,w值為
           mov   cx,ax		;把ax值賦給cx
           mov  dx,0		
           mov  bx,4		;ax/4
           div  bx			;ax/bx,結果在ax中,餘數在dx中
           					;如果除數是8位,那麼除法的結果AL儲存商,AH儲存餘數,
       						;如果除數是16位,那麼除法的結果 AX儲存商,DX儲存餘數。
           cmp  dx,0		;比較餘數和0,結果存入cf標誌位(進位標誌位)
           jnz  lab1		;如果非0,跳轉到lab1處
           mov   ax,cx		
           mov  bx,100		;ax/100
           div  bx			
           cmp dx,0			;比較餘數和0,結果存入cf標誌位(進位標誌位)
           jnz  lab2		;如果非0,跳到lab2
           mov  ax,cx		
           mov bx,400		;ax/400
           div  bx			
           cmp  dx,0		;比較餘數和0,結果存入cf標誌位(進位標誌位)
           jz  lab2			;cf=0跳到lab2
     lab1: clc				;清除cf標誌位,設定cf=0
           jmp lab3			;跳到lab3
     lab2: stc				;cf置1
     lab3: pop  dx			;恢復現場
           pop  cx		
           pop  bx
           ret
   ifyears endp
code ends
   end start

引數傳遞:
主函式與DATACATE的引數傳遞方式為約定單元法,約定單元為BUF、 W。
主函式與IFYEARS的引數傳遞方式為約定單元法,約定單元為W。

中斷向量的計算
中斷向量處理程式地址為1C8B:000D和1c8b:0015 .
本題用到了21H函式庫,入口地址為0:84h。
CS=421h+2h=86h
IP=4
21h=84h