|
|
View previous topic :: View next topic |
Author |
Message |
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
Hardware division |
Posted: Fri Oct 20, 2017 8:23 am |
|
|
Good day,
How would I code the following in assembly?
Code: | TempMsg = TempMsg/10000; //Gives 1 decimal after point thus 122 will be 12.2A
|
Where TempMsg is a int32 variable.
Using CCS 5.074
dsPIC33EP128GM604 which have a hardware division instruction, can't seem to find a function in CCS which will do what the _mul() do.
Regards[/quote] |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19559
|
|
Posted: Fri Oct 20, 2017 8:35 am |
|
|
You can't.
A float number has no concept of decimal places. In fact it won't even guarantee to hold any number accurately. 33000.1 for example will actually be stored internally as 33000.102 since this is the closest representation possible.
Just store integer 'tenths'. So /1000, so you have 122. Then the %LW output will print this as if it has one decimal.
122 will print as 12.2 etc.. |
|
|
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
Posted: Fri Oct 20, 2017 8:49 am |
|
|
Hi Ttelmah,
Everything is already in integer. I just need to scale by 10000.
So something like 123456 will become 12. this i send through to someone else who will display as 1.2 for instance.
I don't want float and have never used it before.
I want to use the div.sd instruction, but my assembler are not that good, can understand when I read the listing but that is as far as it go. Last time I used assembler with MPLAB was in 1999.
Regards |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Fri Oct 20, 2017 9:35 am |
|
|
Try using the ldiv() function and look at the assembly it generates. I might be misunderstanding what you are looking for though. |
|
|
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
Posted: Fri Oct 20, 2017 10:06 am |
|
|
I'll try again.
I want something similar to the _mul() function
Code: | .................... TempMsg = _mul(iref,Offset);
MOV 101C,W4
MOV 103A,W3
MUL.US W4,W3,W0
MOV W0,1140
MOV W1,1142
|
Code: | TempMsg = TempMsg/10000;
MOV 101C,W4
MOV 103A,W3
MOV 103A,W3 ???
MOV 103A,W3 ???
REPEAT #18 ?????
DIV.SD ??,??,??,W4,W3,W0
MOV W0,1140
MOV W1,1142
|
Edit: Had a look on the web and found that there will probably be a repeat.
Regards |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Fri Oct 20, 2017 10:52 am |
|
|
did you try the ldiv() function?
I don't know off the top of my head if it implements the same or not. It might be different.
The repeat instruction is required for hardware division to work.
EDIT: Here is the relevant blurb from the datasheet:
Quote: |
The 16-bit ALU has been enhanced with integer divide
assist hardware that supports an iterative non-restoring
divide algorithm. It operates in conjunction with the
REPEAT instruction looping mechanism and a selection
of iterative divide instructions to support 32-bit (or
16-bit), divided by 16-bit, integer signed and unsigned
division. All divide operations require 19 cycles to
complete, but are interruptible at any cycle boundary.
|
|
|
|
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
Posted: Fri Oct 20, 2017 1:27 pm |
|
|
Sorry I should have included the asm in previous reply.
Code: | .................... TempMsg = TempMsg/10000; //Gives 1 decimal after point thus 122 will be 12.2A
014FE: BCLR.B 43.0
01500: MOV 1140,W0
01502: MOV 1142,W1
01504: MOV #2710,W2
01506: MOV #0,W3
01508: CALL 13A2
0150C: MOV W0,1140
0150E: MOV W1,1142
.................... TempMsg = ldiv(TempMsg,10000);
01510: PUSH 1140
01512: POP 116A
01514: PUSH 1142
01516: POP 116C
01518: MOV #2710,W4
0151A: MOV W4,116E
0151C: CLR 1170
0151E: CALL 14AE
01522: MOV W0,1140
01524: MOV W1,1142
|
and then the call to 14AE. You will see it end up calling 13A2 which are the same function for the standard divide.
Code: | .................... val.quot = numer / denom;
*
014AE: BCLR.B 43.0
014B0: MOV 116A,W0
014B2: MOV 116C,W1
014B4: MOV 116E,W2
014B6: MOV 1170,W3
014B8: CALL 13A2
014BC: MOV W0,1172
014BE: MOV W1,1174
.................... val.rem = numer - (denom * val.quot);
014C0: MOV 116E,W0
014C2: MOV 1170,W1
014C4: MOV 1172,W2
014C6: MOV 1174,W3
014C8: CALL 146C
014CC: MOV 116A,W4
014CE: SUB W4,W0,W0
014D0: MOV W0,1176
014D2: MOV 116C,W4
014D4: SUBB W4,W1,W0
014D6: MOV W0,1178
.................... return (val);
014D8: MOV 1172,W0
014DA: MOV 1174,W1
014DC: MOV 1176,W2
014DE: MOV 1178,W3
014E0: RETURN |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19559
|
|
Posted: Fri Oct 20, 2017 2:08 pm |
|
|
A standard integer division does what he is describing.
The point about ldiv, is it gives you access to the remainder, which he is not talking about.
Key is that there is no equivalent to mul. A numeric multiplication can overflow. The point about mul is you start with two smaller numbers (8 bit say), and keep the overflow to give you a 16bit result. On a division, you need to be using the larger maths type to actually perform the division. You can simply just take the smaller result when finished.
Declare a structure containing two int16's 'MSW & LSW'. Then declare a union between this and the int32. Simply perform a standard division by 10000, and then access the LSW as the result. No casting needed, and you are now using the smaller type. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|