Сборка 8086 | Сумма массива, печать многозначных чисел

Я написал довольно простой код в asm x8086, и я столкнулся с ошибкой. Если бы кто-нибудь мог помочь мне с кратким объяснением, я был бы очень признателен.

IDEAL
MODEL small
STACK 100h
DATASEG
; --------------------------
    array db 10h, 04h, 04h, 04h, 04h, 04h, 04h, 04h, 04h, 04h
    sum db 0
    ; --------------------------
CODESEG
start:
    mov ax, @data
    mov ds, ax
; --------------------------
    xor cx, cx
    mov al, 0
    mov bx, offset array
StartLoop:
    cmp cx, 10
    jge EndLoop
    add al, [bx]
    add [sum],al
    inc cx
    inc bx
    jmp StartLoop
EndLoop:
    mov ah, 09h
    int 21h

; --------------------------

exit:
    mov ax, 4c00h
    int 21h
END start

2 ответа

Решение

С поправкой на add быть замененным mov как отмечено в вашем комментарии (обратите внимание, что строка: add al, [bx] на самом деле mov al, [bx]) есть только вызов функции на метке EndLoop, что неправильно!

Вы хотите отобразить сумму и используете функцию печати DOS. Эта функция 09h ожидает указатель в DS:DX, который вы не предоставляете!
Даже если бы вы это сделали, вам все равно пришлось бы преобразовать сумму суммы в ее текстовое представление.

Быстрое решение здесь состоит в том, чтобы довольствоваться собой и просто отображать результат в виде одного символа ASCII. Жестко запрограммированная сумма равна 52, и поэтому это отображаемый символ:

EndLoop:
    mov dl, [sum]
    mov ah, 02h    ;Single character output
    int 21h

; --------------------------

exit:
    mov ax, 4c00h
    int 21h

Еще один шаг вперед, и мы можем отобразить "52":

mov al,[sum]
mov ah,0
mov dl,10
div dl        ---> AL=5   AH=2
add ax,3030h  ---> AL="5" AH="2"
mov dh,ah     ;preserve AH
mov dl,al
mov ah,02h
int 21h
mov dl,dh     ;restore
int 21h

Я не вижу никакой ошибки вообще, код будет суммировать массив, отображать случайное sh*t и завершаться.

Вы, вероятно, хотите отобразить результат суммы?

int 21h, ah=9 будет отображать '$' завершенная строка из памяти, на которую указывает dx,

Таким образом, вам нужно две вещи, преобразовать число в [sum] строка завершается'$' в конце, а затем установить dx перед преобразованной строкой int 21h,

Вы можете попробовать извлечь number2string процедура отсюда: /questions/11755424/sborka-kak-sdelat-summu-mezhdu-dvumya-chislami-interval/11755430#11755430

Я бы лично изменил его на адрес целевого буфера в si в качестве другого аргумента вызова (т.е. просто удалите mov si,offset str из тела процедуры). Как это:

PROC number2string
  ; arguments:
  ;  ax = unsigned number to convert
  ;  si = pointer to string buffer (must have 6+ bytes)
  ; modifies: ax, bx, cx, dx, si
    mov  bx, 10  ; radix 10 (decimal number formatting)
    xor  cx, cx  ; counter of extracted digits set to zero
number2string_divide_by_radix:
  ; calculate single digit
    xor  dx, dx  ; dx = 0 (dx:ax = 32b number to divide)
    div  bx      ; divide dx:ax by radix, remainder will be in dx
  ; store the remainder in stack
    push dx
    inc  cx
  ; loop till number is zero
    test ax, ax
    jnz  number2string_divide_by_radix
  ; now convert stored digits in stack into string
number2string_write_string:
    pop  dx
    add  dl, '0' ; convert 0-9 value into '0'-'9' ASCII character encoding
  ; store character at end of string
    mov  [si], dl
    inc  si
  ; loop till all digits are written
    dec  cx
    jnz  number2string_write_string
  ; store '$' terminator at end
    mov  BYTE PTR [si],'$'
    ret
ENDP

Затем позвонить в ваш EndLoop вам нужно добавить в сегмент данных numberStr DB 8 DUP (0) выделить некоторый буфер памяти для строки и добавить в код:

    ; load sum as 16b unsigned value into ax
      xor  ax,ax      ; ax = 0
      mov  al,[sum]   ; ax = sum (16b zero extended)
    ; convert it to string
      mov  si,OFFSET numberStr
      call number2string
    ; display the '$' terminated string
      mov  dx,OFFSET numberStr
      mov  ah,9
      int  21h
    ; ... exit ...
Другие вопросы по тегам