Печать упакованного BCD (DT) - язык ассемблера (TASM) - PullRequest
1 голос
/ 05 февраля 2012

Я пытался сделать простой калькулятор в сборке.Я использовал TASM (школьная политика).Проблема заключается в печати числа, сохраненного с помощью команды FBSTP (команды сопроцессора) в переменной DT.

FBSTP adr - сохраняет по адресу «adr» значение, расположенное в верхней части стека (ST (0)), в виде упакованного десятичного числа (определяется в «adr» с помощью DT).Указатель стека уменьшается.Преобразование выполняется во время процесса сохранения.

Я отладил программу, и при делении на 10 результат искажается.Например: 12 * 1 = 12.Результат в res2 правильный.После перемещения в AX это все еще верно, но когда я делю это на 10, DX становится 8 вместо 2, поэтому вместо 12 он печатает 18. Я также заметил, что 12h = 18d, но я не могу установить соединение.Л.Е .: Если я использую простое целочисленное хранилище в переменной слова и печатаю, что оно отлично работает.

Вот часть кода, которую я считаю, имеет значение:

multiplication:
FINIT
FILD x
FILD y
FMUL
FBSTP res2
FWAIT
MOV ax,WORD PTR res2
call write
jmp_line
jmp exit  


write       PROC    NEAR ;my printing proc moves cursor x spaces and starts writing
                          from back to front

    PUSH    DX
            PUSH    AX
    PUSH    CX
    MOV     CX,0

    CMP     AX, 0;check sign
    JNS     ok_write
    NEG     AX ;negate if <0
    MOV     CX,1 ;used to know if number is negative


ok_write:
    printspace ;macro that jumps 5 spaces(maximum number length)
    ;starts printing the number backwards
    print_digit:
    inc len
    ;print each digit
    MOV DX,0 ;prepare DX for storing the remeinder
    DIV CS:ten ;divide AX by 10 so that the last digit of the number is stored
    ADD dl,30h ;transform to ascii
    PUSH AX ;save AX
    MOV ah,02h
    INT 21h  ;print last digit
    printchar   8 ;put cursor over last printed digit
    printchar   8 ;move cursor in front of last printed digit

    cmp divi,1  ;
    JNE not_div
    cmp len,1
    JNE not_div
    printchar '.'
    printchar   8
    printchar   8

    not_div:
    POP AX ;retreive AX
    CMP AX,0 ;when AX=0 the number is written
    JNE print_digit
    ;/print each digit
    CMP     CX,1
    JNE     end_print
    printchar   '-'
   end_print:

    POP     CX
    POP     AX
    POP     DX
    RET
  write       ENDP  

Большое спасибо.

1 Ответ

0 голосов
/ 16 февраля 2015

Вы загружаете номер BCD в AX.BCD означает двоично-десятичный кодтаким образом, каждый 4-битный код на самом деле является десятичным значением.Вы делите на 10, также десятичные.Но AX рассматривает числа как шестнадцатеричные.Если вы попытаетесь разделить 12 (bcd) на 10 (десятичное число), то 12 будет считаться шестнадцатеричным, а десятичное значение равно 18. 18, деленное на 10 (десятичное), или 0Ah действительно дает в конце 18 десятичное число.Если 12 - это bcd, вам нужно только преобразовать упакованный bcd (каждые 4 бита - это десятичное число, закодированное в шестнадцатеричном формате) в неупакованный (каждые 8 ​​бит представляют одну десятичную цифру).Чтобы упростить задачу: если AX содержит 12 (bcd), вы можете и AX с 0Fh, чтобы получить 2 из него, и топор с 0F0h, чтобы получить 1 из него.Для цифр вы просто добавляете 30h ("0") к нему.Для палаток вы выбираете 4 бита и добавляете к нему 30ч («0»).Опять же: если вы конвертируете упакованный bcd в AX = 12 в распакованный BCD в AX = 0102 и добавите к нему 3030h, AX будет содержать ASCII 12 (bcd).Чтобы сохранить это для печати на экране, вы должны знать, что младшие 8 бит будут сохранены в младших адресах в памяти.Поэтому используйте AH и AL с xchg AH, AL, таким образом, AX = 3231h и сохраняйте их в ячейке памяти в DS.Для чисел, превышающих 99 (bcd), вы должны использовать ту же технику для извлечения сотен, тысяч и т. Д. Я надеюсь, что это прояснит ситуацию.

...