Searching \ for '[PIC:] Efficiency of C?' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: www.piclist.com/techref/microchip/devices.htm?key=pic
Search entire site for: 'Efficiency of C?'.

Exact match. Not showing close matches.
PICList Thread
'[PIC:] Efficiency of C?'
2003\10\14@111056 by Hulatt, Jon

flavicon
face
Hi,

I've been using MPASM up to now, but I am considering the benefits of
developing in C, since I'm a C++ programmer by trade, and a PIC hobbyist.
It'll make development much simpler for me.

C being a higher level language obviously introduces some potential issues
for efficiency. But how severe are these? Some of the features of the PIC16
instruction set allow some neat coding techniques that create fast, small
code.

For example, recent experimentation I've done with an LCD in a 4 bit
interface mode called for code to take a byte and output it as 2 4-bit
nibbles . The outputnibble function in the following handles the writing
value to PORTC, and fiddling with the E line (which was on PORTA). In C,
this could optimally be coded somethng along the lines of:-


void OutputByte( unsigned char w)
{
       unsigned char nibble;

       nibble = w >> 4;
       OutputNibble(nibble);
       nibble = w & 0xF;
       OutputNibble(nibble);

       return;
}

That seems all well and good in C. But will it compile to anything as
effient as an ASM ecquivalent of:-

cblock
       temp
endc

outputbyte:                                             ; byte to output is
in W
                       movwf           temp

                       swapf           temp,W  ; get the hi nibble in the
lo 4 bits
                       andlw           0xF
                       call            outputnibble

                       movf            temp,W  ; recover the lo nibble &
send
                       andlw           0xF
                       call            outputnibble

                       return


So, the ASM version is 8 instructions and 1 temp variable.

How does the C version compile?

I can see lots of oppurtunities for some serious wastage:-

 - a few instrunctions fiddling with popping the argument off the stack.
 - I'm guessing the compiler would use two variables - "w" and "nibble"- my
ASM only needs one.
 - "w >> 4" - will this map to 4 occurences of rrf + bcf STATUS,C ?
 - more stack usage calling outputnibble() twice?



So, all in all I'd appreciate some comments as to just how much code space I
throw away for using C. I haven't picked a C compiler yet, or tried any C,
I'm still evaluating whether my project can afford it, both monetarily
(although PiCC-Lite is free) and code speed & size wise.

Thanks

Jon

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads

2003\10\14@114343 by hael Rigby-Jones

picon face
{Quote hidden}

Ok, I put this into HiTech PICC V8.01 patch level 3 and got the following
out:

 33  07EC                     _OutputByte
   34                           ;      _w assigned to ?a_OutputByte+0
   35  0000                     _OutputByte$w  set     ?a_OutputByte
   36                           ;      _nibble assigned to ?a_OutputByte+1
   37  0000                     _OutputByte$nibble     set
?a_OutputByte+1
   38                           ;_w stored from w

   39  07EC  1283                      bcf     3,5
   40  07ED  1303                      bcf     3,6
   41  07EE  00A0                      movwf   ?a_OutputByte
   43  07EF  0E20                      swapf   ?a_OutputByte,w
   44  07F0  390F                      andlw   15
   45  07F1  00A1                      movwf   ?a_OutputByte+1
   47  07F2  27E7                      fcall   _OutputNibble
   49  07F3  0820                      movf    ?a_OutputByte,w
   50  07F4  390F                      andlw   15
   51  07F5  00A1                      movwf   ?a_OutputByte+1
   53  07F6  2FE7                      ljmp    _OutputNibble

Not bad, the first two instructions are for bank setting.  I chose a 16F877
so a smaller device may require less instructions.  Note that the compiler
has optimised the last call to OutputNibble by converting it to a jump.
However also note that the nibble variable is not actually required, a
better implementation would be:

void OutputByte( unsigned char w )
{
       OutputNibble((unsigned char)(w >> 4));
       OutputNibble((unsigned char)(w & 0xF));
}

giving:

   33  07EE                     _OutputByte
   34                           ;      _w assigned to ?a_OutputByte+0
   35  0000                     _OutputByte$w  set     ?a_OutputByte
   36                           ;_w stored from w
   37  07EE  1283                      bcf     3,5
   38  07EF  1303                      bcf     3,6
   39  07F0  00A0                      movwf   ?a_OutputByte
   41  07F1  0E20                      swapf   ?a_OutputByte,w
   42  07F2  390F                      andlw   15
   43  07F3  27E9                      fcall   _OutputNibble
   45  07F4  0820                      movf    ?a_OutputByte,w
   46  07F5  390F                      andlw   15
   47  07F6  2FE9                      ljmp    _OutputNibble

Now apart from the bank setting bits which weren't included in your assembly
example, this has exactly the same number of instructions, but actually
executes more quickly due to the jump optimisation.  The ljmp macro
degenerates to a single goto if the OutputNibble resides in the same program
memory page as the OutputByte function.

Hope that calms your fears over the code generation quality of HiTech :o)

Mike







=======================================================================
This e-mail is intended for the person it is addressed to only. The
information contained in it may be confidential and/or protected by
law. If you are not the intended recipient of this message, you must
not make any use of this information, or copy or show it to any
person. Please contact us immediately to tell us that you have
received this e-mail, and return the original to us. Any use,
forwarding, printing or copying of this message is strictly prohibited.
No part of this message can be considered a request for goods or
services.
=======================================================================
Any questions about Bookham's E-Mail service should be directed to
postmasterspamKILLspambookham.com.

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads

2003\10\14@115800 by Dan Oelke

flavicon
face
I can't comment directly with a PIC as I haven't done a lot of looking
at what the compiler spits out - but in general I would recommend using
C over assembly especially if you are a C/C++ programmer by trade and
are using PICs for a hobby.  You can spend just a couple of extra bucks
and get one of the PICs that has a lot more memory and it will be
overkill, but you will be much more proficient using C and that makes
the hobby more enjoyable.

Just my 2 cents - from another C++ programmer by trade using PICs for
hobby and most recently for employment.

Dan

Hulatt, Jon wrote:

{Quote hidden}

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads

2003\10\14@121426 by piclist

flavicon
face
On Tue, 14 Oct 2003, Hulatt, Jon wrote:

> void OutputByte( unsigned char w)
> {
>         unsigned char nibble;
>
>         nibble = w >> 4;
>         OutputNibble(nibble);
>         nibble = w & 0xF;
>         OutputNibble(nibble);
>
>         return;
> }

Here's what PICC18 generates, after removing the uncecessary temporary
variable from your code:

  105  000002'                    _OutputByte:
  106  000000
  107                           ; _w loaded to fsr2l
  108  000002' 6ED9                    movwf   fsr2l,c
  109                           ;t.c: 7: OutputNibble(w >> 4);
  110  000004' 38D9                    swapf   fsr2l,w,c
  111  000006' 0B0F                    andlw   15
  112  000008' DFFB                    call    _OutputNibble
  113                           ;t.c: 8: OutputNibble(w & 0xF);
  114  00000A' 50D9                    movf    fsr2l,w,c
  115  00000C' 0B0F                    andlw   15
  116  00000E' D7F8                    goto    _OutputNibble

Like the 16-series code already posted, this code is actually more
efficient than your hand-assembled code, since the "return" is
optimized out, and also note that it uses no RAM in this case, using
an FSR as a temporary variable.

Of course, this is just a trivial example and can't be extrapolated to
mean that problem X solved in C will be smaller/faster/whatever than
some other language.  There are some places where requirements imposed
by the language make C inherently less efficient on the PIC; for
example, C does not have a "rotate" operator, while the PIC does not
have a "shift" instruction.  So a simple one-bit shift in C takes two
instructions on the PIC.

--
John W. Temples, III

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads

2003\10\14@125508 by Eugene Rosenzweig
flavicon
face
I compiled your routine out of interest. I was using a demo version of cc5x,
demo version.
                       ;void OutputByte( unsigned char w)
                       ;{
OutputByte
       MOVWF w
                       ;        W = w >> 4;
       SWAPF w,W
       ANDLW .15
                       ;        OutputNibble(W);
       CALL  OutputNibble
                       ;        W = w & 0xF;
       MOVLW .15
       ANDWF w,W
                       ;        OutputNibble(W);
       GOTO  OutputNibble
                       ;
                       ;        return;
                       ;}

Notice from the comments that I tweaked the source a little.

> So, the ASM version is 8 instructions and 1 temp variable.
> How does the C version compile?


7 instructions and 1 temp var. Looks pretty good ;-)

Here is output from c2c (a cheap shareware option). This is unmodified code
as this compiler did not accept the above version :

_OutputByte
       ;;;;;;;;{
       ;;;;;;;; w = w >> 4;
       movf param00_OutputByte, W
       movwf _code_tmp_0000
       rrf _code_tmp_0000 , F
       rrf _code_tmp_0000 , F
       rrf _code_tmp_0000 , F
       rrf _code_tmp_0000 , W
       andlw D'15'
       movwf param00_OutputByte
       ;;;;;;;; OutputNibble(w);
       movwf param00_OutputNibble
       call _OutputNibble
       ;;;;;;;; w = w & 0xF;
       movf param00_OutputByte, W
       andlw D'15'
       movwf param00_OutputByte
       ;;;;;;;; OutputNibble(w);
       movwf param00_OutputNibble
       call _OutputNibble
       ;;;;;;;;
       ;;;;;;;; return;
       return
       ;;;;;;;;}
_OutputByte__end

Radically different... Maybe this one needs tinkering with the code.

> So, all in all I'd appreciate some comments as to just how much code space
I
> throw away for using C. I haven't picked a C compiler yet, or tried any C,
> I'm still evaluating whether my project can afford it, both monetarily
> (although PiCC-Lite is free) and code speed & size wise.

AFAIK the only truly ANSI-compartible compiler for PIC is PICC if you care
about that.
CCS seem to be pretty big but never tried them. They are supposed to have
large set of support libraries. This could be a great plus if you'd prefer
to use a library rather than sweat over the datasheets working out how to
use a particular peripheral.
There is an open source compiler in the works, sdcc, but from what I read on
the mailing list, it still has a little way to go before the code generation
is reliable. I have not tried it though so I might be wrong.

I cannot help with these questions much. Compiler vendors provide code size
comparisons between C and assembly... However there are comparisons between
the compilers. There are some on cc5x site
(http://www.bknd.com/cc5x/index.shtml) and some on c2c site
http://www.picant.com/c2c/c.html. Obviously the code quality produced by a
compiler will vary with each compiler and the only way to find out is to
test each individually. One certainty however: most of them are expensive. I
would also agree with one of the previous posts, you might enjoy the whole
experience if you use C if you are proficient with it.

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads

2003\10\14@125713 by Olin Lathrop

face picon face
> So, all in all I'd appreciate some comments as to just how much code
> space I throw away for using C. I haven't picked a C compiler yet, or
> tried any C, I'm still evaluating whether my project can afford it,
> both monetarily (although PiCC-Lite is free) and code speed & size wise.

I don't know about the code efficiency since I use assembler exclusively.
However, if I needed to know for some reason, I would get the evaluation
version of a compiler, run some test code thru it, and look at the
resulting assembly code.


*****************************************************************
Embed Inc, embedded system specialists in Littleton Massachusetts
(978) 742-9014, http://www.embedinc.com

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads

2003\10\14@130335 by Sergio Masci

picon face
From: Michael Rigby-Jones wrote:

<snip>

{Quote hidden}

The following shows equivalent code compiled using the XCSB compiler.
Note the absence of call and return instructions.

Admittedly the total of 12 instructions generated could be further
reduced to 8 by a key hole optimiser but none the less still not bad
going for a high level language generating code for a 16 series PIC

       //----------------------
       //----------------------

       include "hwreg-p16f628.h"

       proc inline OutputNibble(ubyte val)

               PORTA = val
       endproc

       proc main()

               ubyte   x

               OutputNibble(x >> 4)
               OutputNibble(x & 0x0f)

       endproc

       //----------------------
       //----------------------

       0069                    main

                               ;;;  OutputNibble ( x_main_func_local >> 4 )
       0069    08 22   f:22            movf    x_main_func_local,w
       006A    00 A7   f:27            movwf   xacc_2_main_func_eval_stk

       006B    0E A7   f:27            swapf   xacc_2_main_func_eval_stk
       006C    30 0F                   movlw   15
       006D    05 A7   f:27            andwf   xacc_2_main_func_eval_stk

                               ;;;  PORTA = xacc_2_main_func_eval_stk
       006E    08 27   f:27            movf    xacc_2_main_func_eval_stk,w
       006F    00 85   f:05            movwf   PORTA

                               ;;;  OutputNibble ( x_main_func_local & 15 )
       0070    08 22   f:22            movf    x_main_func_local,w
       0071    39 0F                   andlw   15
       0072    00 A7   f:27            movwf   xacc_2_main_func_eval_stk

                               ;;;  PORTA = xacc_2_main_func_eval_stk
       0073    08 27   f:27            movf    xacc_2_main_func_eval_stk,w
       0074    00 85   f:05            movwf   PORTA

       0075                    main_func_exit_point


Regards
Sergio Masci

http://www.xcprod.com/titan/XCSB - optimising structured PIC BASIC compiler

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads

2003\10\14@131755 by Hulatt, Jon

flavicon
face
So it seems that most the compilers optimise a 4 bit shift into a swapf/and
combo. Which is a good optimisation. I think I shall actually have a play
tonight

thanks for the insights.

Jon

> {Original Message removed}

More... (looser matching)
- Last day of these posts
- In 2003 , 2004 only
- Today
- New search...