|
|
View previous topic :: View next topic |
Author |
Message |
x34678
Joined: 18 May 2012 Posts: 6 Location: Argentina
|
CCS Function to asm optimization |
Posted: Fri May 18, 2012 10:51 am |
|
|
Hi All,
i'm developing in C for my actual project and ROM space is critical because the program which I'm programming is really big.
So, here is the fact:
PIC: 16F887A
CCS Version: 4.120
Xtal: 4Mhz
My Problem: When I compile my code, there are some functions (from my C code) which appear more than once in assembly code. Is that correct?
I think, if I would program in assembly I would put my "function" just only 1 time and I would "call" this function whenever I would need it.
I try to use #org but I get the "out of range" error...
So... a part of the whole Code:
Code: |
void rom2lcd(int16 rom_location)
{
char u,x;
/* wr lcd buffer with byte, with bytes stored in flash */
/* copy each byte to lcd_putchar() */
u RESET;
do
{
/* first byte */
x = read_flash(rom_location + u,0);
if (x)
{
lcd_putc(x);
/* second byte */
x = read_flash(rom_location + u,1);
if (x)
{
lcd_putc(x);
}
}
u++;
}
while (x != 0x00);
}
//READ BYTE FROM FLASH
char read_flash(int16 y, char x)
{
char u;
/* read byte 0x100 */
eeadrh = y >> 8; /* high byte */
eeadr = y & 0x00FF; /* low byte */
eecon1.eepgd SET ; /* point to flash */
eecon1.rd SET; /* start read operation */
delay_us(3); /* required delay(two nops) */
/* high or low byte */
if (x == 0)
{
/* high byte */
u = eedath << 1; /* get first 6 bits */
u &= 0x7F; /* clear bit7 */
/* get bit0 */
if ((eedat & 0x80) == 0x80)
u |= 0x01;
else
u &= 0xFE;
}
else
{
/* low byte */
u = eedat & 0x7F;
}
return(u);
}
|
And the Assembly code done by CCS:
Code: |
here appears my funtion more than once!!...
2683 0A7A 01D2 rom2lcd CLRF 0x52
2684 0A7B 0852 MOVF 0x52, W
2685 0A7C 0750 ADDWF 0x50, W
2686 0A7D 00D4 MOVWF 0x54
2687 0A7E 0851 MOVF 0x51, W
2688 0A7F 00D5 MOVWF 0x55
2689 0A80 1803 BTFSC STATUS, 0
2690 0A81 0AD5 INCF 0x55, F
2691 0A82 0855 MOVF 0x55, W
2692 0A83 00D7 MOVWF 0x57
2693 0A84 0854 MOVF 0x54, W
2694 0A85 00D6 MOVWF 0x56
2695 0A86 01D8 CLRF 0x58
2696 0A87 0857 read_flash MOVF 0x57, W
2697 0A88 1703 BSF STATUS, 0x6
2698 0A89 008F MOVWF TMR1H
2699 0A8A 1303 BCF STATUS, 0x6
2700 0A8B 0856 MOVF 0x56, W
2701 0A8C 1703 BSF STATUS, 0x6
2702 0A8D 008D MOVWF PIR2
2703 0A8E 1683 BSF STATUS, 0x5
2704 0A8F 178C BSF PIR1, 0x7
2705 0A90 140C BSF PIR1, 0
2706 0A91 2A92 GOTO 0x292
2707 0A92 0000 NOP
...
2835 0B12 01D2 rom2lcd CLRF 0x52
2836 0B13 0852 MOVF 0x52, W
2837 0B14 0750 ADDWF 0x50, W
2838 0B15 00D4 MOVWF 0x54
2839 0B16 0851 MOVF 0x51, W
2840 0B17 00D5 MOVWF 0x55
2841 0B18 1803 BTFSC STATUS, 0
2842 0B19 0AD5 INCF 0x55, F
2843 0B1A 0855 MOVF 0x55, W
2844 0B1B 00D7 MOVWF 0x57
2845 0B1C 0854 MOVF 0x54, W
2846 0B1D 00D6 MOVWF 0x56
2847 0B1E 01D8 CLRF 0x58
2848 0B1F 0857 read_flash MOVF 0x57, W
2849 0B20 1703 BSF STATUS, 0x6
2850 0B21 008F MOVWF TMR1H
2851 0B22 1303 BCF STATUS, 0x6
2852 0B23 0856 MOVF 0x56, W
2853 0B24 1703 BSF STATUS, 0x6
2854 0B25 008D MOVWF PIR2
2855 0B26 1683 BSF STATUS, 0x5
2856 0B27 178C BSF PIR1, 0x7
2857 0B28 140C BSF PIR1, 0
2858 0B29 2B2A GOTO 0x32a
2859 0B2A 0000 NOP
|
And this means, of course, spend of ROM...
Question: What am I doing wrong?
How could I put my function only one time in asm code and call it whenever I need it?
Thanks! |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Fri May 18, 2012 11:40 am |
|
|
It's automatically "inlining" your function. To get around this you can do a couple of things. I think #separate prevents inlining...but it may also have some other side effects that I cannot bring to mind at this point. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri May 18, 2012 12:41 pm |
|
|
There is no PIC with this part number.
Quote: |
When I compile my code, there are some functions (from my C code)
which appear more than once in assembly code.
|
Edit your posted code and make it into a test program that we can
compile. Add the #include, #fuses, #use delay(), #include for the
lcd driver (but don't post the actual driver). Also add definitions for
lines like this:
Add the declarations for these symbols, etc.:
Code: |
eeadrh = y >> 8; /* high byte */
eeadr = y & 0x00FF; /* low byte */
eecon1.eepgd SET ; /* point to flash */
eecon1.rd SET; |
In other words, make it into a complete, compilable test program.
Test it to make sure it compiles before you post it.
Also, ideally, convert all the traditional C comments ( /* ... */ ) into
modern line comments: // |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1938 Location: Norman, OK
|
|
Posted: Fri May 18, 2012 4:06 pm |
|
|
My question is why go to all the hassle? You have to deal with paging and
other such issues.
For a $5 PIC 18F with more memory you can save dozens, if not hundreds
of hours of development/debugging time... it must be a school assignment. _________________ Google and Forum Search are some of your best tools!!!! |
|
|
x34678
Joined: 18 May 2012 Posts: 6 Location: Argentina
|
|
Posted: Sat May 19, 2012 1:22 am |
|
|
dyeatman wrote: | My question is why go to all the hassle? You have to deal with paging and
other such issues.
For a $5 PIC 18F with more memory you can save dozens, if not hundreds
of hours of development/debugging time... it must be a school assignment. |
Thanks for the tip, but please don't forget that a PIC 18F is more expensive where i live :(
And YES... you have to deal with this paging issues because in another way you may not compile the whole program (out of ROM, blah blah) |
|
|
x34678
Joined: 18 May 2012 Posts: 6 Location: Argentina
|
|
Posted: Sat May 19, 2012 1:30 am |
|
|
PCM programmer wrote: |
There is no PIC with this part number.
Quote: |
When I compile my code, there are some functions (from my C code)
which appear more than once in assembly code.
|
Edit your posted code and make it into a test program that we can
compile. Add the #include, #fuses, #use delay(), #include for the
lcd driver (but don't post the actual driver). Also add definitions for
lines like this:
Add the declarations for these symbols, etc.:
Code: |
eeadrh = y >> 8; /* high byte */
eeadr = y & 0x00FF; /* low byte */
eecon1.eepgd SET ; /* point to flash */
eecon1.rd SET; |
In other words, make it into a complete, compilable test program.
Test it to make sure it compiles before you post it.
Also, ideally, convert all the traditional C comments ( /* ... */ ) into
modern line comments: // |
Thanks for your tips (in special comment tips), but the whole program has more than 2400 lines and it is separated in several files. What I have posted is only a sample, I have more C functions that I got several times in the final asm code.
My POINT here is NOT to compile the mentioned code, but the question why should appear one C function more than once in the final assembly code. I have the feeling that CCS doesn't optimize enough. |
|
|
x34678
Joined: 18 May 2012 Posts: 6 Location: Argentina
|
conclusion |
Posted: Sat May 19, 2012 1:38 am |
|
|
I found some solutions optimizing memory organization (and distribution into the pages) by dividing some functions in subfunctions (but the stack is almost to the limit -> 7 worst case).
My conclusion is: If the time calculation or the ROM space is critical, then you have 2 options:
1. your pocket (PIC 18F)
2. Assembly code (my option).
Thanks all anyway. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sat May 19, 2012 1:59 am |
|
|
You have already found out, that call stack limitation is the reason behind automatic function inlining. Apperently, this isn't a case of unsufficient optimization rather than caused by your application layout, that doesn't take account for the limited PIC16 resources.
Assembly coding as such can't be expected to solve the problem. Nevertheless, you'll most likely find other places where it can help to save rom space.
Code: | Edit your posted code and make it into a test program that we can
compile. | The suggestion was to make a small test program that reproduces the issue (unintentional "inlining"/duplication of functions), not to post your full application. Doing so usually helps yourself to understand the problem. In this case, it won't be necessary, because you identified the underlying problem. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sat May 19, 2012 2:35 am |
|
|
Jeremiah is right, #separate does prevent inlining.
The CCS manual explains, at length, to pros and cons of #inline against #separate.
Having been advised, and before abandoning 'C', did you try #separate?
Mike |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sat May 19, 2012 3:39 pm |
|
|
x34678 wrote: | dyeatman wrote: | My question is why go to all the hassle? You have to deal with paging and
other such issues.
For a $5 PIC 18F with more memory you can save dozens, if not hundreds
of hours of development/debugging time... it must be a school assignment. |
Thanks for the tip, but please don't forget that a PIC 18F is more expensive where i live :( | Going to use assembly is a nightmare, not just now, but also for future maintenance.
That's why I want to remark on the above suggestion to use another processor. You didn't correct which PIC you are using, the 16F887A doesn't exist. With the 'A' in the number I assume you meant the 16F877A, an old chip and not recommended for new designs, about $5 each. Now Microchip is a bit strange in that they are selling the newer more advanced chips cheaper than the old models. So, for example you can buy a new chip with more memory for less money. Without more details about your circuit it is difficult to give good advice, but the PIC16F877A costs about $5,00 for a 40 pin PDIP. The PIC16F1519 has double the amount of Flash (28 kb), 3 times the RAM (1024 bytes) and doubled stack levels (16), costing $2.10 for a 40 pin PDIP in 1-25 quantities.
Do you really need the EEPROM feature, then a PIC16F1939 for $2.41 could fit the job.
If even remotely possible I would strongly recommend to upgrade to a PIC with more memory. |
|
|
x34678
Joined: 18 May 2012 Posts: 6 Location: Argentina
|
|
Posted: Sat May 19, 2012 11:43 pm |
|
|
Mike Walne wrote: | Jeremiah is right, #separate does prevent inlining.
The CCS manual explains, at length, to pros and cons of #inline against #separate.
Having been advised, and before abandoning 'C', did you try #separate?
Mike |
Hi Mike, thanks... Yes, I tried with #separate #inline #org... .... and... it was not easy to use them...
Some times it worked, sometimes it didn't. |
|
|
x34678
Joined: 18 May 2012 Posts: 6 Location: Argentina
|
|
Posted: Sat May 19, 2012 11:46 pm |
|
|
ckielstra wrote: | x34678 wrote: | dyeatman wrote: | My question is why go to all the hassle? You have to deal with paging and
other such issues.
For a $5 PIC 18F with more memory you can save dozens, if not hundreds
of hours of development/debugging time... it must be a school assignment. |
Thanks for the tip, but please don't forget that a PIC 18F is more expensive where i live :( | Going to use assembly is a nightmare, not just now, but also for future maintenance.
That's why I want to remark on the above suggestion to use another processor. You didn't correct which PIC you are using, the 16F887A doesn't exist. With the 'A' in the number I assume you meant the 16F877A, an old chip and not recommended for new designs, about $5 each. Now Microchip is a bit strange in that they are selling the newer more advanced chips cheaper than the old models. So, for example you can buy a new chip with more memory for less money. Without more details about your circuit it is difficult to give good advice, but the PIC16F877A costs about $5,00 for a 40 pin PDIP. The PIC16F1519 has double the amount of Flash (28 kb), 3 times the RAM (1024 bytes) and doubled stack levels (16), costing $2.10 for a 40 pin PDIP in 1-25 quantities.
Do you really need the EEPROM feature, then a PIC16F1939 for $2.41 could fit the job.
If even remotely possible I would strongly recommend to upgrade to a PIC with more memory. |
Sorry, I meant pic16F887 (sorry for the A). Thanks! but the chip was not an option in this project :( |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sun May 20, 2012 3:28 am |
|
|
Quote: |
My POINT here is NOT to compile the mentioned code, but the question why should appear one C function more than once in the final assembly code. I have the feeling that CCS doesn't optimize enough. |
Back in the olden days of Z80 assembler I had a choice. Optimise for SPEED with inline code & lookup tables, or ROM SPACE with tight loops, deeply nested functions & and on the fly calculations.
The fundamentals haven't changed, whether your working in assmbler or higher level language.
The POINT is, YOU now tell the compiler WHICH route to take.
Mike |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun May 20, 2012 6:53 am |
|
|
Mike Walne wrote: | The POINT is, YOU now tell the compiler WHICH route to take. | You are right for most modern compilers; you can specify you want to optimize for speed or size. In the CCS compiler I don't know how to do this. There is the #OPT specifier, but nowhere have I ever seen an explanation for the difference between levels 0-9.
Back to the OT:
As you have already found out the most likely cause for the functions being duplicated has to do with the limited stack levels on your PIC16F887.
What you can do to improve this is to squeeze multiple functions into one larger function using the #inline option. Note that this is opposite to using #seperate for preventing the 'Out of ROM' compiler error. This will require some tweaking to find the optimum balance between stack level usage and spreading of functions aver memory banks.
As a guide you can have a look at the compiler generated tree file (*.tre, command line option +T). Here you can see at a glance which functions use the deepest call stack, so where optimization will work best.
Note that interrupts take up stack levels as well (see the top of the list file for a specification). |
|
|
|
|
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
|