Incrementing a pointer by 1 in an array of words: loading a word from half way between two words? - arrays

Consider the code below. If incrementing SI by 2 gives me the 2nd element of the array, what exactly would incrementing SI by 1 give me?
.data
var dw 1,2,3,4
.code
LEA SI,VAR
MOV AX,[SI]
INC SI
MOV AX,[SI]

Statement var dw 1,2,3,4 tells the assembler to statically define eight bytes in memory at the beginning of .data segment. Layout of the data bytes will be
|01|00|02|00|03|00|04|00|
and the first MOV AX,[SI] will load AL with 01 and AH with 00.
When you increment SI only by 1, the next MOV AX,[SI] will load AL with 00 and AH with 02.
If you want to keep loading AX with the whole 16bit words, increment SI by 2 (ADD SI,2).
You could also replace both MOV AX,[SI] and ADD SI,2 with one single instruction LODSW which does the same and occupies only one byte instead of five. In this case you should be sure to have the Direction flag reset (using the instruction CLD in the beginning of your program).

Related

assembly 8086 multiply even elements and data segment

As a part of my homework I need to initialize two one dimensional arrays, every with 10 2B terms, to multiply every even term with 2. I found some codes, but I dont understand part of initializing arrays in memory.
In next part of example, after this queastion, what does it mean MOV AX,PODACI?
does it moves only address of first term in array TABELA and TABELA1 in AX
or it moves first element in array TABELA and TABELA1 in AX (would that be possible in my case, because of size of AX, I have dw type of data?)
Is it necessarry to define only arrays in DATA SEGMENT if address is used as in question above (I need to find max and min element and according to that plan to define also min_niz1 dw ? and max_niz1 dw ? in data segment, is that possible if I am using MOV AX,PODACI)?
What does it mean MOV SI, OFFSET TABELA and MOV DI, OFFSET TABELA1, would that move offset address in SI and DI and what will be in AL and BL later?
:
PODACI SEGMENT 'DATA'
TABELA DB 3Fh, 06h, 5Bh, 4Fh, 66h, 6Dh, 7Dh, 27h, 7Fh, 6Fh
TABELA1 DB 3Fh, 05h, 5Bh, 04h, 03h, 6Dh, 7Dh, 27h, 01h, 6Fh
PODACI ENDS
PROGRAM SEGMENT 'CODE'
ASSUME CS:PROGRAM,DS:PODACI
START: MOV AX,PODACI
MOV DS,AX
MOV SI,0
MOV DI, 0
MOV CX, 10
MOV SI, OFFSET TABELA
MOV DI, OFFSET TABELA1
petlja: MOV AL, [SI]
MOV BL, [DI]
CMP AL, BL
JNZ nije
INC DX
nije: INC SI
INC DI
loop petlja
PROGRAM ENDS
END START
As second part, I need to multiply even terms in arrays with 2, is that possible with this part of code which is below?
mov ax,niz1[di]
add ax,ax
mov niz1[di],ax
I dont know is that correct way to use only even terms of array, and to put back new value in my array?
I tried to execute this with emu 8086 but solution is not obvious for me.
even:
MOV DI, 0
mov ax,niz1[di]
add ax
mov niz1[di],ax
inc di
inc di
cmp di,11
jle even:
The program you studied
In next part of example, after this queastion, what does it mean MOV AX,PODACI?
The pair of instructions
mov ax, PODACI
mov ds, ax
is used to setup the DS segment register so that it points at your program's DATA section.
What does it mean MOV SI, OFFSET TABELA and MOV DI, OFFSET TABELA1, would that move offset address in SI and DI and what will be in AL and BL later?
MOV SI, OFFSET TABELA
MOV DI, OFFSET TABELA1
will load SI and DI with the offsets to both arrays, offsets within the DATA section.
MOV AL, [SI]
MOV BL, [DI]
will load AL and BL each with one byte-sized element of each array.
Your task
I need to initialize two one dimensional arrays, every with 10 2B terms, to multiply every even term with 2
To initialize your new arrays with 10 2B terms, you would use the DW directive:
niz1 dw 100,200,300,400,500,600,700,800,900,1000
The subscripts for all the elements in this array are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
The even terms are those elements that have array subscripts that are even, so the array elements 0, 2, 4, 6, 8.
Because each array element occupies 2 bytes in memory, the offsets where you'll find these elements are 0, 4, 8, 12, 16. Remember that in assembly programming the value that appears between the square brackets (niz1[di]) is an offset in memory and not an array subscript like in high level programming languages.
xor di, di ;Similar to "MOV DI,0".
Even:
shl niz1[di], 1 ;Doubles this element.
add di, 4 ;Goes to next 'even' term.
cmp di, 20 ;Total size of the array.
jb Even ;Repeat as long as we're IN the array.
Please note that your solution to multiply even terms in arrays with 2
mov ax,niz1[di]
add ax !!! typo?
mov niz1[di],ax
is fine, but doubling through shifting to the left is better.
Good luck turning this into a working program.
(Every program needs an exit to the OS, here it's DOS...)

Wrong result in multiplying in 8086 assembly

The program must calculate the following:
in VP array , each index will have the value of Multiplying V1[INDEX] WITH V2[INDEX]
in VPROD array , the program ADDS all the Values of Array VP
Example:
VP = { V1[0]*V2[0] , V1[1]*V2[1] , V1[2]*V2[2] , V1[3]*V2[3] ,V1[4]*V2[4] }
VPROD = { VP[0] + VP[1] + VP[2] + VP[3] + VP[4] }
The problem is that when the result is bigger than 16 bits (a word), it does not give the right results. But when the result is smaller than 16 bits, it gives the right result.
I thought about Carry and fixed my code, but still it gives me bad results.
My code:
dseg segment
v1 DW 255,5,255,9,21
v2 DW 4,4,255,13,5
vprod DW 10 DUP (0)
vp DW 10 DUP (?)
N DB 5
dseg ends
sseg segment stack
dw 100h dup(?)
sseg ends
cseg segment
assume ds:dseg,cs:cseg,ss:sseg
start: mov ax,dseg
MOV DS,AX
MOV SI,0
MOV CX,0
MOV CL,N
MOV DI, 0
LOVP: MOV AX,v1[si]
MUL v2[si]
MOV vp[di],AX
MOV vp[di+2],DX
ADD SI,2
ADD DI,4
LOOP LOVP
MOV CX,0
MOV CL,N
MOV SI,0
MOV DI,0
LOVPROD: MOV AX,vp[SI]
ADD vprod[DI],AX
ADC VPROD[DI+2],0
ADD SI,2
LOOP LOVPROD
SOF:
mov ah,4ch
int 21h
cseg ends
end start
Since you are getting a 32 bit result from the multiply, you should use 4 bytes for every element of the vp array. You will need to use a separate index for that, and of course store the high word at offset +2 instead of +1. For the summation part, you should add up both low and high words.
Fixed code for the multiplication could look like:
MOV DI, 0
LOVP: MOV AX,v1[si]
MUL v2[si]
MOV vp[di],AX
MOV vp[di+2],DX
ADD SI,2
ADD DI,4
LOOP LOVP
I trust you can do the summation yourself, using ADD and ADC.
UPDATE:
Since your post says you want to sum the vp array, I don't see why you expect the result in another array (vprod). The sum is a scalar value, do something like:
MOV SI, 0
MOV AX, 0
MOV DX, 0
LOVPROD: ADD AX,vp[SI]
ADC DX,vp[SI+2]
ADD SI,4
LOOP LOVPROD
The result will be in DX:AX
Also, for the LOOP to work properly, you should put the number of iterations into CX, not 0 as you are doing.

Sum of a word array not storing in another word array

*The task assigned to me twas to write an assembly program that finds the sum of three 8-bits values and places it in memory at location SUMS. Then compute sum of three word variable, and place it in memory at location SUMS + 2. Use the following data:
BYTE_ARRAY DB 10H,20H,30H
WORD_ARRAY DW 1000H,2000H,3000H
SUMS DW 0,0*
My problem is that the following code gives me an error
mov sums,al
I understand that one is a 16 bit address and the other is 8 bit address but is there any other way to get around it?
EDIT:
Complete code:
org 100h
.data
byte_array db 10h,20h,30h
word_array dw 1000h,2000h,3000h
sums dw 0,0
.code
mov ax,#data
mov ds,ax
mov bx,offset byte_array
mov al,[bx]
inc bx
add al,[bx]
inc bx
add al,[bx]
mov si,offset sums
mov [si],al
mov bx,offset word_array
mov ax,[bx]
add ax,[bx+2]
add ax,[bx+4]
mov [bx+6], ax
ret
My only problem that remains is that i do not understand the meaning of SUMS + 2. What is the questions asking me to do?
al is 8 bits.
sum is 16 bits.
so they have conflict.
SUMS DW 0,0
mov sums,al
As you declared your array being of word size, your operand should match that.
mov sums, ax

8086 assembly - how to access array elements within a loop

Ok, to make things as simple as possible, say I have a basic loop that i want to use in order to modify some elements of an array labeled a. In the following sample code I've tried replacing all elements of a with 1, but that doesn't really work.
assume cs:code ,ds:data
data segment
a db 1,2,3,4
i db 0
data ends
code segment
start:
mov ax,data
mov ds,ax
lea si,a
the_loop:
mov cl,i
cmp cl,4
jae the_end
mov ds:si[i],1 ; this is the part that i don't really understand since
inc i ; i'm expecting i=0 and ds:si[i] equiv to ds:si[0] which
loop the_loop ; is apparently not the case here since i actually receives the
; the value 1
the_end:
mov ax,4c00h
int 21h
code ends
end start
I am aware that I could simply do this by modifying the element stored in al after the lodsb instruction, and just store that. But I would like to know if it is possible to do something like what I've tried above.
In x86 assembly you can't use a value stored to a memory to address memory indirectly.
You need to read i into some register that can be used for memory addressing, and use that instead. You may want to check Wikipedia for 8086 memory addressing modes.
So, replace
mov ds:si[i],1
with (segment ds is unnecessary here, as it's the default of si, bx and bx+si too):
xor bx,bx
mov bl,[i]
mov [bx+si],byte 1 ; some other assemblers want byte ptr
There are other problems with your code too. The entire loop can be made easier and fixed this way:
lea si,a
xor cx,cx
mov cl,[i]
#fill_loop:
mov [si], byte 1
inc si
dec cx
jnz #fill_loop
Or, if you want to save 1 byte and use loop instruction.
#fill_loop:
mov [si], byte 1
inc si
loop #fill_loop
Note that in 16-bit mode loop instruction decrements cx and jumps to label if cx is not zero after decrement. However, in 32-bit mode loop decrements ecx and in 64-bit mode (x86-64) it decrements rcx.
I suppose that your code does not even run through the assembler, since
mov ds:si[i],1
is not a valid address mode.
Use something like
mov byte ptr [si],1 ; store value 1 at [SI]
inc si ; point to next array element
instead (used MASM to verify the syntax).
The DS: prefix is unnecessary for [si] since this is the default.
See also The 80x86 Addressing Modes.

Displaying hexadecimal contents in assembly language

Hey guys I'm not sure if I'm going about all this the right way. I need the first 12 numbers of Fibonacci sequence to calculate which its doing already I'm pretty sure. But now I need to display the hexadecimal contents of (Fibonacci) in my program using dumpMem. I need to be getting a print out of : 01 01 02 03 05 08 0D 15 22 37 59 90
But I'm only getting: 01 01 00 00 00 00 00 00 00 00 00 00
Any tips or help is much much appreciated.
INCLUDE Irvine32.inc
.data
reg DWORD -1,1,0 ; Initializes a DOUBLEWORD array, giving it the values of -1, 1, and 0
array DWORD 48 DUP(?)
Fibonacci BYTE 1, 1, 10 DUP (?)
.code
main PROC
mov array, 1
mov esi,OFFSET array ; or should this be Fibonacci?
mov ecx,12
add esi, 4
L1:
mov edx, [reg]
mov ebx, [reg+4]
mov [reg+8], edx
add [reg+8], ebx ; Adds the value of the EBX and 'temp(8)' together and stores it as temp(8)
mov eax, [reg+8] ; Moves the value of 'temp(8)' into the EAX register
mov [esi], eax ; Moves the value of EAX into the offset of array
mov [reg], ebx ; Moves the value of the EBX register to 'temp(0)'
mov [reg+4], eax ; Moves the value of the EAX register to 'temp(4)
add esi, 4
; call DumpRegs
call WriteInt
loop L1
;mov ebx, offset array
;mov ecx, 12
;L2:
;mov eax, [esi]
;add esi, 4
;call WriteInt
;loop L2
;Below will show hexadecimal contents of string target-----------------
mov esi, OFFSET Fibonacci ; offset the variables
mov ebx,1 ; byte format
mov ecx, SIZEOF Fibonacci ; counter
call dumpMem
exit
main ENDP
END main
It seems to me that the problem here is with computing the Fibonacci sequence. Your code for that leaves me somewhat...puzzled. You have a bunch of "stuff" there, that seems to have nothing to do with computing Fibonacci numbers (e.g., reg), and others that could, but it seems you don't really know what you're trying to do with them.
Looking at your loop to compute the sequence, the first thing that practically jumps out at me is that you're using memory a lot. One of the first (and most important) things when you're writing assembly language is to maximize your use of registers and minimize your use of memory.
As a hint, I think if you read anything from memory in the course if computing the sequence, you're probably making a mistake. You should be able to do all the computation in registers, so the only memory references will be writing results. Since you're (apparently) producing only byte-sized results, you should need only one array of the proper number of bytes to hold the results (i.e., one byte per number you're going to generate).
I'm tempted to write a little routine showing how neatly this can be adapted to assembly language, but I suppose I probably shouldn't do that...
Your call to dumpMem is correct, but your program is not storing the results of your calculations at the correct location: the region you call "Fibonacci" remains initialized to 1, 1, and ten zeros. You need to make sure that your loop starts writing at the offset of Fibonacci plus 2, and moves ten times in one-byte increments (ten, not twelve, because you provided the two initial items in the initializer).
I'm sorry, I cannot be any more specific, as any question containing the word "Fibonacci" inevitably turns out to be someone's homework :-)

Resources