16bit/16bit division by using assembly

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,

In my application I am required to do a 16 bit by 16 bit division by using assembly language, it is not a problem if by using C language but my whole code are written in assembly, and also it is not a problem if the dividend is bigger than divisor, however, in my application the dividend is definitely bigger than divisor, the result is expected to be 0.1--0.5.

Anyone have idea about this division in assembly? I also consider if by this way was too fussy, I have to mix some C function in my assembly codes, I know GCC assembler can do this job, right? Could anyone show me some sample codes?

Thanks a lot

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One easy way is to get GCC, then make a simple program with the muls, divs, whatever, generate a .LST file (assembly source) and get the assembly routines (they are at the end of the file).
As for the less than unit results, you can use fixed point math. Just set some power of 2 to be 1 (the unit), like 256 ( 2^8 ). Then you can have and process real numbers, with a certain precision (given by how big is your unit). The subject is extensive, just Google for it.

Embedded Dreams
One day, knowledge will replace money.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You don't mention if the numbers are signed or unsigned so I expect hey are unsigned. You also want a non-integer result.
I would probably implement a 32-bit by 32-bit divide with the numbers loaded into the upper 2 bytes and leaving the lower bytes as zeros. Then you can treat the 32-bit values as shifted 16-bit ones with the lower 16 bits of the result as the fraction you require.
EG 0x00008000 = 0.5, 0x00004000 = 0.25 etc.

I have coded for about 2 dozen architectures, and they all have their place.
Don't get too religious about them (but AVR is excellent!)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First, look at Atmel app notes on "16 Bit Arithmetics", AVR202 IIRC and "Multiply and Divide Routines" AVR200.

Then exercise the search feature on the forum (and hope the right hits are indexed ;) ). There were extensive discussions several years back, including some 24-bit stuff that might work well for you.

There may also be projects posted for extended arithmetic.

Or just write in C. :)

https://www.avrfreaks.net/index.p...

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks everyone for the hints. Actually I tracked lots of threads in the past years, but still a bit lost since the information is too much.

I am thinking if I can do the following:
Multiply the dividend by 2, then it will be bigger than the divisor(only feasible in my application) -> then right shift the result 1 bit. For instance, I have 0110 1011/0111 1010, I firstly do unsigned 1101 0110/0111 1011, after I get a result, I divide the result by 2.

Now I can get the result and remainder, however this is not the final step, later I will use this value in other calculations, what should I do?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Paul Turner wrote:
You don't mention if the numbers are signed or unsigned so I expect hey are unsigned. You also want a non-integer result.
I would probably implement a 32-bit by 32-bit divide with the numbers loaded into the upper 2 bytes and leaving the lower bytes as zeros. Then you can treat the 32-bit values as shifted 16-bit ones with the lower 16 bits of the result as the fraction you require.
EG 0x00008000 = 0.5, 0x00004000 = 0.25 etc.

Sorry I forgot to mention, the calculation is unsigned.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

longwaytogo wrote:
Thanks everyone for the hints. Actually I tracked lots of threads in the past years, but still a bit lost since the information is too much.

I am thinking if I can do the following:
Multiply the dividend by 2, then it will be bigger than the divisor(only feasible in my application) -> then right shift the result 1 bit. For instance, I have 0110 1011/0111 1010, I firstly do unsigned 1101 0110/0111 1011, after I get a result, I divide the result by 2.

Now I can get the result and remainder, however this is not the final step, later I will use this value in other calculations, what should I do?

This won't work, after division you'll get (in your example) 0x01, then after the /2 (>>1) that bit will be shifted off and you'l end up with 0x00.
If 0.5 is maximum possible result you can get then left shift your dividend by 16 (<<16) after casting it to 32 bits (this is from your original question with 16 bit vars) do the divide then cast back to 16bits. This will discard the integer portion. 0x8000 will be equivalent to 0.5, 0xFFFF will be almost-but-not-quite 1.0.

Edward

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
This will discard the integer portion. 0x8000 will be equivalent to 0.5, 0xFFFF will be almost-but-not-quite 1.0.

Edward

Thanks Edward for the quick reply, if dont bother too much could you explain the quoted part more specifically? Thanks a lot.

And by the way I am not quite understand, make the dividend to 32 bits. Then I will do division as 32bit/16bit, right? Now the result is already 16bits, how could I cast it back to 16bits and discard the integer part?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is so called fixed point maths. Instead of having a variable power like in floating point maths you have to keep track of where your decimal point would be. In this case we are pretending that the decimal point is between the 16th and the non-existent 17th digits. For normal integer maths the decimal point is below the LSB.

The result wouldn't always be 16bits in a division, say you divide 0xFB4C7156 by 0x0003, you're going to end up with a result bigger than 16bits. It's only in the special case where the original 16 bit dividend is smaller than the 16 divisor that you will end up with a result that will fit into 16 bits. If you can't guarantee that the result will be then you will need to add checks to make sure.

Edward

PS all that about casting to various variable sizes is because I didn't notice you were using assembly, it really applies to C.