David Pupaza
David Pupaza

Reputation: 23

How to work with variables in assembly x86

So i have to multiply 'a' by a number of 'b' times and I tried to do it like this. I also took some procedures from other questions I found.

.MODEL SMALL

.DATA
a db 3, 4 dup (0)
b db 3, 4 dup (0) ;With the buffer that this provides, this now will allow you to input from the keyboard two double-digit numbers.

.CODE
  mov  ax, @data ;INITIALIZE DATA SEGMENT.
  mov  ds, ax

START:
;a
mov ah, 0ah
mov dx, offset a 
int 21h         
call string2number1 ;convert a to number (a->bx)
mov dx,bx ;(a->ax)
;b
mov ah, 0ah
mov dx, offset b
int 21h
call string2number2 ;convert b to number (b->bx)

;multiplication
mov cx,bx ;b->cx (multiply by cx(b) times)
mov bx,dx ;a->bx (to do a*a)
power:
    mul bx
    loop power
;dx:ax should now contain m^n (i hope)

;displaying dx:ax
    mov     bx,10          ;CONST
    push    bx             ;Sentinel
.a: mov     cx,ax          ;Temporarily store LowDividend in CX
    mov     ax,dx          ;First divide the HighDividend
    xor     dx,dx          ;Setup for division DX:AX / BX
    div     bx             ; -> AX is HighQuotient, Remainder is re-used
    xchg    ax,cx          ;Temporarily move it to CX restoring LowDividend
    div     bx             ; -> AX is LowQuotient, Remainder DX=[0,9]
    push    dx             ;(1) Save remainder for now
    mov     dx,cx          ;Build true 32-bit quotient in DX:AX
    or      cx,ax          ;Is the true 32-bit quotient zero?
    jnz     .a             ;No, use as next dividend
    pop     dx             ;(1a) First pop (Is digit for sure)
.b: add     dl,"0"         ;Turn into character [0,9] -> ["0","9"]
    mov     ah,02h         ;DOS.DisplayCharacter
    int     21h            ; -> AL
    pop     dx             ;(1b) All remaining pops
    cmp     dx,bx          ;Was it the sentinel?
    jb      .b             ;Not yet

;-----------------------------------------
jmp skipProcedures

;CONVERT a TO NUMBER IN BX.
proc string2number1         
;MAKE SI TO POINT TO THE LEAST SIGNIFICANT DIGIT.
  mov  si, offset a + 1
  mov  cl, [ si ] ;NUMBER OF CHARACTERS ENTERED.                                         
  mov  ch, 0 ;CLEAR CH, NOW CX==CL.
  add  si, cx ;NOW SI POINTS TO LEAST SIGNIFICANT DIGIT.
;CONVERT STRING.
  mov  bx, 0
  mov  bp, 1 ;MULTIPLE OF 10 TO MULTIPLY EVERY DIGIT.
repeat:         
;CONVERT CHARACTER.                    
  mov  al, [ si ] ;CHARACTER TO PROCESS.
  sub  al, 48 ;CONVERT ASCII CHARACTER TO DIGIT.
  mov  ah, 0 ;CLEAR AH, NOW AX==AL.
  mul  bp ;AX*BP = DX:AX.
  add  bx,ax ;ADD RESULT TO BX. 
;INCREASE MULTIPLE OF 10 (1, 10, 100...).
  mov  ax, bp
  mov  bp, 10
  mul  bp ;AX*10 = DX:AX.
  mov  bp, ax ;NEW MULTIPLE OF 10.  
;CHECK IF WE HAVE FINISHED.
  dec  si ;NEXT DIGIT TO PROCESS.
  loop repeat ;COUNTER CX-1, IF NOT ZERO, REPEAT.

  ret 
endp    

;CONVERT b TO NUMBER IN BX.
proc string2number2         
;MAKE SI TO POINT TO THE LEAST SIGNIFICANT DIGIT.
  mov  si, offset b + 1
  mov  cl, [ si ] ;NUMBER OF CHARACTERS ENTERED.                                         
  mov  ch, 0 ;CLEAR CH, NOW CX==CL.
  add  si, cx ;NOW SI POINTS TO LEAST SIGNIFICANT DIGIT.
;CONVERT STRING.
  mov  bx, 0
  mov  bp, 1 ;MULTIPLE OF 10 TO MULTIPLY EVERY DIGIT.
repeat2:         
;CONVERT CHARACTER.                    
  mov  al, [ si ] ;CHARACTER TO PROCESS.
  sub  al, 48 ;CONVERT ASCII CHARACTER TO DIGIT.
  mov  ah, 0 ;CLEAR AH, NOW AX==AL.
  mul  bp ;AX*BP = DX:AX.
  add  bx,ax ;ADD RESULT TO BX. 
;INCREASE MULTIPLE OF 10 (1, 10, 100...).
  mov  ax, bp
  mov  bp, 10
  mul  bp ;AX*10 = DX:AX.
  mov  bp, ax ;NEW MULTIPLE OF 10.  
;CHECK IF WE HAVE FINISHED.
  dec  si ;NEXT DIGIT TO PROCESS.
  loop repeat2 ;COUNTER CX-1, IF NOT ZERO, REPEAT.

  ret 
endp    

skipProcedures:
;---------------------------------------
mov ax,4c00h
int 21h         
end start


The program wont let me press enter after I write the input for 'a'. Maybe I was wrong when I made the multiplication loop or when I tried to display dx:ax, but what does that have to do with letting me write input for a? I tried to explain as much as possible in the comments. What should I do?

Upvotes: 2

Views: 855

Answers (1)

Sep Roland
Sep Roland

Reputation: 39166

I keep getting the same error as 'Operand types do not match on lines 18 and 19

That's because TASM knows that the a and b variables are byte-sized given that they were defined using the DB directive, but your instructions mov bx,a and mov cx,b are word-sized operations. So, a mis-match.

This is what is happening in the code

Your program is using the a and b 'variables' for user input via the DOS.BufferedInput function 0Ah. Read all about this function here.

What your definitions should look like is:

.DATA
a db 3, 4 dup (0)
b db 3, 4 dup (0)

With the buffer that this provides, this now will allow you to input from the keyboard two double-digit numbers.

To actually start calculating with these numbers, you need to convert the text characters (by which they were inputted) into a simple number in the range [0,99].
Next code accomplishes this for the two-digit a input:

mov bx, offset a
mov ah, [bx+2]     ; The tens ["0","9"]
mov al, [bx+3]     ; The ones ["0","9"]
sub ax, "00"       ; Converting to [0,9] on both at the same time
aad                ; Combining both: AX = (AH * 10) + AL

mov ax,0   ; Initial result, i.e. m^0
power:
    jcxz power_done
    mul bx
    loop power
power_done:

No matter the value by which you multiply (BX), this multiplication will always yield zero. That's because you initialized AX=0. This does not correspond to the comment "Initial result, i.e. m^0". Remember that m^0 = 1.


You are trying to display the result with a single character output function. That's never going to be enough! See this Q/A for the correct method.

Upvotes: 2

Related Questions