Exponentiation operation on assembler...

Hello all.

Hope this is the right place to post in…
I’m trying to implement exponentiation of a number in assembler language (for the 8051 processor in this case). I’m trying by using the MUL instruction, which does the multiplication of 2 numbers stored in registers A (accumulator) and B, and puts the lower 8 bits in A and the upper ones in B. So the exercise is, I have initially numbers in A and B, and we want the operation A^B leaving lower 8 bits in A and upper ones in B.

I’m trying first with a particular case: 3^10. I already have part of the overall idea, I’m making a loop that multiplies A itself B number of times, making 8 bit multiplications (obviously storing previous results in other R registers). When I reach the 6th power the upper 8 bits (register B) begins to be used. I did the following binary multiplications in calculator apart in 2 ways: taking all the 8+ bits and taking only the lower 8 bits. Compared and realized that in both cases the lower 8 bits remain the same, only the upper 8 bits changing.

So the idea of doing 8-bit multiplications seems good. My problems are, I just have no clue of how to gradually do the arrangements on the upper 8 bits, nor I know how to stop the program if the result exceeds the 16 total bits (according to MUL’s instruction manual, the overflow flag sets when the product exceeds 255, not 65535, where it’s actually needed!).

Can you help me by chance?
Thank you beforehand.

Not a direct answer to your question (since I have not touched a 8 bit
micro controller during the last 25 years), but since you got no answer
till now I wonder why you did not post your question on a uC forum in
the first place.
If I were you I would just look for a 8051 forum as this programming
question has nothing to do with Linux or any architecture on which Linux
runs (probably not many 8051 assembler programmers here).


PC: oS 12.2 x86_64 | i7-2600@3.40GHz | 16GB | KDE 4.10.1 | GTX 650 Ti
ThinkPad E320: oS 12.2 x86_64 | i3@2.30GHz | 8GB | KDE 4.10.1 | HD 3000
eCAFE 800: oS 12.2 i586 | AMD Geode LX 800@500MHz | 512MB | KDE 3.5.10

On 2013-03-11, F style <F_style@no-mx.forums.opensuse.org> wrote:
>
> Hello all.
>
> Hope this is the right place to post in…
> I’m trying to implement exponentiation of a number in assembler
> language (for the 8051 processor in this case). I’m trying by using the
> MUL instruction, which does the multiplication of 2 numbers stored in
> registers A (accumulator) and B, and puts the lower 8 bits in A and the
> upper ones in B. So the exercise is, I have initially numbers in A and
> B, and we want the operation A^B leaving lower 8 bits in A and upper
> ones in B.

I code IA32/64 assembler every day and have no clue about 8051 instructions. I frequently encounter such problems
(although mixing 8-bit with 16-bit operations would be a new one for me!) and my first approach to tackle them is to
code a solution in straight C using the correct data types (in this case you need to combine char and int). If you can’t
code it in C, then no assembler will help you. The assembler only gives you register control to make your code execute
faster than software-compiled assembler.

On 2013-03-11, F style <F_style@no-mx.forums.opensuse.org> wrote:
> I’m trying first with a particular case: 3^10. I already have part of
> the overall idea, I’m making a loop that multiplies A itself B number of
> times, making 8 bit multiplications (obviously storing previous results
> in other R registers). When I reach the 6th power the upper 8 bits
> (register B) begins to be used. I did the following binary
> multiplications in calculator apart in 2 ways: taking all the 8+ bits
> and taking only the lower 8 bits. Compared and realized that in both
> cases the lower 8 bits remain the same, only the upper 8 bits changing.

Well then your code is obviously wrong. For 3^n, as n increases, sure you need more bits once n >= 6, since the result
(729) is greater than 255. But (3^n % 256) is not constant afterwards unless you are multiplying only by factors of 256!

> So the idea of doing 8-bit multiplications seems good. My problems are,
> I just have no clue of how to gradually do the arrangements on the upper
> 8 bits, nor I know how to stop the program if the result exceeds the 16
> total bits (according to ‘MUL’s instruction manual’
> (http://www.keil.com/support/man/docs/is51/is51_mul.htm), the overflow
> flag sets when the product exceeds 255, not 65535, where it’s actually
> needed!).

Presumably the 8051 doesn’t support floating point instructions so you’re stuck with integers. If your CPU has an
8-bit architecture (which it seems to me), you can’t blame it for setting the overflow limit at 255! The odd
multiplication instruction (16-bit product = 8-bit multiplicahend * 8-bit multiple) is probably the exception that
yields 16-bit results. The only solution I can think of around this weird implementation is having a database integer
array of size 256 whose elements consist of the maximum power allowed before reaching overflow.

e.g. (in C notation) let:


short* maxpow = short[256];
maxpow[0] = -1;
maxpow[1] = -1;
maxpow[2] = 16;
maxpow[3] = 10;
maxpow[4] = 8;
etc...
maxpow[255] = 2;

so in your 16-bit assembler (haven’t done for years!! - but it seems similar to 8051 8-bit - not that Intel syntax is
[MOV DESTINATION, SOURCE]):


mov ax, [multiplicahend];
mov dx, [multiple];
mov si, maxpow;
mov di, [si+ax*2];
cmp dx, di;
jg branch_overflow;
.... then do the serial multiplication ...

… but there may be a more elegant solution for the 8051, so it would be worth checking with forum fluent in 8051
assembler.

On 2013-03-11, F style <F_style@no-mx.forums.opensuse.org> wrote:
>
> Hello all.
>
> Hope this is the right place to post in…
> I’m trying to implement exponentiation of a number in assembler
> language (for the 8051 processor in this case). I’m trying by using the
> MUL instruction, which does the multiplication of 2 numbers stored in
> registers A (accumulator) and B, and puts the lower 8 bits in A and the
> upper ones in B. So the exercise is, I have initially numbers in A and
> B, and we want the operation A^B leaving lower 8 bits in A and upper
> ones in B.

I code IA32/64 assembler every day and have no clue about 8051 instructions. I frequently encounter such problems
(although mixing 8-bit with 16-bit data types in a single operations would be a new one for me!) and my first approach
to tackle them is to code a solution in straight C using the correct data types (in this case you need to combine char
and int). If you can’t code it in C, then no assembler will help you. The assembler only gives you register control to
make your code execute faster than software-compiled assembler.

On 2013-03-11, F style <F_style@no-mx.forums.opensuse.org> wrote:
> I’m trying first with a particular case: 3^10. I already have part of
> the overall idea, I’m making a loop that multiplies A itself B number of
> times, making 8 bit multiplications (obviously storing previous results
> in other R registers). When I reach the 6th power the upper 8 bits
> (register B) begins to be used. I did the following binary
> multiplications in calculator apart in 2 ways: taking all the 8+ bits
> and taking only the lower 8 bits. Compared and realized that in both
> cases the lower 8 bits remain the same, only the upper 8 bits changing.

Well then your code is obviously wrong. For 3^n, as n increases, sure you need more bits once n >= 6, since the result
(729) is greater than 255. But (3^n % 256) is not constant afterwards unless you are summing only by factors of 256! I
strongly suspect your serial multiplying strategy won’t work because after the product has exceeded 255, I cannot see
how 8051 MUL will accept 16-bit multiplicahends.

> So the idea of doing 8-bit multiplications seems good. My problems are,
> I just have no clue of how to gradually do the arrangements on the upper
> 8 bits, nor I know how to stop the program if the result exceeds the 16
> total bits (according to ‘MUL’s instruction manual’
> (http://www.keil.com/support/man/docs/is51/is51_mul.htm), the overflow
> flag sets when the product exceeds 255, not 65535, where it’s actually
> needed!).

Presumably the 8051 doesn’t support floating point instructions so you’re stuck with integers. If your CPU has an
8-bit architecture (which it seems to me), you can’t blame it for setting the overflow limit at 255! The odd
multiplication instruction (16-bit product = 8-bit multiplicahend * 8-bit multiple) is probably the exception that
yields 16-bit results. The only solution I can think of around this weird implementation is having a database integer
array of size 256 whose elements consist of the maximum power allowed before reaching overflow.

e.g. (in C notation) let:


unsigned short* maxpow = new unsigned short[256];
maxpow[0] = -1;
maxpow[1] = -1;
maxpow[2] = 16;
maxpow[3] = 10;
maxpow[4] = 8;
etc...
maxpow[255] = 2;

so in your 16-bit assembler (haven’t done for years!! - but it seems similar to 8051 8-bit - note that Intel syntax is
[MOV DESTINATION, SOURCE]):


mov ax, [base];
mov dx, [power];
mov si, maxpow;
mov di, [si+ax*2];
cmp dx, di;
jg branch_overflow;
.... then do the serial multiplication ...

… but there may be a more elegant solution for the 8051, so it would be worth checking on forums frequented by those
fluent in 8051 assembler.

On 2013-03-11, F style <F_style@no-mx.forums.opensuse.org> wrote:
>
> Hello all.
>
> Hope this is the right place to post in…
> I’m trying to implement exponentiation of a number in assembler
> language (for the 8051 processor in this case). I’m trying by using the
> MUL instruction, which does the multiplication of 2 numbers stored in
> registers A (accumulator) and B, and puts the lower 8 bits in A and the
> upper ones in B. So the exercise is, I have initially numbers in A and
> B, and we want the operation A^B leaving lower 8 bits in A and upper
> ones in B.

I code IA32/64 assembler every day and have no clue about 8051 instructions. I frequently encounter such problems
(although mixing 8-bit with 16-bit data types within a single operation would be a new one for me!) and my first
approach to tackle them is to code a solution in straight C using the correct data types (in this case you need to
combine char and int). If you can’t code it in C, then no assembler will help you. The assembler only gives you register
control to make your code execute faster than software-compiled assembler.

On 2013-03-11, F style <F_style@no-mx.forums.opensuse.org> wrote:
> I’m trying first with a particular case: 3^10. I already have part of
> the overall idea, I’m making a loop that multiplies A itself B number of
> times, making 8 bit multiplications (obviously storing previous results
> in other R registers). When I reach the 6th power the upper 8 bits
> (register B) begins to be used. I did the following binary
> multiplications in calculator apart in 2 ways: taking all the 8+ bits
> and taking only the lower 8 bits. Compared and realized that in both
> cases the lower 8 bits remain the same, only the upper 8 bits changing.

Well then your code is obviously wrong. For 3^n, as n increases, sure you need more bits once n >= 6, since the result
(729) is greater than 255. But (3^n % 256) is not constant afterwards unless you are progressively summing only by
factors of 256! I strongly suspect your serial multiplying strategy won’t work because I cannot see how 8051 MUL could
deal with 16-bit multiplicahend inputs.

> So the idea of doing 8-bit multiplications seems good. My problems are,
> I just have no clue of how to gradually do the arrangements on the upper
> 8 bits, nor I know how to stop the program if the result exceeds the 16
> total bits (according to ‘MUL’s instruction manual’
> (http://www.keil.com/support/man/docs/is51/is51_mul.htm), the overflow
> flag sets when the product exceeds 255, not 65535, where it’s actually
> needed!).

Presumably the 8051 doesn’t support floating point instructions so you’re stuck with integers. If your CPU has an
8-bit architecture (which it seems to me), you can’t blame it for setting the overflow limit at 255! The odd
multiplication instruction (16-bit product = 8-bit multiplicahend * 8-bit multiple) is probably the exception that
yields 16-bit results. The only solution I can think of around this weird implementation is having a database integer
array of size 256 whose elements consist of the maximum power allowed before reaching overflow.

e.g. (in C notation) let:


unsigned short* maxpow = new unsigned short[256];
maxpow[0] = -1;
maxpow[1] = -1;
maxpow[2] = 16;
maxpow[3] = 10;
maxpow[4] = 8;
etc...
maxpow[255] = 2;

so in your 16-bit assembler (haven’t done for years!! - but it seems similar to 8051 8-bit - note that Intel syntax is
[MOV DESTINATION, SOURCE]):


mov ax, [base];
mov dx, [power];
mov si, maxpow;
mov di, [si+ax*2];
cmp dx, di;
jg branch_overflow;
.... then do the serial multiplication ...

… but there may be a more elegant solution for the 8051, so it would be worth checking on a forum frequented by those
fluent in 8051 assembler.

On 2013-03-11, flymail <flymail@no-mx.forums.opensuse.org> wrote:
> my first
> approach to tackle them is to code a solution in straight C using the correct data types (in this case you need to
> combine char and int).

Obvious correction: `char and short’ I meant!

On 3/10/2013 9:16 PM, F style wrote:
>
> Hello all.
>
> Hope this is the right place to post in…
> I’m trying to implement exponentiation of a number in assembler
> language (for the 8051 processor in this case). I’m trying by using the
> MUL instruction, which does the multiplication of 2 numbers stored in
> registers A (accumulator) and B, and puts the lower 8 bits in A and the
> upper ones in B. So the exercise is, I have initially numbers in A and
> B, and we want the operation A^B leaving lower 8 bits in A and upper
> ones in B.
>
> I’m trying first with a particular case: 3^10. I already have part of
> the overall idea, I’m making a loop that multiplies A itself B number of
> times, making 8 bit multiplications (obviously storing previous results
> in other R registers). When I reach the 6th power the upper 8 bits
> (register B) begins to be used. I did the following binary
> multiplications in calculator apart in 2 ways: taking all the 8+ bits
> and taking only the lower 8 bits. Compared and realized that in both
> cases the lower 8 bits remain the same, only the upper 8 bits changing.
>
> So the idea of doing 8-bit multiplications seems good. My problems are,
> I just have no clue of how to gradually do the arrangements on the upper
> 8 bits, nor I know how to stop the program if the result exceeds the 16
> total bits (according to ‘MUL’s instruction manual’
> (http://www.keil.com/support/man/docs/is51/is51_mul.htm), the overflow
> flag sets when the product exceeds 255, not 65535, where it’s actually
> needed!).
>
> Can you help me by chance?
> Thank you beforehand.
>
>
F style;
This looks a lot like a homework problem so this is only a hint. You do the
multiplication the same way that you would with pencil and paper. Just think of
an intermediate product as a two digit number xy (x and y are base 256 digits)
to multiply xy by 3. First multiply x by 3. This will give you the first digit
of the product and an amount to carry. Next multiply y by 3, add in the carry
from the first step and this gives you the second digit of your product. You
should be able to extend this idea to an unlimited number of digits in the product.


P.V.
“We’re all in this together, I’m pulling for you” Red Green

On 3/11/2013 2:06 PM, PV wrote:
<snip>

> F style;
> This looks a lot like a homework problem so this is only a hint. You do the
> multiplication the same way that you would with pencil and paper. Just think of
> an intermediate product as a two digit number xy (x and y are base 256 digits)
> to multiply xy by 3. First multiply x by 3. This will give you the first digit
> of the product and an amount to carry. Next multiply y by 3, add in the carry
> from the first step and this gives you the second digit of your product. You
> should be able to extend this idea to an unlimited number of digits in the product.
>
Note: In the above x is the least significant byte.


P.V.
“We’re all in this together, I’m pulling for you” Red Green

@Venzkep:
Very thanks for your help! Though that was actually the “arrangement” for the upper byte, instead of hint you almost gave me the answer… But thank you very much.

Now I have a little doubt. According to the instruction manual of which I posted link above, when using the MUL instruction the overflow flag is set when the product exceeds 255. Does it mean the upper byte’s product (register B)? If it was I could finally use it as condition for stopping the program when product exceeded 16 bits…

On 3/12/2013 12:16 AM, F style wrote:
>
> @Venzkep:
> Very thanks for your help! Though that was actually the “arrangement”
> for the upper byte, instead of hint you almost gave me the answer… But
> thank you very much.
>
> Now I have a little doubt. According to the instruction manual of which
> I posted link above, when using the MUL instruction the overflow flag is
> set when the product exceeds 255. Does it mean the upper byte’s product
> (register B)? If it was I could finally use it as condition for stopping
> the program when product exceeded 16 bits…
>
>
F style;

Google is your friend, just look for “8051 instruction set”. Carefully read the
write up on the MUL instruction, I think it is clear. Remember you need to use
the MUL command twice, once for the LSB and again for the MSB.


P.V.
“We’re all in this together, I’m pulling for you” Red Green