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

Fast multiply without hardware multiplier

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



Joined: 27 Dec 2006
Posts: 28

View user's profile Send private message

Fast multiply without hardware multiplier
PostPosted: Sun Sep 09, 2007 1:45 pm     Reply with quote

Hi,

I was reading the thread below:

http://www.ccsinfo.com/forum/viewtopic.php?t=6131&highlight=fast+multiplication
I know there is a function _mul (x,y) where x and y is 8 bit and the result is 16 bit. I am confused on how this is done on 12F chips with 14bit core without the assembly MULWF or MULLW instruction.

I looked at the .lst file, but it calls the mult8*8 function. Not sure if it stores the high byte of the result. Could someone confirm this? Does _mult work with 12F chips????

Should I just stick to 16 bit result = 16 bit * 16 bit ?

Will 16 bit var = _mul(8bit * 8bit) be equal to above if both the 16bit operand and the 8bit operand are equal?

How can I stick and debug the file in asm? I can do it with CC5x since it generates asm, but CCS doesn't.

I am looking for the fastest possible multiplication of 8*8 bit.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Sep 09, 2007 2:31 pm     Reply with quote

Some 8x8 methods (in ASM) are given on Piclist:
http://www.piclist.com/techref/microchip/math/mul/index.htm

For an example of how to put ASM code in a function and have it return
a value, see Ttelmah's post in this thread:
http://www.ccsinfo.com/forum/viewtopic.php?t=28815

Also, CCS has a special "_RETURN_" variable that allows ASM code
to easily return a value from a function. See this post.
http://www.ccsinfo.com/forum/viewtopic.php?t=31697

See the CCS manual. It has sample code which shows how to do this.
Look in the #ASM #ENDASM secton.
http://www.ccsinfo.com/downloads/CReferenceManual.pdf
anestho



Joined: 27 Dec 2006
Posts: 28

View user's profile Send private message

PostPosted: Sun Sep 09, 2007 5:54 pm     Reply with quote

Thanks, PCM _programmer;

Here is what I found

Code:

;***************************************************************************
;**  time efficient multiplication 8 bit x 8 bit = 16 bit (unsigned)
;**
;**  company:       elektronik 21 GmbH
;**  programmer:            Martin Schaefer (idea from Andrew Warren)
;**
;**  execution time:  fixed 38 cycles  (with jump in and jump out) !!!
;**  code length:           35 words
;**  multiplier:            w
;**  multiplicand:    resultlo
;**  result:        resulthi:resultlo
;***************************************************************************
MUL8X8   CODE
Mul8x8                          ;* 2 cycles for call - instruction
        GLOBAL Mul8x8, resulthi, resultlo

mult    MACRO
        btfsc   STATUS,C
        addwf   resulthi,F
        rrf     resulthi,F
        rrf     resultlo,F
        ENDM

        clrf    resulthi                ;* 1 cycle
        rrf     resultlo,F              ;* 1 cycle

        mult                            ;* 4 cycles
        mult                            ;* 4 cycles
        mult                            ;* 4 cycles
        mult                            ;* 4 cycles
        mult                            ;* 4 cycles
        mult                            ;* 4 cycles
        mult                            ;* 4 cycles
        mult                            ;* 4 cycles

        retlw 0                 ;* 2 cycles


I am having trouble converting it to CCS #asm format.
I am using a PIC12F683

I defined these at the beginning of the code.
#byte STATUS = 0x03
#bit CARRY = STATUS.0
#bit ZERO = STATUS.2

Here is what I got so far:
Code:

/// *************************************************************


//multiplier =    W (accumilator)
//multiplicand=   result_lo
//result:         result_hi:result_lo

int16 mult8x8 (int8 result_lo, char W)
{
 int8 result_hi=0;
 int16 result = 0;
 
  #asm             
        rrf     result_lo,F             
         
        // #1
        btfsc   STATUS,CARRY
        addwf   result_hi,F
        rrf     result_hi,F
        rrf     result_lo,F
       
        // #2
        btfsc   STATUS,CARRY
        addwf   result_hi,F
        rrf     result_hi,F
        rrf     result_lo,F
       
        // #3
        btfsc   STATUS,CARRY
        addwf   result_hi,F
        rrf     result_hi,F
        rrf     result_lo,F
       
        // #4
        btfsc   STATUS,CARRY
        addwf   result_hi,F
        rrf     result_hi,F
        rrf     result_lo,F
       
        // #5
        btfsc   STATUS,CARRY
        addwf   result_hi,F
        rrf     result_hi,F
        rrf     result_lo,F
       
        // #6
        btfsc   STATUS,CARRY
        addwf   result_hi,F
        rrf     result_hi,F
        rrf     result_lo,F
       
        // #7
        btfsc   STATUS,CARRY
        addwf   result_hi,F
        rrf     result_hi,F
        rrf     result_lo,F
       
        // #8
        btfsc   STATUS,CARRY
        addwf   result_hi,F
        rrf     result_hi,F
        rrf     result_lo,F
  #endasm
   result = result_hi*256+result_low;
   return result;
}   



I get an error on the 2nd line of the #asm addwf result_hi,F saying "expression must evaluate to a constant"

I am using version 3.249 PCWH compiler.
anestho



Joined: 27 Dec 2006
Posts: 28

View user's profile Send private message

PostPosted: Sun Sep 09, 2007 6:01 pm     Reply with quote

This does the same thing as:

Code:
uns16 operator* _multM8_8( uns8 arg1, char W)
{
    uns16 rval = 0;
    Carry = 0;
   #define addRR(rval,arg,bit) if(arg&((uns8)1<<bit)) rval.high8+=W; rval=rr(rval);
    addRR( rval, arg1, 0);
    addRR( rval, arg1, 1);
    addRR( rval, arg1, 2);
    addRR( rval, arg1, 3);
    addRR( rval, arg1, 4);
    addRR( rval, arg1, 5);
    addRR( rval, arg1, 6);
    addRR( rval, arg1, 7);
   #undef addRR
    return rval;
}
[/code]

this is from CC5x math lib MATH16M.h

If you can get either to work, that would be great, or at least some suggestions.

Here is how I understand it:
1. compare the 0 bit with 1, if it is 1, then add 1 to the MSB and rotate right the bits
2. same thing with bit 1.. etc to bit 7
anestho



Joined: 27 Dec 2006
Posts: 28

View user's profile Send private message

PostPosted: Sun Sep 09, 2007 6:53 pm     Reply with quote

I got it to compile finally. Mistake was using STATUS, CARRY instead of STATUS,0.

Will report if it works.
anestho



Joined: 27 Dec 2006
Posts: 28

View user's profile Send private message

PostPosted: Sun Sep 09, 2007 7:02 pm     Reply with quote

Here is what I am using now. Still need to test it, but it compiles.

Code:

//      Begin Multiplier Routine
int16 mult8x8(int8 mulcnd, int8 mulplr) // 35 instruction cycles = 0.5 x 35 = 17us
{     
      int8 H_byte = 0;
      int8 L_byte = 0;
#asm
        //clrf    H_byte
        //clrf    L_byte
        movf    mulcnd,W    // move the multiplicand to W reg.
        bcf     STATUS,0    // Clear the carry bit in the status Reg.
       
        btfsc   mulplr,0
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
       
        btfsc   mulplr,1
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
     
        btfsc   mulplr,2
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
       
        btfsc   mulplr,3
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
       
        btfsc   mulplr,4
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
       
        btfsc   mulplr,5
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
       
        btfsc   mulplr,6
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
       
        btfsc   mulplr,7
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
#endasm
      return H_byte*256+L_byte;
}


Last edited by anestho on Sun Sep 09, 2007 7:08 pm; edited 1 time in total
anestho



Joined: 27 Dec 2006
Posts: 28

View user's profile Send private message

PostPosted: Sun Sep 09, 2007 7:07 pm     Reply with quote

I eliminated the clrf for the H_byte and L_byte since I clear them above, and its duplicate code in .lst

I also reduced the instruction count by using W for one of the arguments.

CAN someone with a UART connection please test this routine for me? I only have 12F683 and it doesn't have a built in UART.

Code:
/      Begin Multiplier Routine
int16 mult8x8(int8 mulcnd, int8 W) // 35 instruction cycles = 0.5 x 35 = 17us
{     
      int8 H_byte = 0;
      int8 L_byte = 0;
#asm
        //clrf    H_byte  // removed, not needed
        //cllrf    L_byte  // removed, not needed
        //movf    mulcnd,W    // removed, not needed
        bcf     STATUS,0    // Clear carry bit
       
        btfsc   W,0   // compare W 0 bit with 0, if 1 goes to next line
        addwf   H_byte,1  // add 1 to MSB
        rrf     H_byte,1
        rrf     L_byte,1
       
        btfsc   W,1   // compare W 1 bit with 0, if 1 goes to next line
        addwf   H_byte,1 // add 1 to MSB
        rrf     H_byte,1
        rrf     L_byte,1
     
        btfsc   W,2
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
       
        btfsc   W,3
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
       
        btfsc   W,4
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
       
        btfsc   W,5
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
       
        btfsc   W,6
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
       
        btfsc   W,7
        addwf   H_byte,1
        rrf     H_byte,1
        rrf     L_byte,1
#endasm
      return H_byte*256+L_byte;
}


Also, how do I handle an interrupt while in this function? My interrupt uses the W register. Should I turn off the interrupt prior to entering this routine?
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon Sep 10, 2007 1:18 am     Reply with quote

Your code doesn't work because the function parameter with the name W is not the same as register W.

Quote:
CAN someone with a UART connection please test this routine for me? I only have 12F683 and it doesn't have a built in UART.
You can test it yourself using the simulator in MPLAB.

Quote:
Also, how do I handle an interrupt while in this function? My interrupt uses the W register. Should I turn off the interrupt prior to entering this routine?
It is the interrupt routine's responsibility for not changing any registers. You don't have to do anything.
Guest








PostPosted: Wed Oct 10, 2007 10:39 am     Reply with quote

I am not getting any answer. All variables are assigned zero when the fucntion is accessed. So how do I fix this? use movwf instead of movf?
Guest








PostPosted: Wed Oct 10, 2007 11:03 am     Reply with quote

Is there a way to do this in CCS C instead of asm?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Oct 10, 2007 11:53 am     Reply with quote

Yes, there is. Use the _mul() function.

Here is the description of the _mul() function from the CCS manual:
Quote:

Performs an optimized multiplication. By accepting a different type than it
returns, this function avoids the overhead of converting the parameters
to a larger type.


Quote:
#include <16F877.H>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

//======================================
void main()
{
int16 result;
int8 a, b;

a = 100;
b = 234;

result = _mul(a, b);

printf("result = %lu \n\r", result);

while(1);
}
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