Wrong result in multiplying in 8086 assembly - arrays

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.

Related

how to check if 2 numbers have reversed bits in assembly?

My code should get 2 arr with the same length(k) and to check how much pairs of numbers have the same index (1 in arr 1 and the other in arr2) and are opposite, which means the first bit in 1 should be the last in the other and the second to first would be the second to first and go on...
Overall, this is my code:
IDEAL
MODEL small
STACK 100h
DATASEG
k dw 2 ;length of arr1 and arr2
ARR1 dw 2 dup (?)
ARR2 dw 2 dup (?)
CODESEG
start:
mov ax,#data
mov ds,ax
lea si,[ARR1]
lea di,[ARR2]
mov cx,k ; cx=length of arr
xor dx,dx
mov [ARR1],1000000000000001b
mov [ARR2],1000000000000001b
mov [ARR1+1],0033h
mov [ARR2+1],0033h
xor dx,dx
L1: ; loops through every index in both arr1, and arr2
mov bx,k
sub bx,cx
push cx
mov cx,16
L2:
xor ax,ax
shr [si+bx],1
jnc nc1
inc al
nc1:
clc
shl [di+bx],1
jnc nc2
inc ah
nc2:
clc
cmp al,ah
jne end_loop2
dec cx
jnz L2
inc dx
end_loop2:
pop cx
dec cx
jnz L1
exit:
mov ax, 4c00h
int 21h
END start
My debugger doesn't give me any errors but when I run the code it doesn't work, when I shift left the number in arr 2 it doesn't change the CF though it should.
Do you know why is that happening?
mov [ARR1],1000000000000001b
mov [ARR2],1000000000000001b
mov [ARR1+1],0033h
mov [ARR2+1],0033h ; ARR1/ARR2 contain 1, 51, 0, ?
Your program defines 2 arrays that have each 2 word-sized elements. Because a word occupies 2 bytes in memory, assigning a value to the 2nd element must use an offset of +2. Assigning a value to the 3rd element would have to use an offset of +4, and so on.
mov [ARR1], 8001h
mov [ARR2], 8001h
mov [ARR1+2], 0033h
mov [ARR2+2], 0033h ; ARR1/ARR2 contain 1, 128, 51, 0
L1:
mov bx,k
sub bx,cx
The inner loop (L2) is processing words but the outer loop (L1) advances through the array per byte. On the 1st outer iteration CX is 2 so BX = k - CX becomes 0, and on the 2nd outer iteration CX=1 so BX = k - CX becomes 1 which then will begin processing a word composed of the high byte from the 1st array element together with the low byte from the 2nd array element.
The good news is that you don't need that convoluted way (using BX) to walk through these arrays. Just add 2 to SI and DI on every iteration of the outer loop.
Your program contains a number of redundant instructions like xor dx, dx and unnecessary instructions like clc. For clarity you should remove these unproductive lines.
to check how much pairs of numbers have the same index (1 in arr 1 and the other in arr2) and are opposite
Knowing that the arrays hold each 2 elements, this means that the final result of your program will have to be a number in the range [0,2].
Without the forementioned errors your program would have worked fine, except that a solution that wipes out the arrays is not something I would have chosen.
Below is my implementation. Read the tail comments carefully!
lea si, [ARR1] ; SI is address of 1st array
mov [si], 8001h ; Assign 1st element
mov [si+2], 0033h ; Assign 2nd element
lea di, [ARR2] ; DI is address of 2nd array
mov [di], 8001h ; Assign 1st element
mov [di+2], 0033h ; Assign 2nd element
mov bp, k ; Number of array elements
xor dx, dx ; Final result (will be 1 based on the fixed data)
L1:
mov cx, [di] ; CX is current element from 2nd array
mov bx, [si] ; BX is current element from 1st array
xor ax, ax ; AL is status byte, AH is a convenient 0
L2:
shr bx, 1 ; The bit that comes out of BX
adc al, ah ; is added to AL (that was zeroed beforehand)
shl cx, 1 ; The bit that comes out of CX (at the opposite side)
sbb al, ah ; is subtracted from AL
jnz NOK ; If both bits matched then AL would still be zero
test bx, bx ; Has BX more ON bits ?
jnz L2 ; Yes
; Early exiting if BX has no more ON bits
; If, at the same time, CX too has no more ON bits
; then an OK pair was found
test cx, cx
jnz NOK
OK:
inc dx ; Found an OK pair
NOK:
add si, 2 ; Next array element is 2 bytes higher in memory
add di, 2
dec bp ; Repeat for every element in the array(s)
jnz L1
If implemented serially, the inner loop can be squeezed at least to
again:
add ax,ax ; shift ax, while moving MSB to carry
sbb bx, 0 ; subtract carry (i.e 0 or 1) from bx
; here the LSB of bx will be 0 afterwards,
; iff the top bit of ax == lsb of bx
; in this case the top 15 bits of bx will
; be preserved for further iterations
shr bx, 1 ; now we shift out the LSB, setting CF on failure
jc not_ok
jnz again ; there are further bits on bx to check
;
test ax,ax ; we need to check that ax == 0, when bx == 0
jnz not_ok ;
ok: ; there was full match
I think a separate early exit on AX would not make much sense, but one could sort the inputs, placing BX <= AX, so BX would run out of bits sooner.
Using the parity flag as in how-to-exchange-between-2-bits-in-a-1-byte-number, one can simplify the inner loop greatly:
ok = (bitreverse(al) == bh) && (bitreverse(bl) == ah)
With the following implementation one does not even need any other registers, than ax = input0, bx = input1.
test al, 0x81
jpe 1f // parity even IFF al == 0x81 OR al == 0
xor al, 0x81 // toggle bits 0x80 and 0x01, if there was only 1 bit
1: test al, 0x42
jpe 2f
2: xor al, 0x42
test al, 0x24
jpe 3f
3: xor al, 0x24
test al, 0x18
jpe 4f
xor al, 0x18
4: cmp al, bh
jnz NOT_OK
// and same for the pair bl, ah

Did the low register and high register swap places?

IDEAL
MODEL small
STACK 100h
jumps
p186
DATASEG
array dw 312, 340, 311, 300
CODESEG
proc example
pusha
mov al ,4 ;number of elements in array
mov bl, 0 ;index
label1:
mov cx, [array + bx] ;here, every second element ch and cl are swapped
inc bl
cmp bl, al
jb label1
popa
ret
endp example
start:
mov ax, #data
mov ds, ax
call example
exit:
mov ax, 4c00h
int 21h
END start
In my assembly code, cx is okay in the 1st and 3rd iterations but in the 2nd and 4th ones for some reason cl and ch swapped their values with each other. I'm really overwhelmed with this and I would appreciate some help, thanks!
The elements of array are words, 2 bytes each, but you only increment your index bx by 1 on each iteration of your loop. Addresses on x86 are in units of bytes, so on the next loop iteration, you load from the middle of the word, and you end up with one byte from one element and another byte from the other.
Probably simplest to do everything in terms of bytes, instead of elements. (In 32- or 64-bit code you could use the scale addressing mode, mov cx, [array+ebx*2], and then keep counting ebx in elements, but that's not available in 16-bit real mode.)
Also, the high half of bx is uninitialized. It's probably best to just use 16-bit values for your indices.
I'd rewrite as (untested):
CODESEG
proc example
pusha
mov ax, 4*2 ;number of bytes in array
mov bx, 0 ;index
label1:
mov cx, [array + bx]
; presumably do something with cx here
add bx, 2
cmp bx, ax
jb label1
popa
ret
endp example

Why am I not getting an output to my program to find the minimum value in a given array in 8086 emulator?

I am trying to find the smallest value in a given array, and the code I used is this
MOV SI,500
MOV CL,[SI]
MOV CH,00
INC SI
MOV AL,[SI]
DEC CL
INC SI
L1:CMP AL,[SI]
JNC SKIP
MOV AL,[SI]
SKIP:INC SI
LOOP L1
MOV [600],AL
HLT
It compiles fine and runs fine, then I go to "aux" and then to "memory" to type in my input values. I set the address as 0100:0500 and then I give input "01" "02" "03" "04" "05" then against the first row, like this -- https://i.imgur.com/Lrg23B2.png and i click update, and then "RUN" and then go to aux-->memory and check the address 0600, which is where i guess the output would be, and i get just zeroes, like this --- https://i.imgur.com/z2CCtBA.png what is wrong with my code? why am i not getting the minimum value and just zeroes in 0600? I am a total beginner to the 8086 programming, please help.
Don't you need setting the DS segment register to 0100h on top of your program?
You clearly expect to address memory at 0100h:0500h.
Don't you have to use the hexadecimal suffix?
MOV SI,500 uses a decimal 500; you need MOV SI,0500h for hexadecimal!
Note: If you're using a debugger then the hexadecimal notation could well be the default. If you're using a normal assembler then using the correct prefix or suffix is essential.
The loop runs for much too long!
MOV SI,500
MOV CL,[SI] <<<< If THIS reads 01 as is expected...
MOV CH,00
INC SI
MOV AL,[SI]
DEC CL <<<< then THIS will produce 0
INC SI
L1:CMP AL,[SI]
JNC SKIP
MOV AL,[SI]
SKIP:INC SI
LOOP L1 <<<< So THIS runs 65536 times.
MOV [600],AL
HLT
In order to find the minimum you will have to change the jnc skip instruction to jb skip. Currently you're looking for the maximum.
This is a version that you could try. As always: don't just copy but try to understand how it works.
mov ax, 0100h
mov ds, ax
mov si, 0500h
mov cx, 5 ;The number of values in the array
mov al, 255 ;This will become the mininum
L1:
cmp al, [si]
jb SKIP
mov al, [si]
SKIP:
inc si
loop L1 ;This now runs 5 times.
mov [0600h], al
hlt
It would be a good idea to try the code with data that is a bit more random. Perhaps use 3, 2, 5, 1, 4.

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...)

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

Resources