Reputation: 11
Need to write a program that takes in two numbers as input and prints the sum of them. Not sure where I'm going wrong here. I think the division might be a little funky but am really struggling with why my output is not correct. Ex. of output: input 10 and 11 - output 22. I appreciate any help!
.model small
;-----------------------------------------------------
.stack 64
;-----------------------------------------------------
.data
PR DB 'ENTER: ','$'
Num1 Label Byte
Max1 DB 3 ; need to hit atmost 3 keys when entering- 2 digits and the enter key
Act1 Db ?
N1 DB 4 DUP ('$')
Num2 Label Byte
Max2 DB 3 ; need to hit atmost 3 keys when entering- 2 digits and the enter key
Act2 Db ?
N2 DB 4 DUP ('$')
Hold DW ?
Res DB 3 DUP ('$')
msg Db " Result is $"
;-----------------------------------------------------
.code
MAIN proc FAR
mov AX,@data ; Initialize segment
mov DS,AX ; registers
call CLEAR
call SET_CURSOR
call REQUEST_INPUT
call GET_INPUT1
call SET_CURSOR2
call REQUEST_INPUT
call GET_INPUT2
call SET_CURSOR3
call Convert
mov AX,4C00h ; Exit to DOS
int 21h
MAIN endp
;-----------------------------------------------------
CLEAR proc NEAR
mov AX, 0600H
mov BH, 71H
mov CX, 0000H
mov DX, 184FH
int 10H
ret
CLEAR endp
;-----------------------------------------------------
SET_CURSOR proc NEAR
mov AH, 02H
mov BH, 0 ;sets color of backround
mov DH, 5
mov DL, 10
int 10H
ret
SET_CURSOR endp
;-----------------------------------------------------
REQUEST_INPUT proc NEAR
mov AH, 09H
lea DX, PR
int 21H
ret
REQUEST_INPUT endp
;-----------------------------------------------------
GET_INPUT1 proc NEAR
mov AH, 0AH
lea DX,Num1
int 21H
mov BH, 00
mov BL, Max1
mov N1[BX],'$'
ret
GET_INPUT1 endp
;-----------------------------------------------------
GET_INPUT2 proc NEAR
mov AH, 0AH
lea DX,Num2
int 21H
mov BH, 00
mov BL, Max2
mov N2[BX],'$'
ret
GET_INPUT2 endp
;-----------------------------------------------------
Convert proc NEAR
mov BX, 0
mov AH, 00h
mov Al, N1[BX] ; Get a character
Sub Al, 48 ; to get decimel value from character
Mov Bx, 10
Mul Bx
mov Cl, Al ; Result of multiplication stored in Al
mov BX, 1
mov BH, 00h
mov Bl, N1[BX] ; Get a character
Sub BL, 48
Add Cl, Bl ; Add first digit and second digit
mov BX, 0
mov CH, 00h
mov Al, N2[BX] ; Get a character
Sub Al, 48 ; to get decimel value from character
Mov Bx, 10
Mul Bx
Mov Bl, Al ; Result of multiplication stored in Al
mov BX, 1
mov BH, 00h
mov AL, N2[BX] ; Get a character
Sub Al, 48 ;to get decimel value from character
Add Al, Bl ; Add first and second digit
Add Cl, Al ; Add number one and number two
Mov Ah, 0; zero out ah before devision
Mov Al, Cl
Mov Cl, 10
Div Cl
Add Al, 48 ;Value of int devision
Mov Res[0], Al
Add AH, 48 ;value of remainder
Mov Res[1], AH
mov AH,09h
lea DX, msg
int 21H
mov AH,09h
lea DX, Res
int 21H
ret
Convert endp
;-----------------------------------------------------
SET_CURSOR2 proc NEAR
mov AH, 02H
mov BH, 0 ;sets color of backround
mov DH, 6
mov DL, 10
int 10H
ret
SET_CURSOR2 endp
;-----------------------------------------------------
SET_CURSOR3 proc NEAR
mov AH, 02H
mov BH, 0 ;sets color of backround
mov DH, 7
mov DL, 10
int 10H
ret
SET_CURSOR3 endp
;------------------------------------------------------------
;formula ()N1[0]-48)*10 + (N1[1]-48)
;same for N2
;before printing need to divide result of N1+N2 by 10. the quation is the frist character remainder is the second character- quaotiant will be in AL, Remainder in AH
;then need to add 48 before putting them into the array Res
;To go back Add Al,48-Mov Res[0], AL
;-----------------------------------------------------------'
end MAIN
Upvotes: 0
Views: 3975
Reputation: 16606
8086 has more than 3 registers (ax
, bx
, cx
in your code reused a lot).
While your code is exercising lot of unneeded re-sets of values, you manage to avoid any clash up till Mov Bl, Al
(storing result of N2[0]*10), followed by mov bx,1
overwriting this value.
If you would use debugger, you would probably notice you lost your value.
If you know, you will access for example N2[1], don't bother with bx
, just write mov al,[N2+1]
.
If you do mul bx
, you are doing dx:ax = bx * ax
(check always documentation for instruction, if you are not sure how it works), in your special case of 2 digit numbers and multiplying by 10, you can just set up al
(0-9 value) and do mul bl
(10), which will put result into ax
(0-90 value), clearing upper 8 bits of ax
for you.
And if I'm already tackling on cleaning up code by trying to do only the inevitable, how about removing one mul
completely:
If you have numbers x, y stored as x1,x0 and y1,y0, where n = ∑ni*10i, then:
x + y ⇔ x1 * 10 + x0 * 1 + y1 *10 + y0 * 1 ⇔
⇔ 10 * (x1 + y1) + (x0 + y0)
So in your code you can do:
mov al,[N1+0] ; ASCII x1
add al,[N2+0] ; ASCII y1 (no real overflow risk, 8b is enough)
sub al,2*'0' ; convert from ASCII to value
mov ah,10
mul ah ; ax = 10 * (x1+y1) (value is 0 to 180)
add al,[N1+1] ; add ASCII x0 (48-57 value)
add al,[N2+1] ; add ASCII y0
; max possible AL value = 180 + 57 + 57 = 294
; -> may overflow, but doesn't matter, conversion will "fix" it
sub al,2*'0' ; convert x0,y0 from ASCII to values
; will "fix" overflow by ignoring AH all the time, keeping it 0
; ax = result here (0 to 188 value = fits to 8 bits)
So it's possible to write that Convert PROC
using only ax
, thanks to the 2-digit input constraint (this is far from universal addition routine, using actually every bit of that constraint to keep the code very simple and short).
BTW, if you would use the 386+ (32-bit) instruction set, then *10 can be done in two instructions using the LEA
instruction, like this:
; eax = 0-9 value
add eax,eax ; *2
lea eax,[eax+eax*4] ; *5
This avoids mul
completely, which used to be slow... with the very latest x86 CPUs actually doing imul eax,eax,10
may be faster, because it's single instruction vs two simple ones, but for many years the two additions (add
and lea
) were "cheaper" than single mul
/imul
.
On the original 8086, it would be still faster to do all the adding like this:
; al = 0-9 value
add al,al ; AL = 2*value
mov dl,al ; copy 2*value to DL
add al,al ; AL = 4*value
add al,al ; AL = 8*value
add al,dl ; AL = 10*value
than mul bl
, which would take about 70-77 clocks to compute on original 8086, the code above needs 4*3+2 = 14 clocks only on original 8086.
Upvotes: 2