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.