CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Multiply 8-bit*8-bit = 16-bit

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
hhoebel
Guest







Multiply 8-bit*8-bit = 16-bit
PostPosted: Wed Jul 09, 2003 3:47 am     Reply with quote

I want to multiply a 8-bit var with a 8-bit litteral using a PIC18F1320 with hardware-multiplier (var16 = var8 * const.). CCS 3.165 produces the correct call of MULLW, but the result is truncated to 8-bit. Example code:

0014 0D36 00017 MULLW 36
0016 50F3 00018 MOVF FF3,W
0018 6A07 00019 CLRF 07
001A 6E06 00020 MOVWF 06

As you can see the ccs clears the upper byte of the 16-bit var. When using var16 = (unsigned int16)var8 * const instead it works, but ccs uses much more code for this instead of simply using the 16-bit-result of the hardware-multiplier.
This is really odd :-(

Any idea how to get around this?

regards,

Heiko
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515805
R.J.Hamlett
Guest







Re: Multiply 8-bit*8-bit = 16-bit
PostPosted: Wed Jul 09, 2003 4:06 am     Reply with quote

:=I want to multiply a 8-bit var with a 8-bit litteral using a PIC18F1320 with hardware-multiplier (var16 = var8 * const.). CCS 3.165 produces the correct call of MULLW, but the result is truncated to 8-bit. Example code:
:=
:=0014 0D36 00017 MULLW 36
:=0016 50F3 00018 MOVF FF3,W
:=0018 6A07 00019 CLRF 07
:=001A 6E06 00020 MOVWF 06
:=
:=As you can see the ccs clears the upper byte of the 16-bit var. When using var16 = (unsigned int16)var8 * const instead it works, but ccs uses much more code for this instead of simply using the 16-bit-result of the hardware-multiplier.
:=This is really odd :-(
:=
:=Any idea how to get around this?
:=
:=regards,
:=
:=Heiko
Yes.
Remember the default integer type is 8bit. You are multiplying two 8bit values (which implies 8bit multiplication), and then transferring the result to a 16bit value. Hence the truncation. To avoid this, you need to tell the compiler to treat the values as 16bit.
Hence (using two 8bit values 'a', and 'b', and the 16bit result in 'c'):

c=(int16)a*(int16)b;

Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515807
hhoebel
Guest







Multiply 8-bit*8-bit = 16-bit
PostPosted: Wed Jul 09, 2003 4:12 am     Reply with quote

:=c=(int16)a*(int16)b;

Sure, i know that this works, but the ccs compiles this to a much to long constuction. It uses two hardware multiplies to get the result which isn't really needed. A single multiply will provide the correct result.

I'm tending to make a multiply-subroutine for this myself.
If would look like this:

unsigned int16 Mul(unsigned int8 A, unsigned int8 B)
{
#asm
movf A,W
mulwf B
movff 0xFF3,_return_
movff 0xFF4,_return_+1
#endasm
}

This works with exception of the "_return_+1" (compiler says: Expression must evaluate to a constant). Any idea how to return a 16-bit-result from assembler?
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515809
hhoebel
Guest







Multiply 8-bit*8-bit = 16-bit
PostPosted: Wed Jul 09, 2003 4:34 am     Reply with quote

:= movff 0xFF4,_return_+1

I've found how to do this: movff 0xFF4,(&_return_+1).

Never used C-syntax from within assembler before:-(
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515811
R.J.Hamlett
Guest







Re: Multiply 8-bit*8-bit = 16-bit
PostPosted: Wed Jul 09, 2003 4:45 am     Reply with quote

:=:=c=(int16)a*(int16)b;
:=
:=Sure, i know that this works, but the ccs compiles this to a much to long constuction. It uses two hardware multiplies to get the result which isn't really needed. A single multiply will provide the correct result.
:=
:=I'm tending to make a multiply-subroutine for this myself.
:=If would look like this:
:=
:=unsigned int16 Mul(unsigned int8 A, unsigned int8 B)
:={
:= #asm
:= movf A,W
:= mulwf B
:= movff 0xFF3,_return_
:= movff 0xFF4,_return_+1
:= #endasm
:=}
:=
:=This works with exception of the "_return_+1" (compiler says: Expression must evaluate to a constant). Any idea how to return a 16-bit-result from assembler?
Yes.
It is beautifully 'undocumented'...
Try this:

unsigned int16 Mul(unsigned int8 A, unsigned int8 B)
{
#asm
movf A,W
mulwf B
movff 0xFF3,_return_
movff 0xFF4,&_return_+1
#endasm
}

The '&', used in this context, seems to make the compiler add one to the address reflected by '_return_', and use this!...

Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515812
Chang-Huei Wu
Guest







Re: Multiply 8-bit*8-bit = 16-bit
PostPosted: Wed Jul 09, 2003 9:29 am     Reply with quote

:=:= movff 0xFF4,_return_+1
:=
:=I've found how to do this: movff 0xFF4,(&_return_+1).
:=
:=Never used C-syntax from within assembler before:-(

one more funny way to do it with CCS ...

int16 mul_prod ;
#byte mul_prod = 0x0ff3

int16 mul_u8(int8 a, int8 b)
{
a * b; return ( mul_prod );
}

it turns out to be ...

.................... int16 mul_u8(int8 a, int8 b)
.................... {
.................... a * b; return ( mul_prod );
*
0022: MOVF 11,W
0024: MULWF 12
0026: MOVF FF3,W
0028: MOVWF 01
002A: MOVF FF4,W
002C: MOVWF 02
.................... }
002E: GOTO 1030 (RETURN)

and I got a warning ... Code has no effect

but, it works with exactly the same speed and ROM size as
the in-line assembly.


Best wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515822
hhoebel
Guest







Multiply 8-bit*8-bit = 16-bit
PostPosted: Thu Jul 10, 2003 2:46 am     Reply with quote

:=one more funny way to do it with CCS ...

Many thanks for that. Helps to understand what the compiler does.

regards,

Heiko
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515834
R.J.Hamlett
Guest







Re: Multiply 8-bit*8-bit = 16-bit
PostPosted: Thu Jul 10, 2003 3:46 am     Reply with quote

:=:=:= movff 0xFF4,_return_+1
:=:=
:=:=I've found how to do this: movff 0xFF4,(&_return_+1).
:=:=
:=:=Never used C-syntax from within assembler before:-(
:=
:=one more funny way to do it with CCS ...
:=
:=int16 mul_prod ;
:=#byte mul_prod = 0x0ff3
:=
:=int16 mul_u8(int8 a, int8 b)
:={
:= a * b; return ( mul_prod );
:=}
:=
:=it turns out to be ...
:=
:=.................... int16 mul_u8(int8 a, int8 b)
:=.................... {
:=.................... a * b; return ( mul_prod );
:=*
:=0022: MOVF 11,W
:=0024: MULWF 12
:=0026: MOVF FF3,W
:=0028: MOVWF 01
:=002A: MOVF FF4,W
:=002C: MOVWF 02
:=.................... }
:=002E: GOTO 1030 (RETURN)
:=
:=and I got a warning ... Code has no effect
:=
:=but, it works with exactly the same speed and ROM size as
:=the in-line assembly.
:=
:=
:=Best wishes
That is very elegant. The 'warning', is because the compiler can't see you doing anything with 'a*b'. As far as it is concerned, this statement generates no effect. However it does make a rather useful 'shortcut' in this context. It might be worth declaring the function as 'inline'. I'd not expect the compiler to seperate it (since it is so short), but it might lead to problems if it did.

Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515835
Chang-Huei Wu
Guest







Re: Multiply 8-bit*8-bit = 16-bit
PostPosted: Thu Jul 10, 2003 4:05 am     Reply with quote

<font face="Courier New" size=-1>:=:=one more funny way to do it with CCS ...
:=:=
:=:=int16 mul_prod ;
:=:=#byte mul_prod = 0x0ff3
:=:=
:=:=int16 mul_u8(int8 a, int8 b)
:=:={
:=:= a * b; return ( mul_prod );
:=:=}
:=:=
:=:=it turns out to be ...
:=:=
:=:=.................... int16 mul_u8(int8 a, int8 b)
:=:=.................... {
:=:=.................... a * b; return ( mul_prod );
:=:=*
:=:=0022: MOVF 11,W
:=:=0024: MULWF 12
:=:=0026: MOVF FF3,W
:=:=0028: MOVWF 01
:=:=002A: MOVF FF4,W
:=:=002C: MOVWF 02
:=:=.................... }
:=:=002E: GOTO 1030 (RETURN)
:=:=
:=:=and I got a warning ... Code has no effect
:=:=
:=:=but, it works with exactly the same speed and ROM size as
:=:=the in-line assembly.
:=:=
:=:=
:=:=Best wishes
:=That is very elegant. The 'warning', is because the compiler can't see you doing anything with 'a*b'. As far as it is concerned, this statement generates no effect. However it does make a rather useful 'shortcut' in this context. It might be worth declaring the function as 'inline'. I'd not expect the compiler to seperate it (since it is so short), but it might lead to problems if it did.
:=
:=Best Wishes

One more not so funny thing, the real potential danger is in case of interrupt, if mul_u8() is interrupted with an ISR also using multiplication, then ... it really hurt, and worse ... very hard to debug. CCS's ISR handling routine does NOT push 0xFF3 and 0xFF4 into safe place, so, it won't be restored after ISR, you have to do it all by yourself.

Best wishes and ... be careful !

p.s. I was planning to use this kind of algorithm for fast floating multiplication, however, exclusively inside my ISR.</font>
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515836
R.J.Hamlett
Guest







Re: Multiply 8-bit*8-bit = 16-bit
PostPosted: Thu Jul 10, 2003 5:08 am     Reply with quote

:=<font face="Courier New" size=-1>:=:=one more funny way to do it with CCS ...
:=:=:=
:=:=:=int16 mul_prod ;
:=:=:=#byte mul_prod = 0x0ff3
:=:=:=
:=:=:=int16 mul_u8(int8 a, int8 b)
:=:=:={
:=:=:= a * b; return ( mul_prod );
:=:=:=}
:=:=:=
:=:=:=it turns out to be ...
:=:=:=
:=:=:=.................... int16 mul_u8(int8 a, int8 b)
:=:=:=.................... {
:=:=:=.................... a * b; return ( mul_prod );
:=:=:=*
:=:=:=0022: MOVF 11,W
:=:=:=0024: MULWF 12
:=:=:=0026: MOVF FF3,W
:=:=:=0028: MOVWF 01
:=:=:=002A: MOVF FF4,W
:=:=:=002C: MOVWF 02
:=:=:=.................... }
:=:=:=002E: GOTO 1030 (RETURN)
:=:=:=
:=:=:=and I got a warning ... Code has no effect
:=:=:=
:=:=:=but, it works with exactly the same speed and ROM size as
:=:=:=the in-line assembly.
:=:=:=
:=:=:=
:=:=:=Best wishes
:=:=That is very elegant. The 'warning', is because the compiler can't see you doing anything with 'a*b'. As far as it is concerned, this statement generates no effect. However it does make a rather useful 'shortcut' in this context. It might be worth declaring the function as 'inline'. I'd not expect the compiler to seperate it (since it is so short), but it might lead to problems if it did.
:=:=
:=:=Best Wishes
:=
:=One more not so funny thing, the real potential danger is in case of interrupt, if mul_u8() is interrupted with an ISR also using multiplication, then ... it really hurt, and worse ... very hard to debug. CCS's ISR handling routine does NOT push 0xFF3 and 0xFF4 into safe place, so, it won't be restored after ISR, you have to do it all by yourself.
:=
:=Best wishes and ... be careful !
:=
:=p.s. I was planning to use this kind of algorithm for fast floating multiplication, however, exclusively inside my ISR.</font>
The compiler should (!), put protection around the routine, and disable interrupts for it, when the same routine is called both inside and outside the ISR. However (obviously), if you use your routine in one place, and use the 'standard' routine in the other, this won't happen. The same problem will exist with all the proposed solutions. One obvious solution, would be to add a 'DIY' save of the registers, by adding something like:

static int16 save;
save=mul_prod;

at the start of the interrupt routine,
and:

mul_prod=save;

at the end, to ensure the registers are protected.

Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515840
Chang-Huei Wu
Guest







Re: Multiply 8-bit*8-bit = 16-bit
PostPosted: Thu Jul 10, 2003 7:43 am     Reply with quote

:=The compiler should (!), put protection around the routine, and disable interrupts for it, when the same routine is called both inside and outside the ISR. However (obviously), if you use your routine in one place, and use the 'standard' routine in the other, this won't happen. The same problem will exist with all the proposed solutions. One obvious solution, would be to add a 'DIY' save of the registers, by adding something like:

Yes, the compiler SHOULD provide this protection as what had been written in the manual and FAQ, however, PCH 3.123(?) does NOT (!) do it, but, PCH 3.148 switched this feature back ON. It was a really horrible learning experience with 3.12x, the atof() in main() is randomly corruptted by a simple z = (float)x * (float)y in ISR. Well, now I have a special test program in my pocket preparing for surprise whenever I upgrade to a new version. I also did modified the stdlib.h with my own protection while tracing CCS's evolution, there was a warning message for this situation around 3.15x, however, they turned OFF this warning since 3.16x. It is fun to observe how considerate CCS is, and, fun to play with CCS. Last of all, it is really good to have you guys on this forum.


Thanks a lot,


C-H Wu

:=
:=static int16 save;
:=save=mul_prod;
:=
:=at the start of the interrupt routine,
:=and:
:=
:=mul_prod=save;
:=
:=at the end, to ensure the registers are protected.
:=
:=Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515843
Chang-Huei Wu
Guest







Thanks for 3.170
PostPosted: Wed Aug 06, 2003 8:04 am     Reply with quote

<font face="Courier New" size=-1>Good news, PCH 3.170 fixed it !

3.170 A problem with hw multiply on PIC18 between interrupt and non-interrupt functions is fixed.

see ... <a href="http://www.ccsinfo.com/versions.shtml" TARGET="_blank"> <a href="http://www.ccsinfo.com/versions.shtml" TARGET="_blank">http://www.ccsinfo.com/versions.shtml</a></a>

the 'DIY' patch suggested by R.J.Hamlett is no longer necessary.

Cheers

PIC18F452 ISR dispatcher:

0018: MOVWF 05
001A: MOVFF STATUS,06
001E: MOVF FSR0L,W
0020: MOVWF 07
0022: MOVF FSR0H,W
0024: MOVWF 08
0026: MOVF FSR1L,W
0028: MOVWF 09
002A: MOVF FSR1H,W
002C: MOVWF 0A
002E: MOVF FSR2L,W
0030: MOVWF 0B
0032: MOVF FSR2H,W
0034: MOVWF 0C
0036: MOVF PRODL,W <--- here
0038: MOVWF 13
003A: MOVF PRODH,W <--- and here
003C: MOVWF 14
003E: MOVF BSR,W
0040: MOVWF 0D
...

:=:=The compiler should (!), put protection around the routine, and disable interrupts for it, when the same routine is called both inside and outside the ISR. However (obviously), if you use your routine in one place, and use the 'standard' routine in the other, this won't happen. The same problem will exist with all the proposed solutions. One obvious solution, would be to add a 'DIY' save of the registers, by adding something like:
:=
:=Yes, the compiler SHOULD provide this protection as what had been written in the manual and FAQ, however, PCH 3.123(?) does NOT (!) do it, but, PCH 3.148 switched this feature back ON. It was a really horrible learning experience with 3.12x, the atof() in main() is randomly corruptted by a simple z = (float)x * (float)y in ISR. Well, now I have a special test program in my pocket preparing for surprise whenever I upgrade to a new version. I also did modified the stdlib.h with my own protection while tracing CCS's evolution, there was a warning message for this situation around 3.15x, however, they turned OFF this warning since 3.16x. It is fun to observe how considerate CCS is, and, fun to play with CCS. Last of all, it is really good to have you guys on this forum.
:=
:=
:=Thanks a lot,
:=
:=
:=C-H Wu
:=
:=:=
:=:=static int16 save;
:=:=save=mul_prod;
:=:=
:=:=at the start of the interrupt routine,
:=:=and:
:=:=
:=:=mul_prod=save;
:=:=
:=:=at the end, to ensure the registers are protected.
:=:=
:=:=Best Wishes ___________________________
This message was ported from CCS's old forum
Original Post ID: 144516708
kypec



Joined: 20 Sep 2003
Posts: 54

View user's profile Send private message

another approach to fast 8x8 bit hardware multiply
PostPosted: Wed Nov 19, 2003 4:54 am     Reply with quote

Here is what I find quite easy and handy for PIC18.
You define the macro below and then use it in your
code like this:
int8 var1,var2;
int16 result;

mul8x8(var1,var2,result) //two variables multiplied

or

mul8x8(var1,const,result) //variable and constant multiplied

CONS:
only one asm instruction overhead, as
MOVF 0xff3, W, ACCESS
is inserted just after the multiplication

PROS:
compiler properly decides whether to use
MULWF or MULLW instruction

best wishes to everybody,
kypec

Code:

////////////////////////////////////////////////////////////////////////////////
//MACRO for fast multiply 8-bit*8-bit=16-bit
////////////////////////////////////////////////////////////////////////////////
#define mul8x8(A8,B8,P16) A8*B8;P16=make16(PRODH,PRODL);
 //compiles to MULWF or MULLW mnemonics
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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