Author Topic: Writing assembly program to do simple arithmetic operations.  (Read 9885 times)

Offline amrak

  • Jr. Member
  • *
  • Posts: 3
I have started to learn assembly programming in NASM, I want to write a basic arithmetic program. where
1:  the user enters the first digit
2:  then the second digit,
3:  then the program gives the option to choose 1=ADD 2=SUB etc...
4: the results get displayed
The code is given below.
Code: [Select]
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1

segment .data

 msg1 db "Enter the first digit", 0xA,0xD
 len1 equ $- msg1
 msg2 db "Please enter a second digit", 0xA,0xD
 len2 equ $- msg2
 msg3 db "Enter a choice 1 ADD 2 = SUB 3 = DIV 4 =MUL ", 0xA,0xD
 len3 equ $- msg3
 msg4 db "The sum is: "
 len4 equ $- msg4

 segment .bss
 choice resb 1
 num1 resb 2
 num2 resb 2
 res resb 1

 section .text
 global _start
_start: ;tell linker entry point
        mov eax, SYS_WRITE   ; prompt for the first digit
        mov ebx, STDOUT
        mov ecx, msg1
        mov edx, len1
        int 0x80

mov eax, SYS_READ    ; accept the first digit
mov ebx, STDIN
mov ecx, num1
mov edx, 2
int 0x80

        mov eax, SYS_WRITE   ; prompt to ask for the second digit
        mov ebx, STDOUT
        mov ecx, msg2
        mov edx, len2
         int 0x80

mov eax, SYS_READ   ;accept the second digit
mov ebx, STDIN
mov ecx, num2
mov edx, 2
int 0x80
 
mov eax, SYS_WRITE  ; prompt to choose to ADD, SUB, DIV or MUL
        mov ebx, STDOUT
        mov ecx, msg3
        mov edx, len3
         int 0x80

mov eax, SYS_READ  ; accept the user choice
mov ebx, STDIN
mov ecx, choice
mov edx, 1
cmp ecx, 1             
je _add       ; [glow=red,2,300]can I add je _mul, je _div to branch to other operations?[/glow]
int 80h

_disp:
         mov eax, SYS_WRITE
         mov ebx, STDOUT
         mov ecx, msg4
         mov edx, len4
jmp exit
         int 0x80
 
 
_add:
mov eax, [num1] ; moving the first number to eax register and second number to ebx
sub eax, '0' ; and subtracting ascii '0' to convert it into a decimal number
mov ebx, [num2]
sub ebx, '0'
add eax, ebx ; add eax and ebx
add eax, '0' ; add '0' to to convert the sum from decimal to ASCII 
mov [res], eax ; storing the sum in memory location
 
; print the sum
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, res
mov edx, 1
int 80h
        jmp _disp
exit:
mov eax, SYS_EXIT
xor  ebx, ebx
int 80h
The problem is when running the program, after I input two numbers and choose 1 (since my code is incomplete and I have to add instructions to SUB, DIV and MUL) the program fails to display the result. Will be grateful if someone could guide me on how to accomplish my task.
« Last Edit: May 24, 2016, 03:09:53 PM by Frank Kotler »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Writing assembly program to do simple arithmetic operations.
« Reply #1 on: May 24, 2016, 04:51:04 PM »
Hi Amrak,
Welcome to the forum!

Code: [Select]
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1

segment .data

 msg1 db "Enter the first digit", 0xA,0xD
 len1 equ $- msg1
 msg2 db "Please enter a second digit", 0xA,0xD
 len2 equ $- msg2
 msg3 db "Enter a choice 1 ADD 2 = SUB 3 = DIV 4 =MUL ", 0xA,0xD
 len3 equ $- msg3
 msg4 db "The sum is: "
 len4 equ $- msg4

 segment .bss
 choice resb 1 ; make it 2 ?
 num1 resb 2
 num2 resb 2
 res resb 1

 section .text
 global _start
_start: ;tell linker entry point
        mov eax, SYS_WRITE   ; prompt for the first digit
        mov ebx, STDOUT
        mov ecx, msg1
        mov edx, len1
        int 0x80

mov eax, SYS_READ    ; accept the first digit
mov ebx, STDIN
mov ecx, num1
mov edx, 2
int 0x80

        mov eax, SYS_WRITE   ; prompt to ask for the second digit
        mov ebx, STDOUT
        mov ecx, msg2
        mov edx, len2
         int 0x80

mov eax, SYS_READ   ;accept the second digit
mov ebx, STDIN
mov ecx, num2
mov edx, 2
int 0x80
 
mov eax, SYS_WRITE  ; prompt to choose to ADD, SUB, DIV or MUL
        mov ebx, STDOUT
        mov ecx, msg3
        mov edx, len3
         int 0x80

mov eax, SYS_READ  ; accept the user choice
mov ebx, STDIN
mov ecx, choice
mov edx, 1
        int 80h ; read it before you compare it! :)

; cmp ecx, 1
; "[contents]", and character '1'
; must specify size (since it's not a register)
       cmp byte [ecx], '1'             

je _add       ; [glow=red,2,300]can I add je _mul, je _div to branch to other operations?[/glow]
; int 80h ; too late

; yeah, you can do that
; what do you want to do if "none of the above"?


_disp:
         mov eax, SYS_WRITE
         mov ebx, STDOUT
         mov ecx, msg4
         mov edx, len4
jmp exit  ; too soon!
         int 0x80
 
 
_add:
mov eax, [num1] ; moving the first number to eax register and second number to ebx
sub eax, '0' ; and subtracting ascii '0' to convert it into a decimal number
mov ebx, [num2]
sub ebx, '0'
add eax, ebx ; add eax and ebx
add eax, '0' ; add '0' to to convert the sum from decimal to ASCII 
mov [res], eax ; storing the sum in memory location
 
; print the sum
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, res
mov edx, 1
int 80h
        jmp _disp
exit:
mov eax, SYS_EXIT
xor  ebx, ebx
int 80h

You've got some problems here...
Code: [Select]
mov eax, [anything]
... moves four bytes into eax. Bigger than your variables. Use "movsx" to zero-extend a byte into a four-byte register, or use a one-byte (8 bit) register (al, bl). Even worse when you move four bytes into a smaller variable!

Due to the nature of SYS_READ, you need a byte for the linefeed (0xA) as well as the byte we're interested in. You account for this with the numbers, but not with "choice".

Since you didn't get the "cmp" right for "choice", you were not getting to "_add" at all, which is why it wasn't displaying anything. Fix that, watch the size of your variables and registers, and give it another shot.

Adding two one-digit numbers can easily give a two-digit result, which won't display correctly. It isn't too difficult to read/print integers up to four billion and change (floating point is a real PITA). You may want to do this, rather than be limited to single digit numbers... but get one digit working first...

Best,
Frank


Offline amrak

  • Jr. Member
  • *
  • Posts: 3
Re: Writing assembly program to do simple arithmetic operations.
« Reply #2 on: May 25, 2016, 06:40:24 PM »
Thank You @Frank Kotler, I did succeed in getting the result to do 1 digit arithmetic operation. I will be grateful if you can guide me on the mistakes with the program
Code: [Select]
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1

segment .data

msg1 db "Enter the first digit", 0xA,0xD
len1 equ $- msg1
msg2 db "Please enter a second digit", 0xA,0xD
len2 equ $- msg2
msg3 db "Enter a choice 1 ADD 2 = SUB 3 = DIV 4 =MUL ", 0xA,0xD
len3 equ $- msg3
msg5    db      10,'Invalid Option',10,0
len5    equ     $ - msg5
msg6  equ "Operation: ",0
len6 equ $- msg6
msg4 db "The sum is: ",10
len4 equ $- msg4
nline   db  10,0
lnline equ     $ - nline

 segment .bss
 choice resb 2 
 num1 resb 2
 num2 resb 2
 res resb 2

 section .text
 
 global _start
 
_start: ;tell linker entry point
        mov eax, SYS_WRITE ;"Enter the first digit", 0xA,0xD
        mov ebx, STDOUT
        mov ecx, msg1
        mov edx, len1
        int 0x80

mov eax, SYS_READ ; read the 1st Digit entered by the user
mov ebx, STDIN
mov ecx, num1
mov edx, 2
int 0x80

        mov eax, SYS_WRITE ;"Please enter the second digit", 0xA,0xD
        mov ebx, STDOUT
        mov ecx, msg2
        mov edx, len2
        int 0x80

mov eax, SYS_READ ; read 2nd user input
mov ebx, STDIN
mov ecx, num2
mov edx, 2
int 0x80
 
mov eax, SYS_WRITE ; "Enter a choice 1 ADD 2 = SUB 3 = DIV 4 =MUL ",
        mov ebx, STDOUT
        mov ecx, msg3
        mov edx, len3
        int 0x80

; Print on screen the message 8: operation
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg6
mov edx, len6
int 80h

  ; We get the option selected: any one from 1,2,3,4
mov ebx,STDIN
mov ecx,choice
mov edx,2
mov eax, SYS_READ
int 80h
 
mov ah, [choice] ; move the users choice into ah register
sub ah,'0'

cmp ah, 1 ; compare user choice with the available options
je _ADD ;if choice == 1 jump to add label

cmp ah, 2
je _SUB

cmp ah, 3
je _MUL

cmp ah, 4
je _DIV

         mov eax, SYS_WRITE ; if the wrong choice is entered
         mov ebx, STDOUT
         mov ecx, msg5
         mov edx, len5
         int 0x80
jmp exit

_printMsg4:
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg4
mov edx, len4
int80h
jmp _printSum

; print the sum
_printSum:
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, res  ; print the value of sum on the screen
mov edx, 2 
int 0x80
jmp exit   ; jump to exit the program

; moving the first number to eax register and second number to ebx
; and subtracting ascii '0' to convert it into a decimal number
_ADD:
mov al, [num1]
sub al, '0'
mov bl, [num2]
sub bl, '0'
add al, bl ; al and bl
add al, '0' ; add '0' to to convert the sum from decimal to ASCII 
mov [res], al ; storing the sum in memory location
int 80h
jmp _printMsg4
_SUB:
mov al, [num1]
sub al, '0'
mov bl, [num2]
sub bl, '0'
sub] al, bl ; al and bl
add al, '0' ; add '0' to to convert the sum from decimal to ASCII 
mov [res], al ; storing the sum in memory location
int 80h
jmp _printMsg4
_DIV:
  ; We store the numbers in registers ax and bx
mov ax, [num1]
sub ax, '0'   ; Convert from ascii to decimall
mov bx, [num2]
sub bx, '0'
mov edx, 0  ;remainder
mov eax, 0  ;quotient
; Division. Ax = AX / BX
div bx

    ; Conversion from decimal to ascii
add ax, '0'
; We move the result
mov [result], eax
int 80h
jmp _printMsg4
 _MUL:
  ; We store the numbers in registers al and bl
mov al, [num1]
mov bl, [num2]
; Convert from ascii to decimal
sub al, '0'
sub bl, '0'
    ; Multiply. AX = AL x BL
mul bl

    ; Conversion from decimal to ascii
add ax, '0'

    ; We move the result
mov [res], ax
int 80h
jmp _printMsg4
exit:
mov eax, SYS_WRITE
    mov ebx, STDOUT
    mov ecx, nline
    mov edx, lnline
    int 80h

mov eax, SYS_EXIT
mov ebx,0
int 80h

« Last Edit: May 26, 2016, 12:25:11 AM by Frank Kotler »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Writing assembly program to do simple arithmetic operations.
« Reply #3 on: May 26, 2016, 03:15:02 AM »
In the first place, I should have mentioned "code tags". Just put the word "code" in square brackets at the beginning of your code and "/code" at the end. (you tried this with "glow", but that doesn't work here) This may or may not make it easier to read, definitely makes it easier to cut and paste.

It does not assemble as posted. Simple typos, mostly. I've got it so it assembles, I think, but I may need a nap or two before I'm done with it. I'll get back to ya. (looks like using ax is not helpful...)

Best,
Frank


Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Writing assembly program to do simple arithmetic operations.
« Reply #4 on: May 26, 2016, 05:36:25 PM »
Okay... One thing I didn't notice at first which caused me quite a bit of trouble: your choice message says 3 is div and 4 is mul, but the code jumped to _mul on 3 and _div on 4. The user (me) is carefully selecting inputs that will give a single-digit result, and it isn't working right. Duh!

Well, I think I've got it working for single digits (and positive, in the case of "sub"). I changed the code to match the message - probably would be better to change the message(?). This is what I've got, at present:
Code: [Select]
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1

segment .data

msg1 db "Enter the first digit", 0xA,0xD
len1 equ $- msg1
msg2 db "Please enter a second digit", 0xA,0xD
len2 equ $- msg2
msg3 db "Enter a choice 1 ADD 2 = SUB 3 = DIV 4 =MUL ", 0xA,0xD
len3 equ $- msg3
msg5    db      10,'Invalid Option',10,0
len5    equ     $ - msg5
msg6  db "Operation: ",0
len6 equ     $ - msg6
msg4 db "The sum is: ",10
len4 equ $- msg4
nline   db  10,0
lnline equ     $ - nline

 segment .bss
 choice resb 2 
 num1 resb 2
 num2 resb 2
 res resb 2

 section .text
 
 global _start
 
_start: ;tell linker entry point
        mov eax, SYS_WRITE ;"Enter the first digit", 0xA,0xD
        mov ebx, STDOUT
        mov ecx, msg1
        mov edx, len1
        int 0x80

mov eax, SYS_READ ; read the 1st Digit entered by the user
mov ebx, STDIN
mov ecx, num1
mov edx, 2
int 0x80

        mov eax, SYS_WRITE ;"Please enter the second digit", 0xA,0xD
        mov ebx, STDOUT
        mov ecx, msg2
        mov edx, len2
        int 0x80

mov eax, SYS_READ ; read 2nd user input
mov ebx, STDIN
mov ecx, num2
mov edx, 2
int 0x80
 
mov eax, SYS_WRITE ; "Enter a choice 1 ADD 2 = SUB 3 = DIV 4 =MUL ",
        mov ebx, STDOUT
        mov ecx, msg3
        mov edx, len3
        int 0x80

; Print on screen the message 8: operation
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg6
mov edx, len6
int 80h

  ; We get the option selected: any one from 1,2,3,4
mov ebx,STDIN
mov ecx,choice
mov edx,2
mov eax, SYS_READ
int 80h
 
mov ah, [choice] ; move the users choice into ah register
sub ah,'0'

cmp ah, 1 ; compare user choice with the available options
je _ADD ;if choice == 1 jump to add label

cmp ah, 2
je _SUB

cmp ah, 4
je _MUL

cmp ah, 3
je _DIV

         mov eax, SYS_WRITE ; if the wrong choice is entered
         mov ebx, STDOUT
         mov ecx, msg5
         mov edx, len5
         int 0x80
jmp exit

_printMsg4:
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg4
mov edx, len4
int 80h
jmp _printSum

; print the sum
_printSum:
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, res  ; print the value of sum on the screen
mov edx, 2 
int 0x80
jmp exit   ; jump to exit the program

; moving the first number to eax register and second number to ebx
; and subtracting ascii '0' to convert it into a decimal number
_ADD:
mov al, [num1]
sub al, '0'
mov bl, [num2]
sub bl, '0'
add al, bl ; al and bl
add al, '0' ; add '0' to to convert the sum from decimal to ASCII 
mov [res], al ; storing the sum in memory location
int 80h
jmp _printMsg4
_SUB:
mov al, [num1]
sub al, '0'
mov bl, [num2]
sub bl, '0'
sub al, bl ; al and bl
add al, '0' ; add '0' to to convert the sum from decimal to ASCII 
mov [res], al ; storing the sum in memory location
int 80h
jmp _printMsg4
_DIV:
  ; We store the numbers in registers ax and bx
mov al, [num1]
sub al, '0'   ; Convert from ascii to decimall
mov bl, [num2]
sub bl, '0'
mov ah, 0  ;remainder
; mov eax, 0  ;quotient
; Division. Ax = AX / BX
div bl

    ; Conversion from decimal to ascii
add al, '0'
; We move the result
mov [res], al
; int 80h
jmp _printMsg4
 _MUL:
  ; We store the numbers in registers al and bl
mov al, [num1]
mov bl, [num2]
; Convert from ascii to decimal
sub al, '0'
sub bl, '0'
    ; Multiply. AX = AL x BL
mul bl

    ; Conversion from decimal to ascii
add al, '0'

    ; We move the result
mov [res], al
; int 80h
jmp _printMsg4
exit:
mov eax, SYS_WRITE
    mov ebx, STDOUT
    mov ecx, nline
    mov edx, lnline
    int 80h

mov eax, SYS_EXIT
mov ebx,0
int 80h

If I get to it, I'll post a version that will handle multiple digits (positive and negative?). Maybe I'll go through it and pick a few nits - stuff that's not exactly an "error", but not really right - carriage returns, for example...

Later,
Frank


Offline amrak

  • Jr. Member
  • *
  • Posts: 3
Re: Writing assembly program to do simple arithmetic operations.
« Reply #5 on: May 27, 2016, 05:11:41 PM »
Thank you for your time and effort. The mistake in mismatch of the options provided to the users was very stupid of me. Thank you @Frank Kotler