Подсчет установленных битов. 16-разрядная программа контроля четности сборки

#assembly #x86 #masm #16-bit #parity

#сборка #x86 #masm #16-разрядный #проверка четности

Вопрос:

Я пытаюсь написать подпроцедуру, которая будет подсчитывать количество ошибок, установленных в 16-битном числе, а затем отправлять это число (набор битов) обратно в основную процедуру в AX. Основной должен отображать количество единиц и определять, является ли число четным или нечетным.

Я пытаюсь подсчитать единицы, сдвигая влево и увеличивая при переносе. Проблема, похоже, в том, что когда я возвращаюсь к «main», исходное входное число по-прежнему находится в AX, а не в количестве, которое я получил в «parity». Я не знаю, почему оно не меняется.

     ;===================================================================
    ;                   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
  

Комментарии:

1. Знаете ли вы, что у x86 есть флаг четности? Она работает только с младшим байтом результата, но это все еще довольно хорошо. В имеющемся у вас коде вы можете использовать ADC для уменьшения разветвленности.

Ответ №1:

Я предполагаю, что цель этого заключается в том, что 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 регистре. В этом случае вам нужно будет удалить PUSH AX перед CALL PARITY (ввод уже введен AX ) и вместо этого поместить его непосредственно после CALL (чтобы сохранить возвращенный результат, который будет выведен позже — я предполагаю, что его AX необходимо сохранить, потому что он может быть поврежден другими вызовами); и удалите POP AX и PUSH AX из PARITY .