Home > Software design >  EMU 8086 stores wrong array element value in register
EMU 8086 stores wrong array element value in register

Time:09-18

.model small
.data
nizA db 1,2,3,4,5,6,7,8   
nizB db 8 dup(?)
len equ 8
.code   
main proc
mov si,0
mov di,0
mov cx,len

program: 
    mov al,nizA[si]      ;problem is here it always stores CDh in AL
    cbw                  ;convert AL to AX so i can divide
    mov bl,2             ;The number I want to divide so I test if its even or not
    div bl               ;Overflow message
    cmp ah,0
    je next:
        input:
            mov dl,nizA[si]
            mov nizB[di],dl
            inc di
next:
    add si,2
    loop program
endp
end

I have this code here, for my finals that I need to make, very simple. Find odd numbers from even indexes of given array. So naturally it means I increase SI by 2 and I put that array element in AL. But no matter what number is in array, what gets stores in AL is always hex number CD, which then, if it was stored as it was supposed to, I want to do CBW to convert to AX and be able do divide with BL I now just have error message from EMU 8086 saying

divide error - overflow. to manually process this error, change address of INT 0 in interrupt vector table.

Which surely is related to CD number, I only have two problems here

  1. CD being stored instead of 1
  2. Overflow (most likely because CD is way too high, but still I divide the numbers they only go less so it wont make sense kinda)

CodePudding user response:

You load cx with 8, so your loop will iterate 8 times. But you increment si by 2 on every iteration, so after the first 4 iterations you are past the end of the nizA array.

Try replacing mov cx, len with mov cx, len/2.

By the way, a much simpler and more efficient way to check if al is odd is to do test al, 1, which sets flags according to the bitwise AND of al with 1.

CodePudding user response:

"CD being stored instead of 1"

When a DOS .EXE starts, the DS segment register does not point at your program's .data section! The DS segment register points at the ProgramSegmentPrefix aka PSP. This 256-byte area is where DOS keeps some important data about the running program, and where you can retrieve the program's command line at offset address 128.

You found the value CDh when your code ran because that happens to be the very first byte in the PSP. It is the opcode for the int 20h instruction that always begins the PSP.

What you need to write is the following:

.code   
main proc
mov ax, @data
mov ds, ax

"Overflow (most likely because CD is way too high, but still I divide the numbers they only go less so it wont make sense kinda)"

Actually it does make sense. Because you are using CBW to extend the dividend into AX, and because the value in AL erroneously is CDh, the new value in AX becomes FFCDh. When your code then divides this by 2 (using mov bl, 2 div bl) the quotient is much larger than what can be stored in the division's dedicated quotient register AL. That's why you get the "divide error".

Solutions

  • Solution to verify that the division works this time:
    mov  ax, @data
    mov  ds, ax
    mov  si, 0
    mov  di, 0
    mov  cx, len/2
program: 
    mov  al, nizA[si]
    mov  ah, 0           ; For UNSIGNED division don't use CBW
    mov  bl, 2
    div  bl
    cmp  ah, 0           ; Remainder
    je   next
    mov  dl, nizA[si]    ; Reload
    mov  nizB[di], dl
    inc  di
next:
    add  si, 2
    loop program
  • Solution that avoids division in favor of TEST and adding some extra improvements too:
    mov  ax, @data
    mov  ds, ax
    xor  si, si        ; Better than 'mov si, 0` for zeroing a register
    xor  di, di        ; idem
program: 
    mov  al, nizA[si]
    test al, 1
    jz   IsEven
    mov  nizB[di], al  ; Only storing 'odd' values
    inc  di
IsEven:
    add  si, 2         ; Next 'even' index
    cmp  si, len
    jb   program

See how TEST AL, 1 is non-destructive on the AL register and that therefore you don't need to reload the value before writing to the nizB array?
Also note that you don't always need a separate loop counter. Here I have used the source array index instead.

  • Related