2011-10-14 120 views
2

我正在嘗試編寫一個子程序,它將計算16位數中設置的數量,然後將該數量(位設置)返回到AX中的主程序。主顯示器應顯示1的數量並確定數字是偶數還是奇數。計數設置位。 16位程序集奇偶校驗程序

我想通過向左移位並在進位時遞增來計數1。問題似乎是,當我回到'主'時,原始輸入數字仍然在AX中,而不是我'平價'中的數量。我不知道爲什麼它沒有改變。

;=================================================================== 
    ;     MAIN.ASM 
    ;=================================================================== 
     EXTERN GETDEC$:FAR 
     EXTERN NEWLINE:FAR 
     EXTERN PUTSTRNG:FAR 
     EXTERN PUTDEC$:FAR 
     EXTERN PUTBIN:FAR 
     EXTERN PARITY:FAR 
    ;=================================================================== 
     .MODEL LARGE 
     .STACK 512 
    ;=================================================================== 
    ; D A T A S E G M E N T D E F I N I T I O N 
     .DATA 
    NUMBER  DW ? 
    PROMPT  DB 'Enter a number: ' 
    BINDISPLAY  DB 'Number in binary: ' 
    ONESDISPLAY  DB 'Number of 1s: ' 
    ODDDISPLAY  DB 'The number of 1s is odd. ' 
    EVENDISPLAY DB 'The number of 1s is even. ' 
    ;=================================================================== 
    ; C O D E S E G M E N T D E F I N I T I O N 
     .CODE 
      ASSUME DS:DGROUP 
    ;=================================================================== 

    MAIN PROC 

     MOV  AX,DGROUP   ;SET DS-REGISTER TO POINT TO 
     MOV  DS,AX    ;DATA SEGMENT 
     MOV  ES,AX    ;AND ES ALSO 

     CALL NEWLINE 
     MOV  DI, OFFSET PROMPT 
     MOV  CX, SIZEOF PROMPT 
     CALL PUTSTRNG 
     CALL GETDEC$ 
     CALL NEWLINE 
     MOV  DI, OFFSET BINDISPLAY 
     MOV  CX, SIZEOF BINDISPLAY 
     CALL PUTSTRNG 
    CALL PUTBIN 
     PUSH AX 
     CALL PARITY 
    CALL NEWLINE 


     CALL NEWLINE 
     MOV  DI, OFFSET ONESDISPLAY 
     MOV  CX, SIZEOF ONESDISPLAY 
     CALL PUTSTRNG 
    POP AX 
     CALL PUTDEC$ 
     CALL NEWLINE 

    SUB DX, DX 
     MOV  BX, 2 
     DIV  BX 
     CMP  DX, 0 
     JNE  ODDS 

     MOV  DI, OFFSET EVENDISPLAY 
     MOV  CX, SIZEOF EVENDISPLAY 
     CALL NEWLINE 
     CALL PUTSTRNG 
     JMP  EXIT_PROGRAM 
ODDS:  
     MOV  DI, OFFSET ODDDISPLAY 
     MOV  CX, SIZEOF ODDDISPLAY 
     CALL NEWLINE 
     CALL PUTSTRNG  
EXIT_PROGRAM: 
    .EXIT 
     MOV  AX, 4C00H 
     INT  21H 
MAIN ENDP 
     END MAIN 

;;=================================================================== 
;    Veronica Kaufman 
;     CISP 310 
;    PARITY.ASM 
;=================================================================== 
     .MODEL LARGE  
;=================================================================== 
; D A T A S E G M E N T D E F I N I T I O N 
     .DATA 
ONES_COUNT  DW  0       
;=================================================================== 
; C O D E S E G M E N T D E F I N I T I O N 
     .CODE 
     ASSUME DS:DGROUP 
;=================================================================== 

PARITY PROC FAR PUBLIC USES CX DX DS 
    POP AX 
NUM_LOOP: 
    CMP AX, 0 
    JE END_PROGRAM 
    SHL AX, 1 
    JC INCREMENT 
    JMP NUM_LOOP 
INCREMENT: 
    INC ONES_COUNT 
    JMP NUM_LOOP 
END_PROGRAM: 
    MOV AX, ONES_COUNT 
    PUSH AX 
    RET 
PARITY ENDP 
     END PARITY 
+0

你知道x86有一個奇偶標誌嗎?它只適用於結果的低字節,但這仍然很不錯。在你的代碼中,你可以使用'ADC'來減少分支。 – harold

回答

3

我認爲這樣做的目的是使PARITY將在堆棧上的參數,然後修改這樣的說法,把它留在同一個地方堆棧:

; (This does not work, see below) 

... 
    PUSH AX   ; input value 
    CALL PARITY  ; want this to change it in-place... 
    ... 
    POP  AX   ; ...so that this pops off the output value 
    CALL PUTDEC$ 

... 

PARITY PROC FAR PUBLIC USES CX DX DS 
    POP  AX   ; get argument from stack 
    ... 
    PUSH AX   ; put result back on stack 
    RET 

這億韓元不起作用,原因有兩個:

  1. CALL將返回地址壓入堆棧。
  2. PROC生成的序言代碼... USES將更多內容推入堆棧。

當你POP AX裏面PARITY,你實際上是突然離開完全不同的東西(然後把別的東西放回原處) - 可能是由序幕保存其他寄存器之一。

選擇做正確的事:

  1. 如果你明白,在這裏被使用的調用約定,你應該能夠發現,被壓入堆棧的AX的位置,最有可能在一些小與BP寄存器相抵消(我對MASM並不十分熟悉,無法確切知道PROC生成的序言代碼在這種情況下會發生什麼),並直接加載/存儲它。

  2. 或者,使PARITY接受其輸入並將其輸出直接返回到AX寄存器中。在這種情況下,你將需要CALL PARITY之前刪除PUSH AX(輸入已經在AX),並把它直接CALL代替(保存返回的結果,這將在後面彈出 - 我假設AX需要保存,因爲它可能會被其他調用破壞);並從PARITY中刪除POP AXPUSH AX