Related
Following is the code I wrote to find LCM of two numbers in EMU8086. When I ran it, I am getting value 0 in the Ans variable.
.MODEL SMALL
.DATA
Num1 DW 250
Num2 DW 100
Ans DW ?
.CODE
MOV AX,#DATA
MOV DS, AX
MOV AX, Num1
MOV BX, Num2
MOV DX, 0000h
NEXT: PUSH AX
PUSH DX
DIV BX
CMP DX, 0000h
JZ LAST
POP DX
POP AX
ADD AX, Num1
JNC NEXT
INC DX
JMP NEXT
LAST: POP Ans+2
POP Ans
MOV AH, 4Ch
INT 21h
END
LCM(a, b) = a * b / GCD(a, b)
Due to this equation, you can find GCD using Euclid's algorithm and then calculate LCM. Assuming numbers a and b are in al and dl, this code calculate LCM.
; Save multiplication value
MOV AL, DL ; This 2 lines is AL * DH
MUL DH
PUSH AX ; Store result in stack
FINDBCD: ; General idea is : LCM(a, b) = a*b/BCD(a,b)
; We calculate BCD with euclidean algorithm
CMP DH, DL
JNS CALCULATE ; Jump if DL < DH else swap them
MOV CL, DL ; This 3 line swap DL and DH
MOV DL, DH
MOV DH, CL
CALCULATE:
MOV AL, DH ; Move greater number in AL
XOR AH, AH ; Zero AX 8 second bits
DIV DL ; This is AL/DL
CMP AH, 0 ; If remainder is zero so we found BCD
JE AFTERFINDBCD
SUB DH, DL ; Else substract smaller number from greater number
JMP FINDBCD ; Do this until find BCD
AFTERFINDBCD:
CMP DH, DL
JNS FINDLCM ; Jump if DL < DH
MOV CL, DL ; This 3 line swap DL and DH
MOV DL, DH
MOV DH, CL
FINDLCM:
POP AX ; Retreive multiplication result
DIV DL ; This is AX/DL
AND AX, 0000000011111111B ; Ignore remainder
So we have like this safes challenge in assembly, you need to create safes and keys that will break them and end the infinite loop.
Here's an example for a safe:
loopy:
mov ax, [1900]
cmp ax,1234
jne loopy
and a key:
loopy2:
mov ax, 1234
mov [1900],ax
jmp loopy2
So I have a safe and a key, and I don't understand why it doesn't work:
here's my safe:
org 100h
mySafe:
mov dx,5
mov ax, [5768h]
mov bx,7
mov word [180h],2
mul word [180h]
mov [180h],bx
push ax
dec bx
mov cx,dx
mov ax,dx
loopy1:
add bx,ax
loop loopy1
dec bx
pop ax
add ax,bx
mul word [180h]
cmp ax,350
jne mySafe
And here's my key:
org 100h
loopy:
mov word [5768h],10
jmp loopy
ret
The right answer to break the loop should be 10 and it works when I put in on the safe, somehow with the key it doesn't work and I can't figure out why..
(the "word" is needed for nasm)
The value in dx used as the counter for the loop instruction comes from the first mul instruction.
This multiplication is just doubling the key, so dx is either 0 or 1 (an easy way to see this is to think of the multiplication as a left shift by one or by remembering that the sum of two n-bit numbers has at most n+1 bits)
If dx is zero, the whole loopy1 block does nothing (as dx also sets ax) and the value in ax at the end of the safe is 7*(5 +2k) where k is the key (see the commented code below).
It is then easy to see that 350 = 7*(5+2k) => 2k = 45 has no solution. Therefore no key for which dx is zero can unlock the safe.
A key has dx 0 iif its value is less than 32768 (again, this is easy to see when thinking of the multiplication as a left shift by one).
Corollary: 10 cannot be a solution.
safe:
mov dx,5
mov ax, [k] ;ax = k (key)
mov bx,7
mov word [aux],2
mul word [aux] ;dx = 0 ax = 2k
mov [aux],bx ;aux = 7
push ax ;ax = 2k
dec bx ;bx = 6
dec bx ;bx = 5
pop ax ;ax = 2k
add ax,bx ;ax = 5 + 2k
mul word [aux] ;ax = 7*(5 +2k)
cmp ax,350
ret
If there is a key that unlocks the safe then it must be greater or equal to 32768 so that dx is 1 after the first multiplication.
With this condition, the value in ax at the end of the safe can be written as 7*(6 + (2k & 0xffff)) => k & 0x7fff = 22.
Adding the condition stated at the very beginning of this section, the final value for k is 32768 + 22 = 32790 or 0x8016 in hex.
I've leaped quite a few logical steps in manipulating the equation and forming the result but, again, thinking of 2k as a shift may help visualize them.
Corollary: Due to the algebraic structure involved, this is the only solution.
safe:
mov dx,5
mov ax, [k] ;ax = k
mov bx,7
mov word [aux],2
mul word [aux] ;dx:ax = 2k
mov [aux],bx ;[aux] = 7
push ax ;dx = 1 ax = 2k & 0xffff
dec bx ;bx = 6
mov cx,dx ;cx = 1
mov ax,dx ;ax = 1
loopy1:
add bx,ax ;bx = 6 + 1
dec cx
jnz loopy1
dec bx ;bx = 6
pop ax ;ax = 2k & 0xffff
add ax,bx ;ax = 6 + (2k & 0xffff)
mul word [aux] ;ax = 7*(6 + (2k & 0xffff))
cmp ax,350
ret
Considering that you have a mov dx, 5 before the first multiplication, did you (or the author of the safe) forget that mul affects dx?
If you wrap the first mul in push dx / pop dx (or just move mov dx, 5 after it), you would get, at the end of the safe, a value in ax equals to 7*(30 +2k) which implies k = 10 indeed.
For example, a user inputs 01010101, and the program splits it into 01 01 01 01 to read as separate values assigned to a specific constant.
I'm aware that shifts/pulling values out of a 32-bit register and masking needs to occur, though I don't know how to do so.
Use AND to mask out bit and SHR to shift bit to right
MOV dl, 0b01010101
AND dl, 0b00000001 ;dl now equals 1
MOV al, 0b01010101
AND al, 0b00000100 ;al now equals 0b00000100 = 4
SHR al, 2 ;al now equals 1
You can use bit operator "AND" to do this.
Assume now you store the original "01011100" in register AH and you want to split it into "01", "01", "11", "00" and store each of them in BH, BL, CH, CL.
You can do it like this:
MOV BH AH ;now the BH is 01011100 ,just like AH
AND BH 0B11000000 ;since "a AND b" equals 1 only when both a and b equal 1 ,so the first two bit of AH will be the same as that of BH, and the other six bit will be 0 because one of the operand is 0 . In this way you can split it.
And you can do the rest in the same way :
MOV BL AH ;now the BL is 01011100 ,just like AH
AND BL 0B00110000 ;now BL is 00010000
MOV CH AH ;now the CH is 01011100 ,just like AH
AND CH 0B00001100 ;now the CH is 00001100
MOV CL AH ;now the CL is 01011100 ,just like AH
AND CL 0B00000011 ;now the DH is 00000000
So, here in the following code, I am writing a code to sort numbers in ascending order.
start: nop
MVI B, 09 ; Initialize counter
LXI H, 2200H ;Initialize memory pointer
MVI C, 09H; Initialize counter 2
BACK: MOV A, M ;Get the number
INX H ;Increment memory pointer
CMP M; Compare number with next number
JC SKIP;If less, don't interchange
JZ SKIP; If equal, don't interchang
MOV D, M
MOV M, A
DCX H
MOV M, D
INX H ;Interchange two numbers
DCR C ; Decrement counter 2
JNZ BACK ;If not zero, repeat
DCR B ; Decrement counter 1
JNZ START
HLT ; Terminate program execution
This was that was taught in class.
When I try running the code in GNUSim, I get errors like :
1. Line 9: Undefined symbol.
2. Line 9: Invalid operand or symbol.Check whether operands start with a 0. Like a0H should be 0a0H.
Can somebody help?
In 8085 (js8085) I'd do it the next way (using bubble sort):
#begin 0100
#next 0100
MVI A 00
MVI B 00
MVI C 00
MVI D 00
MVI E 00
MVI H 00
MVI L 00
IN 00
out 00
DCR A
out 06
bubble: in 06
cmp c
jz finished
inr e
ldax b
mov h,a
ldax d
cmp h
jc change;
comprobation: in 00
cmp e
jz semi-fin
call bubble
semi-fin: inr c
mov a,c
mov e,c
call bubble
change: stax b
mov a,h
stax d
call comprobation
finished: hlt
In the port 00 you got the number of elements you have and the the elements themselves are starting from the position 0000 to the number of elements - 1.
What is the most efficient way to do 128 bit shift on a modern Intel CPU (core i7, sandy bridge).
A similar code is in my most inner loop:
u128 a[N];
void xor() {
for (int i = 0; i < N; ++i) {
a[i] = a[i] ^ (a[i] >> 1) ^ (a[i] >> 2);
}
}
The data in a[N] is almost random.
Using instruction Shift Double.
So SHLD or SHRD instruction, because SSE isn't intended for this purpose.
There is a clasic method, here are you have test cases for 128 bit left shift by 16 bits under 32 and 64 bit CPU mode.
On this way you can perform unlimited size shift for up to 32/64 bits. Yoo can shift for immediate number of bits or for number in cl register. First instruction operant can also address variable in memory.
128 bit left shift by 16 bits under 32 bit x86 CPU mode:
mov eax, $04030201;
mov ebx, $08070605;
mov ecx, $0C0B0A09;
mov edx, $100F0E0D;
shld edx, ecx, 16
shld ecx, ebx, 16
shld ebx, eax, 16
shl eax, 16
And 128 bit left shift by 16 bits under 64 bit x86 CPU mode:
mov rax, $0807060504030201;
mov rdx, $100F0D0E0B0C0A09;
shld rdx, rax, 16
shl rax, 16
In this particular case you could use a combination of x86 SHR and RCR instructions:
; a0 - bits 0-31 of a[i]
; a1 - bits 32-63 of a[i]
; a2 - bits 64-95 of a[i]
; a3 - bits 96-127 of a[i]
mov eax, a0
mov ebx, a1
mov ecx, a2
mov ecx, a3
shr eax, 1
rcr ebx, 1
rcr ecx, 1
rcr edx, 1
; b0 - bits 0-31 of b[i] := a[i] >> 1
; b1 - bits 32-63 of b[i] := a[i] >> 1
; b2 - bits 64-95 of b[i] := a[i] >> 1
; b3 - bits 96-127 of b[i] := a[i] >> 1
mov b0, eax
mov b1, ebx
mov b2, ecx
mov b3, edx
shr eax, 1
rcr ebx, 1
rcr ecx, 1
rcr edx, 1
; c0 - bits 0-31 of c[i] := a[i] >> 2 = b[i] >> 1
; c1 - bits 32-63 of c[i] := a[i] >> 2 = b[i] >> 1
; c2 - bits 64-95 of c[i] := a[i] >> 2 = b[i] >> 1
; c3 - bits 96-127 of c[i] := a[i] >> 2 = b[i] >> 1
mov c0, eax
mov c1, ebx
mov c2, ecx
mov c3, edx
If your target is x86-64 this simplifies to:
; a0 - bits 0-63 of a[i]
; a1 - bits 64-127 of a[i]
mov rax, a0
mov rbx, a1
shr rax, 1
rcr rbx, 1
; b0 - bits 0-63 of b[i] := a[i] >> 1
; b1 - bits 64-127 of b[i] := a[i] >> 1
mov b0, rax
mov b1, rbx
shr rax, 1
rcr rbx, 1
; c0 - bits 0-63 of c[i] := a[i] >> 2 = b[i] >> 1
; c1 - bits 64-127 of c[i] := a[i] >> 2 = b[i] >> 1
mov c0, rax
mov c1, rbx
Update: corrected typos in 64-bit version