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
Related
I have a program that can add two arrays of binary numbers
I'm sorry, I'm not very good at asm
I can draw the conclusion myself, but to understand how to convert an array to a number, I don’t really understand how to do it
example:
section .text
global _start
_start:
mov esi, 0
mov ecx, len_arr_1
_add_two_array:
mov eax, 0
add al, [array_1 + esi]
add al, [array_2 + esi]
inc esi
mov [res + esi], ax
loop _add_two_array
mov esi, len_res - 1
_check:
Call update
dec esi
cmp esi, -1
jne _check
jmp output_set
update:
mov ebx, 2
cmp [res + esi], bl
jge return
ret
return:
sub [res + esi], bl
mov ebx, 1
add [res + esi - 1], bl
ret
output_set:
mov esi, 0
mov ecx, len_res
output:
push ecx
mov ecx, [res + esi]
inc esi
add ecx, 48
mov [msg], ecx
mov edx, msg_len
mov ecx, msg
mov ebx, 1
mov eax, 4
int 0x80
pop ecx
loop output
exit:
nop
mov eax, 1
mov ebx, 0
int 80H
section .data
array_1 db 1, 1, 0
len_arr_1 equ $ - array_1
array_2 db 0, 1, 1
len_arr_2 equ $ - array_2
res db 0, 0, 0, 0
len_res equ $ - res
msg db '', 0xa
msg_len equ $ - msg
```
output: 1010 // need 10
how to display the resulting answer by converting it to a decimal number?
You throw un-commented asm code at us without any description what with what and how it does or does not. Most of us will not bother to look further.
You should clarify for example what your array represents Is it bigint or something else? like fixed point, floating point ... Is it MSB first or last?
Here few things I noticed just by quick look without any deeper analysis (Assuming unsigned "big" int):
I do not see any carry propagation during long num addition
Only the first addition (lowest bit/word) should use add and all others should be adc !!! or all are adc if you clear carry flag before addition loop.
your input is array of BYTEs and output is array of WORDs ?
That makes no sense and even if it is then you inconsistently update esi as you use it for both BYTEs and WORDs at the same time while incrementing only by 1. If not then your target digits overlap as you write ax so depending on MSB first/last order you might overwrite already computed digits...
Your test case is wrong due to previous bullets !!!
You know 110b + 011b = 1001b however without the carry propagation from #1 you got 101b wrongly interpreted due #2 as 1010b ...
You never convert binary to decadic
Now you should convert base which you do not do anywhere. For integers That is done by dividing the number by printing base (10) and printing the remainders in reverse order. So if your number is not too big convert your result array to single register value (using bitshifts and or) and then convert to decadic string...
1001b -> 1<<3 | 0<<2 | 0<<1 | 1<<0 = 9 // conversion to single register
9 / 10 = 0 + remainder 9 -> "9" // division
If the result would be 1010b it would be:
1001b -> 1<<3 | 0<<2 | 1<<1 | 0<<0 = 10 // conversion to single
10 / 10 = 1 + remainder 0 -> "0" // division
1 / 10 = 0 + remainder 1 -> "10" // division
If the number is for examle 123:
123/10 = 12 remainder 3 -> "3"
12 /10 = 1 remainder 2 -> "23"
1 /10 = 0 remainder 1 -> "123"
In case your array is big (does not fit into single register) you have to implement bignum division too ...
You are failing in many things at once !!! You should focus on single stuff/task not all bugs together ... I would start with printing some register hardcoded value in binary first (ignore rest of code), then coumulate array to such value, and only then try addition...
Here is my old lib for printing numbers to strings in NASM I wrote decades ago (just digged it out of my archive so you have some inspiration):
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; txtnum: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
txtnum:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;.hex16 num ax >> string hex16 [cs:si], si=end of string adress at zero
;.dec16 num ax >> string dec16 [cs:si], si=end of string adress at zero
;.dec32 num eax >> string dec32 [cs:si], si=end of string adress at zero
;.txt32 num eax << string dec32 [cs:si], si=end of string adress after zero
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.hex16 pusha
mov cx,4
.hex16l:rol ax,4
mov bl,al
and bl,15
add bl,'0'
cmp bl,'9'
jbe .hex16r
add bl,'A'-'0'-10
.hex16r:mov [cs:si],bl
inc si
loop .hex16l
mov [cs:si],cl
popa
add si,4
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.dec16: push ax
push bx
push dx
mov bx,10
inc si
cmp ax,10
jb .dec16r
inc si
cmp ax,100
jb .dec16r
inc si
cmp ax,1000
jb .dec16r
inc si
cmp ax,10000
jb .dec16r
inc si
.dec16r:mov [cs:si],bh
push si
.dec16l:xor dx,dx
div bx
add dl,'0'
dec si
mov [cs:si],dl
cmp ax,0
jnz .dec16l
pop si
pop dx
pop bx
pop ax
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.dec32: push eax
push ebx
push edx
mov ebx,10
inc si
cmp eax,10
jb .dec32r
inc si
cmp eax,100
jb .dec32r
inc si
cmp eax,1000
jb .dec32r
inc si
cmp eax,10000
jb .dec32r
inc si
cmp eax,100000
jb .dec32r
inc si
cmp eax,1000000
jb .dec32r
inc si
cmp eax,10000000
jb .dec32r
inc si
cmp eax,100000000
jb .dec32r
inc si
cmp eax,1000000000
jb .dec32r
inc si
.dec32r:mov [cs:si],bh
push si
.dec32l:xor edx,edx
div ebx
add dl,'0'
dec si
mov [cs:si],dl
cmp eax,0
jnz .dec32l
pop si
pop edx
pop ebx
pop eax
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.txt32: push ebx
push ecx
push edx
mov eax,0
mov ebx,10
mov ecx,0
.txt32l:mov cl,[cs:si]
inc si
or cl,cl
jz .txt32e
cmp cl,'0'
jb .txt32e
cmp cl,'9'
ja .txt32e
sub cl,'0'
mul ebx
add eax,ecx
jmp .txt32l
.txt32e:or edx,edx
jz .txt32x
mov eax,-1
.txt32x:pop edx
pop ecx
pop ebx
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; end. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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
This question already has an answer here:
Problems with IDIV Assembly Language
(1 answer)
Closed 1 year ago.
The pseudocode is the following:
read c //a double digit number
for(i=1,n,i++)
{ if (n%i==0)
print i;}
In assembly I have written it as:
mov bx,ax ; ax was the number ex.0020, storing a copy in bx.
mov cx,1 ; the start of the for loop
.forloop:
mov ax,bx ; resetting ax to be the number(needed for the next iterations)
div cx
cmp ah,0 ; checking if the remainder is 0
jne .ifinstr
add cl 48 ;adding so my number would be displayed later as decimal
mov dl,cl ;printing the remainder
mov ah,2
int 21h
sub cl,48 ;converting it back to hexa
.ifinstr:
inc cx ;the loop goes on
cmp cx,bx
jle .forloop
I've checked by tracing its steps. The first iteration goes well, then, at the second one, it makes ax=the initial number and cx=2 as it should, but at 'div cx' it jumps somwhere unknown to me and it doesn't stop anywhere. It does:
push ax
mov al,12
nop
push 9
.
.
Any idea why it does that?
try to do mov dx,0 just before div instruction.
Basically every time you come after jump, there may be some data in dx register, so you can just move zero in dx or XOR dx,dx.
This is to be done, because otherwise division will be considered differently.
See this:
Unsigned divide.
Algorithm:
when operand is a byte:
AL = AX / operand
AH = remainder (modulus)
when operand is a word:
AX = (DX AX) / operand
DX = remainder (modulus)
Example:
MOV AX, 203 ; AX = 00CBh
MOV BL, 4
DIV BL ; AL = 50 (32h), AH = 3
RET
How could I do something like this in assembly? DOS 16bit graphic mode
int start_x=1, start_y=1;
for(int i=0; i<8; i++){
for(int j=0; j<8; j++){
if(T34[i][j]==1) put_colour_pixel(start_x+i, start_y+j);
else put_black_pixel(start_x+i, start_y+j);
}
}
:edit:
So my loops pretty work. How to connect it to table with 0 and 1.
mov ax, 10 ; Y start line
mov bx, 20 ; X start line
mov dl, 4 ; colour (red)
mov cx, 5 ; loop top counter
top:
add ax, 1
push cx ;loop top counter
mov cx, 10
inside:
add bx, 1
push ax
push bx
push cx
call putpixel
pop cx
pop bx
pop ax
loop inside
mov bx, 20 ;next line X go to start X
pop cx ;loop top counter
loop top
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
My new code:
segment .data
segment .code
..start:
mov ax, 13h
int 10h ; switch to 320x200 mode
mov ax, 0a000h ; The offset to video memory
mov es, ax ; We load it to ES through AX,
; because immediate operation
; is not allowed on ES
;;;;;;;;;;;;;;;;;;;;;;
mov di, T34
mov si, 8
;------------------------------------
P1: mov bp, 8
;----------------
P2: cmp BYTE[di], 1
jnz short NOHIT
NOHIT: ; increase the x position
push ax
push bx
push cx
mov ax,si ;Y
mov bx,bp ;X
mov dl, 1 ; here I should take '0' or '1' from table
call putpixel
pop cx
pop bx
pop ax
inc di ; increase offset address of array
dec bp
jnz P2
;-------------
; increase the y position + substract 8 from x position
dec si
jnz P1
;------------------------------------
;;;;;;;;;;;;;;;;;;;;;;;;;
xor ah, ah
int 16h ; keyboard (wait for key)
mov ax, 3
int 10h ; go to text mode
mov ax, 4c00h
int 21h ; return to DOS, exit code 0
;;;;;;;;;;;;;;;;;;;;;
putpixel:
push dx ; mul changes dx too
mov cx, 320
mul cx ; multiply Y (ax) by 320 (one row)
add ax, bx ; and add X (bx) (result= dx:ax)
mov di, ax
pop dx
mov [es:di], dl ; store color/pixel
ret
;;;;;;;;;;;;;;;;;;;;;;
T34 DB 1,1,1,1,1,1,1,1
DB 1,0,0,0,0,0,0,0
DB 1,0,0,0,0,0,0,0
DB 1,0,0,0,0,0,0,0
DB 1,1,1,1,1,1,1,1
DB 1,0,0,0,0,0,0,0
DB 1,0,0,0,0,0,0,0
DB 1,1,1,1,1,1,1,1
I have changed order and now it is drawing square in left corner (as I expected). Did I change order rigth?
I suppose that letter will be spinned, but it is not problem for me. I can fix it later.
Now I should go to '0' or '1' in table and set color. Which register have "0" or "1"?
So mostly I have problem with colour.
I have try this, but I have error. I have try set colour black (0) or blue (1)
push dx
mov ax, bp ; X*8
mov cx,8
mul cx
add ax, si ; X*8 +Y
add ax, di ; tab0 + X*8+Y
mov dl, ax; here is error, here I set the colour
pop dx
So I don't know how to fix it :( I have try different possibilities and northing work.
mov di, T34
mov si, 8
;------------------------------------
P1: mov bp, 8
;----------------
P2: cmp BYTE[di], 1
jnz short NOHIT
; save used REGISTER
; load register with the X,Y position and color
call putpixel
; get back the saved Register
NOHIT: ; increase the x position
inc di ; increase offset address of array
dec bp ; decrease counter and set zeroflag if register is zero
jnz P2 ; jump if zeroflag is not set
;-------------
; increase the y position + substract 8 from x position
dec si
jnz P1
;------------------------------------
It is also possible to start the counters for the loops with 0 for to increase the counter, but then we need a compare instruction for to leave the loop, if we want to run the loop from 0 to 8. The offset addresses inside of the array are pointed independent with no relationship to the counters.
With a little modifying (put an additional jump instruction in the code and a second call) it is also possible to set a black pixel if the byte of the array is 0. But i think this simple form of a nested loop is easier to understand in the first time.
Edit: Now it is compatible for NASM.
Edit2: Maybe it is more simple to store the x,y coordinates into a known ram location for modifying and reloading inside of a loop, if many parameters are in use.
Our ram location:
Color DB ? ; define byte
X_Pos DW ? ; define word
Y_Pos DW ?
Examples for to show how to access a memory location (default segment is DS):
mov [X_Pos], ax
mov [X_Pos], bx
mov [Color], dl
mov ax, [X_Pos]
mov bx, [Y_Pos]
mov dl, [Color]
mov WORD[X_Pos], 10
inc WORD[X_Pos]
sub WORD[X_Pos], 8
mov BYTE[Color], 4
inc BYTE[Color]
Edit3:
mov dl, ax; here is error, here I set the colour
It is not possible to mix an 8 bit register with a 16 Bit register.
Note:
AX = AL+AH
DX = DL+DH
Existing instruction are:
mov dl, al
mov dl, ah
mov dx, ax
movzx dl, ax
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.