I am writing .asm for 8086 using emu8086.
I want to loop over an array of bytes, using the loop
instruction. Inside the loop I want to access the data in the array, in order (from the lowest memory address to the highest).
I can do it with the following code:
array DB 9,1,4,7,2
length DW 5
mov cx, length ;cx <-- desired iterations
lea si, array ;si <-- address of first array byte
my_loop: mov al, [si] ;load from array
;perform operations
;on AL here
inc si ;si points to the next array element
loop my_loop
I am wondering if there is a better way to do it exploiting just one register, since CX and SI are basically doing the same job (the offset from the first array element stems naturally from the iteration count).
In this example at each iteration the values of CX and SI will be the following:
CX: [5, 4, 3, 2, 1]
SI: [array + 0, array + 1, array + 2, array + 3, array + 4]
Now at each iteration the value of SI is given by the formula si = addr(array) + length - cx
where array
and length
are known at compile time.
Inside the loop this would look like (this syntax explains what I want to do but is most likely wrong):
mov al, offset(array) + length - cx
I am a newbie with addressing modes. Is there a way to avoid using SI altogether or can you explain why it's unavoidable to use it?
array DB 9,1,4,7,2 length DW 5
array
andlength
are known at compile time.
There's a good reason to not define length as a memory-based variable, but rather as an equate by writing: length equ $ - array
.
I want to loop over an array of bytes, using the
loop
instruction.
If you insist on using loop
, then you will have to use an additional register. On 8086, the CX register can never be used in an addressing mode.
I am a newbie with addressing modes, is there a way to avoid using SI altogether or can you explain why it's unavoidable to use it?
The SI register is not unavoidable, since on 8086 you can replace it by BX, DI, and even BP. (BP is special because it uses the SS segment register by default, so don't use it as your first choice!)
I am wondering if there is a better way to do it exploiting just one register
You can quite easily write the loop using a single address register (one of BX, SI, DI, or BP). Below are some methods:
xor bx, bx ; 0
my_loop:
mov al, [array + bx]
...
inc bx ; Increment the 'offset' BX
cmp bx, length ; 5
jb my_loop ; Loop for as long as BX below 5
and:
mov bx, OFFSET array
my_loop:
mov al, [bx]
...
inc bx ; Increment the 'address' BX
cmp bx, OFFSET array + length
jb my_loop ; Loop for as long as BX below (array + 5)
and as suggested by @ecm and @PeterCordes (shaving off an instruction):
mov bx, -length
my_loop:
mov al, [array + length + bx]
...
inc bx ; Increment the 'offset' BX
jnz my_loop ; Loop for as long as BX negative [-5,-1]
Inside the loop I want to access the data in the array, in order (from the lowest memory address to the highest).
That's a pity (but not so much), because if it were allowable for the task at hand, you could reverse the direction and shave off an instruction:
mov bx, length - 1 ; 5 - 1
my_loop:
mov al, [array + bx]
...
dec bx ; Decrement the 'offset' BX
jge my_loop ; Loop for as long as BX positive [0,4]