Home > Archive > A86 Assembler > May 2006 > Simple multiplication program error (beginner help)
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Simple multiplication program error (beginner help)
|
|
| sathyashrayan 2006-05-07, 6:59 pm |
| Dear group,
I have a bit of experience with C/C++ but my new
course curriculum wants me to learn x86 asm. I am
asked to use TASM , with tlink. This is my first
ever program in asm, so kindly bare this beginner.
"Write a program which will read two decimal numbers
then multiply them together, and finally print out the
reault(in decimal)"
code:
^^^^
data segment
a db 10h
b db 10h
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov ah,01h
int 21h
mov a,al
mov ah,01h
int 21h
mov b,al
mov al,a
mov bl,b
mul bl
mov ax,004ch
int 21h
code ends
end start
I know I did not do the mandatory thing,input should be a integer.
But the above program just gives a runtime error.Pls help me.
| |
| randyhyde@earthlink.net 2006-05-07, 6:59 pm |
|
sathyashrayan wrote:
> Dear group,
> I have a bit of experience with C/C++ but my new
> course curriculum wants me to learn x86 asm. I am
> asked to use TASM , with tlink. This is my first
> ever program in asm, so kindly bare this beginner.
>
>
>
> "Write a program which will read two decimal numbers
> then multiply them together, and finally print out the
> reault(in decimal)"
>
> code:
> ^^^^
> data segment
>
> a db 10h
> b db 10h
>
> data ends
>
> code segment
> assume cs:code,ds:data
> start:
> mov ax,data
> mov ds,ax
>
> mov ah,01h
> int 21h
> mov a,al
>
> mov ah,01h
> int 21h
> mov b,al
>
> mov al,a
> mov bl,b
> mul bl
>
> mov ax,004ch
> int 21h
> code ends
> end start
>
>
> I know I did not do the mandatory thing,input should be a integer.
> But the above program just gives a runtime error.Pls help me.
Well, if you *must* run under DOS, you should go grab a copy of the
"UCR Standard Library for 80x86 Assembly Language Programmers" at
http://webster.cs.ucr.edu/AsmTools/MASM/MASMLibs.html
(which works fine with TASM). It contains numeric input and output
routines that you can call. You might also want to check on the 16-bit
edition of "The Art of Assembly Language" on Webster
(http://webster.cs.ucr.edu).
There's also a 32-bit edition, which uses the HLA (high-level
assembler). But it sounds like you've got a class project and if your
instructor requires you to use TASM, this last suggestion won't be of
much help.
Cheers,
Randy Hyde
| |
| Frank Kotler 2006-05-07, 6:59 pm |
| sathyashrayan wrote:
> Dear group,
> I have a bit of experience with C/C++ but my new
> course curriculum wants me to learn x86 asm.
Bummer, huh?
> I am
> asked to use TASM , with tlink.
Mmmm. I guess they wanted something stable that wouldn't be coming out
with confusing new versions all the time. The best part of Tasm is TD
(the debugger). I hope you've got it. As I recall, the switches are "/z"
to Tasm, and "/v" to Tlink, to generate "symbolic debugging info".
Figure out how to use TD - I'll make life easier!
> This is my first
> ever program in asm, so kindly bare this beginner.
:) Normally, I wouldn't mention a mistake in English, but this one's
funny. Look up the difference between "bear" and "bare". :)
> "Write a program which will read two decimal numbers
> then multiply them together, and finally print out the
> reault(in decimal)"
Okay... it doesn't say how large a number you're supposed to handle.
What you've got so far only handles a single keystroke - numbers from 0
to 9. Is that enough? Chances are, you're supposed to handle multi-digit
numbers. A number from 0 to 255 will fit in a byte. A word will hold
from 0 to 65535. You can use 32-bit registers in a 16-bit dos file, or
you can use two 16-bit registers, if you need to go bigger than that.
> code:
> ^^^^
> data segment
>
> a db 10h
> b db 10h
>
> data ends
>
> code segment
> assume cs:code,ds:data
> start:
> mov ax,data
> mov ds,ax
>
> mov ah,01h
> int 21h
Okay, this waits for the user to hit a key. Hopefully, they've hit a
number key - we better check, those users can be awfully careless!
What's returned in al is the ascii code of the key - numbers 1 to 9 have
ascii codes of 30h to 39h (or 48 to ??? decimal). To get a "number", we
have to subtract 30h - your assembler will understand:
sub al, '0'
and it might be clearer than:
sub al, 30h ; or sub al, 48
Another way you could do it, since the number we're looking for is in
the low nibble, is:
and al, 0Fh
Here's where we could check to make sure we've got a valid decimal
digit. If we stick with "sub"...
sub al, '0'
The carry flag will be set if al was less than 30h ('0'), so,
jc invalid
cmp al, 9 ; too big? (note we've got a number now)
ja invalid
Where "invalid" is a label on code to handle it - print a message and
quit, or re-try the input. Silently producing a "wrong answer" is not good!
> mov a,al
Now you can save it in your variable. Incidentally, "a" is a lousy name
for a variable - call it something that means something! "first_number"
or something...
> mov ah,01h
> int 21h
> mov b,al
Same thing here - "convert" from a character to a number before you save
it. (won't hurt to duplicate the code, but this would make a good
subroutine...)
> mov al,a
> mov bl,b
> mul bl
This should work okay. Now you've got the chore of printing the result -
which can be more than one digit, even if we only allowed a single digit
input. We obviously can't print "81" as a single character!
The "div" instruction gives us a quotient and a remainder - if we divide
by ten (for decimal representation of the number), repeatedly, the
remainder(s) are the numbers we want - we'll have to "convert" them to
characters by adding '0' - but in the wrong order. One way to deal with
this is to start at the "end" of a buffer, and work forward as you get
characters. Another way is to push characters on the stack as we get 'em
(and count 'em - or push a "guard" value first), then pop 'em off the
stack and print 'em. Our result, after the "mul bl" is in ax...
mov bx, 10 ; divide by ten
xor cx, cx ; zero cx for a counter
push_loop:
xor dx, dx ; "div" works on dx:ax, not just ax !!!
; this always bites newbies! :)
div bx ; quotient in ax, remainder in dx
add dx, '0' ; "convert" it to character
push dx ; stash it away
inc cx ; count it
cmp ax, 0 ; if quotient is zero, we're done
jnz push_loop ; else do more
mov ah, 2 ; "print char in dl" function
pop_loop:
pop dx ; get a char back
int 21h ; print it
loop pop_loop ; until done (loops cx times)
> mov ax,004ch
Oh, oh!!! You want "mov ax, 4C00h" here! (or "mov ah, 4Ch"... put an
errorlevel in al if there was overflow or invalid input?) This may be
why you're getting the runtime error.
> int 21h
> code ends
> end start
>
>
> I know I did not do the mandatory thing,input should be a integer.
Well... the input is inevitably characters. You need to "convert" to
integer. If you want to handle more than one...
Get a character.
User hit "enter"? If so, exit loop.
Got a valid decimal digit?
Convert it to a number - "sub al, '0'".
Multiply your result so far by ten.
Add the new digit to result.
Get another character.
> But the above program just gives a runtime error.
Probably the "mov ax, 004Ch"... (???). You're on the right track.
> Pls help me.
You should be able to find examples of this all over the net. Randy
suggested http://webster.cs.ucr.edu - the old "UCR Standard Library".
You can "just call it" (easiest, but you don't learn how to do it), or
you can examine the code and see how to write your own version. Or you
could study it and learn how it works and then just call it.
Programmer's choice (or perhaps instructor's choice, in your case :) The
whole site is a tremendous resource! You'll probably also want Ralf
Brown's Interrupt List - http://www.pobox.com/~ralf I think.
Does your "new course curriculum" not provide help?
Best,
Frank
| |
| Terje Mathisen 2006-05-07, 6:59 pm |
| Frank Kotler wrote:
> sathyashrayan wrote:
>
> Bummer, huh?
>
>
> Mmmm. I guess they wanted something stable that wouldn't be coming out
> with confusing new versions all the time. The best part of Tasm is TD
> (the debugger). I hope you've got it. As I recall, the switches are "/z"
> to Tasm, and "/v" to Tlink, to generate "symbolic debugging info".
> Figure out how to use TD - I'll make life easier!
>
>
> :) Normally, I wouldn't mention a mistake in English, but this one's
> funny. Look up the difference between "bear" and "bare". :)
>
>
> Okay... it doesn't say how large a number you're supposed to handle.
> What you've got so far only handles a single keystroke - numbers from 0
> to 9. Is that enough? Chances are, you're supposed to handle multi-digit
> numbers. A number from 0 to 255 will fit in a byte. A word will hold
> from 0 to 65535. You can use 32-bit registers in a 16-bit dos file, or
> you can use two 16-bit registers, if you need to go bigger than that.
For extra credit, I'd write a program which did everything in decimal
(or even ascii?), i.e:
Read in number 1, store it directly after subracting '0' (48 in ascii)
from each digit. Remember how long it is!
Do the same for number 2.
Do the multiplication the old-fashioned way, multiplying every digit in
(1) by every digit in (2), adding all these sums (properly shifted of
course!) together.
Propagate all the carries.
Print out the result.
To avoid all memory allocation problems, you could simply push all the
digits on the stack as you read them, then reserve an additional area as
big as the sum of the two lengths on top of this:
Cheating just a little bit by requiring the numbers to be given on the
command line makes the program more useful, and gives you fixed limits
on the size of the numbers!
PS. If you do go the decimal way, please notice that if you work from
the least significant digits forward, you can generate the result
directly, in the same order. Push these resulting digits on the stack as
you do so, then pop them off afterwards to print in the proper direction:
perl pseudocode (not tested at all!):
sub ascii_mul
{
local ($a, $b) = @_;
my ($al, $bl) = (length($a), length($b));
my ($i, $result, $digitsum) = ();
for ($i = 0; $i < $al+$bl; $i++) {
for ($j = $i; $j >= 0; $j--) {
$digitsum += (ord(substr($a,$al-1-$j,1)) & 15) *
(ord(substr($b,$bl-1-$i+$j,1)) & 15);
}
$result = chr($digitsum % 10) . $result;
$digitsum /= 10;
}
$result = chr($digitsum % 10) . $result
if ($digitsum);
return $result;
}
Terje
--
- <Terje.Mathisen@hda.hydro.com>
"almost all programming can be viewed as an exercise in caching"
|
|
|
|
|