Arrays and addressing modes

Intermediate

An array is a run of bytes or words in memory, one after another. To reach element i, the CPU adds an offset to the array's start. The ways an operand can be named are the addressing modes:

ModeExampleThe operand is
immediateMOV AL, 5the number itself
registerMOV AL, BLa register
directMOV AL, LISTthe memory at LIST
register indirectMOV AL, [BX]the memory at the address in BX (or SI, DI)
basedMOV AL, [BX + 2]at BX + 2
indexedMOV AL, LIST[SI]at LIST + SI
based-indexedMOV AL, [BX + SI]at BX + SI (plus a number, if given)

Inside the brackets the 8086 accepts only BX or BP (a base) and SI or DI (an index), added together with a number. [AX], [CX] and [BX + BP] are not allowed, and StepVioz says so. BP is special: [BP] reads the stack segment, as lesson 12 uses.

Walking an array

To visit every element, keep its index in SI (or its address in BX) and count with CX:

; Add up a byte array and print the sum.
.MODEL SMALL
.STACK 100H
.DATA
    LIST DB 12, 7, 30, 5, 21
    N    EQU 5
.CODE
MAIN PROC
    MOV AX, @DATA
    MOV DS, AX
    MOV AL, 0          ; the sum
    MOV SI, 0          ; the index
    MOV CX, N
ADDUP:
    ADD AL, LIST[SI]   ; indexed: LIST + SI
    INC SI
    LOOP ADDUP
    AAM                ; 75 -> AH = 7, AL = 5
    MOV BX, AX
    MOV DL, BH
    ADD DL, '0'
    MOV AH, 2
    INT 21H
    MOV DL, BL
    ADD DL, '0'
    INT 21H
    MOV AH, 4CH
    INT 21H
MAIN ENDP
END MAIN
Open in compiler

The sum here is below 100, so AAM can print it in two digits.

Word arrays

A word is 2 bytes, so element i of a DW array is at offset 2 × i: add 2 to SI each time, not 1.

; Find the largest value in a word array and print it.
.MODEL SMALL
.STACK 100H
.DATA
    NUMS DW 320, 1450, 98, 1203
    N    EQU 4
.CODE
MAIN PROC
    MOV AX, @DATA
    MOV DS, AX
    MOV AX, NUMS       ; the largest so far: the first element
    MOV SI, 2          ; words: the next element is 2 bytes on
    MOV CX, N - 1
FIND:
    CMP AX, NUMS[SI]
    JAE KEEP           ; unsigned: AX is already as large
    MOV AX, NUMS[SI]
KEEP:
    ADD SI, 2
    LOOP FIND
    MOV BX, 10         ; print AX in decimal
    MOV CX, 0
DIGITS:
    MOV DX, 0
    DIV BX
    PUSH DX
    INC CX
    CMP AX, 0
    JNE DIGITS
SHOWIT:
    POP DX
    ADD DL, '0'
    MOV AH, 2
    INT 21H
    LOOP SHOWIT
    MOV AH, 4CH
    INT 21H
MAIN ENDP
END MAIN
Open in compiler

MOV AX, NUMS reads the first element; CMP AX, NUMS[SI] compares with element SI ÷ 2. The answer, the largest value, is printed with the divide-by-10 method from lesson 8.

Common mistakes

  • Stepping through a word array by 1: element i is at 2 × i.
  • Using [AX] or [CX]: only BX, BP, SI and DI can point into memory.
  • Reading one element too many: with n elements and CX = n, start at index 0, not 1.
  • Using MOV SI, LIST (the first element's value) when you meant LEA SI, LIST (its address).

Quick check

1. Which of these is a valid 8086 memory operand?
2. NUMS DW 10, 20, 30. At what offset from NUMS is the third element?
3. SI = 2. Which element of LIST DB 7, 8, 9 does LIST[SI] read?
4. What is the difference between MOV BX, LIST and LEA BX, LIST?

Practice problems for this lesson

My notes

Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.