I have to write a program in 8086 assembly that calculates this:
(a+b*c+2/c)/(2+a)+e
where
a,b - byte
c - word
e - doubleword,
in unsigned interpretation.
So far I have this:
assume cs:code,ds:data
data segment
a db 4
b db 2
c dw 16
e dd 126
data ends
code segment
start:
mov ax,data
mov ds,ax
and here is my program
mov al,b ; al=b
mov ah,0 ; ax=b;
mul c; dx:ax=b*c; b*c=doubleword
mov bx,ax; we save b*c in bx to use ax in the division 2/c
mov al,2; al=2
mov ah,0; al=ax=0
div c; ax=dx:ax/c ; dx=dx:ax%c;
I don't know how to continue.
When you write
mov bx,ax; we save b*c in bx to use ax in the division 2/c
you're actually only saving the low word of the product between B and C. It works with the numbers provided but it's not a general solution.
In stead of writing
mov al,2; al=2
mov ah,0; al=ax=0
use mov ax,2 and remember to explicitely clear the DX register because the division needs it.
To continue I would suggest you create a result variable of doubleword size because in the end the size of your largest expression participant defines the size of the result. Then on the way move or add your partial results to this variable.
If you are allowed to use 32 bit registers a suitable approach might be to promote all values to 32 bit and continue from there.
Related
Need to divide CL by 10. I understand that in division AX will always be the numerator, but I need it to be the denominator.
In the code below I attempt to move the value I need as the numerator into AL and then put 10 into CL and divide.
Any help would be appreciated.
Mov Al, Cl
Mov Cl, 10
Div Cl
Need to divide Cl by 10
So you'll want the quotient back in the CL register then.
Your corrected solution (10 bytes):
mov al, cl
xor ah, ah ;Clear high byte because DIV will use the entire AX
mov cl, 10
div cl ;Divides AX by 10, leaves quotient in AL
mov cl,al
Shorter solution (6 bytes):
mov al, cl
aam ;Divides AL by 10, leaves quotient in AH
mov cl, ah
On 8086 the AAM instruction exclusively divides by 10.
On x86 the AAM instruction can divide by any byte-sized number.
So this AAM instruction is in effect an 8 bit by 8 bit division!
Is there a way then to divide a register by 10?
All divisions implicitly use the accumulator (AL, AX, DX:AX). Just copy your register to the accumulator first.
Hello I am very new to writing assembly and have a question regarding my attempt at writing a recursive function to compute the factorial of n.
Here is my attempt at writing the factorial function:
.global main
main:
MOV r1, #3
fact:
SUB sp, sp, #8
STR lr, [sp, #0]
STR r1, [sp,#4]
CMP r1, #1
BGT Else
ADD sp, sp, #8
MOV pc, lr
Else:
SUB r1, r1, #1
BL fact
MOV r2, r1
LDR r1, [sp, #4]
LDR lr, [sp, #0]
ADD sp, sp, #8
MUL r1, r2, r1
MOV pc, lr
MOV r0, #1
SWI 0x6b
SWI 0x11
The issue is this: i successfully can compute that 3 factorial is 6 and it gets stored in r1 at the end of the program; however, I can never get passed the last "MOV pc, lr" statement in the third execution of the loop and I cannot understand the logic behind why.
When I get to the third loop of MOV pc, lr I get an error stating: "PC out of valid memory range" but I am not sure why this is the case. Any pointers in the right direction would be greatly appreciated because I am an absolute beginner and cannot understand why this error is occurring. Thank you for your time!
I want to check if the value of the register ax is divisible by 7, with remainder = 0. How can I do it?
You can use the same way as shown in this answer, with different constants of course.
The modular multiplicative inverse of 7 mod 216 is 0x6db7, which (by definition) means that numbers of the form x = n * 7 will obey x * 0x6db7 = n, where n will be less than or equal to 0xffff / 7. So if you get something bigger out of x * 0x6db7, you know it's not a multiple of 7. Also, non-multiples of 7 cannot also map to low results, because multiplication by an odd number modulo a power of two is bijective.
So you can use (not tested)
imul ax, ax, 0x6db7
cmp ax, 0x2492
ja not_multiple_of_7
This is for unsigned numbers of course.
As a bonus, ax will be the original value divided by 7 iff it was a multiple of 7.
org 100h
mov ax,14
mov cl,7
div cl
cmp ah,0
je positive
PRINTN "The number has a remainder"
jmp finish
positive:
PRINTN "The number has no remainder"
finish:
PRINTN "After comparison"
mov ah, 0
int 16h
ret
For example, let's say register 4 (R4) has a value 0001110010101111. How could you change bit 5 (0001110010 >1< 01111) to 0 (even if it was already 0) without moving or changing the other bits in a single hex instruction?
So 0001110010101111 -> 0001110010001111
You'll want to AND it. Since the immediate value for AND is 5 bits and it uses sign extension, you can only clear a bit if it's one of the four least significant bits. Otherwise, you will need to perform another instruction to load the mask into a register. I'll do an example of both.
In the case of the 5th bit, the number that will mask the bit is 0b1111111111011111. In decimal, this is #65503 or #-33. Since this is too big to fit in an immediate instruction, you won't be able to do it in a single instruction. You will need to declare it in the data segment of your program and load the mask into a register. Then, you can AND it with R4.
; assuming R4 = 0001110010101111
LD R5, MASK_5 ; load the mask into R5
AND R4, R4, R5 ; set R4 = R4 AND R5
; R4 will now have the bit cleared
; data segment
MASK_5 .FILL #65503
In the case of the 3rd bit, the number that will mask the bit is 0b1111111111110111. In decimal, this is #65527 or #-9. This will fit in the immediate value of AND, so you can perform it in a single instruction:
; assuming R4 = 0001110010101111
AND R4, R4, #-9 ; set R4 = R4 AND #-9
; R4 will now have the bit cleared
I just need some help. I don't fully understand and I am fairly new to masm32 so if you could explain, that would be great!
MOV AX, 200
ADD AX, 300
MOV RESULT, AX
Will result be equal to 500? I tried adding 3 and 2 and using this to show output:
MOV DX, RESULT
ADD RESULT, '0'
MOV AH, 02H
INT 21H
But the output is a candy cane character! Where is it wrong?
Now I assume subtraction will work the same as addition, so on to Multiplication we go.
This is what I did for multiplication
MOV AX, 30
MOV BX, 8
MUL BX
MOV RESULT, AX
Is RESULT's value equal to 240?....
I tried AX as 3 and BX as 2. The output is a spade. Can you point me to the right direction?
Now division.
MOV AX, 30
MOV BX, 12
DIV BX
MOV RESULT, AX
What holds the quotient? If what I read was correct, that would be AX, and DX holds the remainder...?
I have already done 8 bit arithmetic (using AL, BL, DL...) and I tried to apply it here, sadly, when the RESULT becomes greater than 128, it just outputs garbage. Someone suggested that I should declare my variables as 'RESULT dw ?' instead of 'RESULT db ?' and instead of AL BL registers I should use AX BX.... Now I'm stuck.
Any help would be appreciated! Sorry if these questions seem too trivial. Anyway, thanks in advance! :DD
MOV AX, 200
ADD AX, 300
MOV RESULT, AX
Will result be equal to 500?
Yes.
I tried adding 3 and 2 and using this to show output:
MOV DX, RESULT
ADD RESULT, '0'
MOV AH, 02H
INT 21H
But the output is a candy cane character! Where is it wrong?
You're adding '0' to RESULT after moving RESULT to DX. You should probably add '0' to DL instead of to RESULT.
Now division.
MOV AX, 30
MOV BX, 12
DIV BX
MOV RESULT, AX
What holds the quotient? If what I read was correct, that would be AX, and DX holds the remainder...?
DIV BX divides the 32-bit value DX:AX by BX, so you should clear DX before the division. The quotient will end up in AX and the remainder in DX.
Someone suggested that I should declare my variables as RESULT dw ?
If you're going to move 16-bit values to/from the variable (e.g. MOV RESULT,AX) then you should make the variable (at least) 16 bits.