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 support@ccsinfo.com

Compiler bug or me ?
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Jim Hearne



Joined: 22 Dec 2003
Posts: 109
Location: West Sussex, UK

View user's profile Send private message Send e-mail Visit poster's website

Compiler bug or me ?
PostPosted: Tue Feb 24, 2009 11:04 am     Reply with quote

Hi all,
Can somebody check this out for me.
PCW 4.086, PIC 18F6722
It's a proof of bug (i think) hacked down code so it looks a bit weird but it runs.
In the full program there is a const stucture containing amongst other things the addresses of lots of variables, most in another stucture
But i was getting corruption of the variables if they were refered to by the stored addresses.

It seems the compiler isn't correctly storing addresses as constants.

Jim1 should be the same as jim2.

Is it me or a bug ?

I am looking at the results in the debugger so no display output.

Thanks,

Jim


Code:
#include <18f6722.h>

#device  adc=10 *=16
#device  ICD=true

#use   delay(clock=16000000)
#fuses WDT, WDT512, INTRC_IO, PROTECT, BROWNOUT, PUT, STVREN, NODEBUG, NOMCLR, NOIESO ,NOFCMEN
#fuses NOLVP, NOWRT, NOWRTD, NOWRTB, WRTC, NOCPD, NOCPB, NOEBTR, NOEBTRB, BORV27, NOXINST, NOLPT1OSC

struct
{
   int8 other_data[100];
   int8 more_data[150];
   int8 bar;
}foo;   

const int16* address=&foo.bar; // store address of foo so it can be changed later.

int16 jim1=0;
int16 jim2=0;

void main()
{
   setup_oscillator(OSC_16MHZ | OSC_NORMAL);
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);

   while(1)
   {
   jim2=&foo.bar; // this works, gets address of foo.bar
     
   jim1=address; // this doesn't
 
   restart_wdt();
   }
  }
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Tue Feb 24, 2009 12:29 pm     Reply with quote

const int16* address is inferring a flash constant pointer, that can't be changed later and possibly don't work in regular assignments to a ram pointer. Omitting the const type modifier should create a regular pointer and hopefully work.
Jim Hearne



Joined: 22 Dec 2003
Posts: 109
Location: West Sussex, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Tue Feb 24, 2009 1:37 pm     Reply with quote

FvM wrote:
const int16* address is inferring a flash constant pointer, that can't be changed later and possibly don't work in regular assignments to a ram pointer. Omitting the const type modifier should create a regular pointer and hopefully work.


Thanks for the reply.
I intend it to be a const pointer, in the real program there are nearly 300 variables referenced from a very large const structure that contains pointers to the variables plus there size, min & max values, decimal point position, units etc. All part of a flexible menu and data entry system.
It was all working quite happily with several 1000 units in the field until the customer wanted some more options added.
Then the problems started.

Jim
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Feb 24, 2009 1:59 pm     Reply with quote

Historically, CCS has a different meaning for 'const' than MSVC++ does.
From the manual:
Quote:

const
Data is read-only. Depending on compiler configuration, this qualifier
may just make the data read-only -AND/OR- it may place the data into
program memory to save space.


Constant Data:
The CONST qualifier will place the variables into program memory.
If the keyword CONST is used before the identifier, the identifier is
treated as a constant. Constants should be initialized and may not be
changed at run-time. This is an easy way to create lookup tables.


CONST=READ_ONLY
Uses the ANSI keyword CONST definition, making CONST variables
read only, rather than located in program memory.

CONST=ROM
Uses the CCS compiler traditional keyword CONST definition, making
CONST variables located in program memory. This is the default mode.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Tue Feb 24, 2009 5:10 pm     Reply with quote

I was assuming from the code comments, that you have used unintentionally a ROM constant for the pointer. If ROM constant pointers are required for your application, there should be a way. But they are handled specially by the compiler and some usage restrictions apply.
Jim Hearne



Joined: 22 Dec 2003
Posts: 109
Location: West Sussex, UK

View user's profile Send private message Send e-mail Visit poster's website

More clarification.
PostPosted: Wed Feb 25, 2009 5:59 am     Reply with quote

Thanks for the replys,

I'm not sure people are following exactly how my code has been working so here is more of a replica of my code which shows the bug more clearly (i think).
I'm not even sure if it's the same problem as above as this bug only shows up if a structrure crosses over 0x0100 in ram.

I don't understand Pic assembler to follow what it's doing, can somebody have a look at it please.

Many thanks,

Jim


Code:
#include <18f6722.h>

#device  adc=10 *=16
#device  ICD=true

#use   delay(clock=16000000)
#fuses WDT, WDT512, INTRC_IO, PROTECT, BROWNOUT, PUT, STVREN, NODEBUG, NOMCLR, NOIESO ,NOFCMEN
#fuses NOLVP, NOWRT, NOWRTD, NOWRTB, WRTC, NOCPD, NOCPB, NOEBTR, NOEBTRB, BORV27, NOXINST, NOLPT1OSC


// symbols for units.
const enum {NONE, U_DATE, U_TIME, U_VOLUME, U_TIME_HR_MIN, U_TIME_HR_MIN_D, U_TIME_MIN_SEC};
const enum {DATA_UP_DOWN, DATA_DIGIT, DATA_DISPLAY_ONLY};

struct
{
int8 padding[231];  // 220 and code works ok, 231 and it gives the wrong address to jim3 (230 gives an internal compiler error !!, another bug)
int8 date_format;
int8 time_format;
int8 liquid_units;
int32 range_4_20ma_4ma_adj;     
int16 pin_number;
int16 some_stuff[8];
int8  lcd_contrast; // lcd contrast value
// many more here normally
}nvram;   

struct
{
   int8 seconds;
   int8 minutes;
   int8 hours;
   int8 days;
   int8 weekdays;
   int8 weeks;
   int8 months;
   int8 years;
   int16 time;
   int32 date;
} rtc_decoded;


typedef struct data_entry_struct
{
   int8  string1;                           // Description, index from string table
   int8  string2;                           // Description2, index from string table
   int8  entry_method;                      // data_entry method
   int8  var_size;                          // var size (1=int8,2=16,4=32 etc), easiest to use sizeof(var)
   int16 *var_ptr;                          // pointer to number location
   int8  dp;                                // position of DP on display
   int8  units;                             // uS, time, pin etc
   int32 min;                               // minimum value
   int32 max;                               // maximum value
   int32 deflt;                             // default value for variable if required.
};

struct data_entry_struct const data_lines[3]=
{
//description1       description2,         entry method, size                        var                   dp units            min   max            default
{ 28, /* Contrast */ 0,   /*           */  DATA_UP_DOWN, sizeof(nvram.lcd_contrast), &nvram.lcd_contrast,  0, NONE,            0,    63,            26,     },
{ 35, /* Date     */ 38,  /* dd/mm/yy  */  DATA_DIGIT  , sizeof(rtc_decoded.date),   &rtc_decoded.date,    0, U_DATE,          0,    999999,        131103, },
{ 108,/* Time     */ 54,  /* hh:mm     */  DATA_DIGIT  , sizeof(rtc_decoded.time),   &rtc_decoded.time,    0, U_TIME_HR_MIN,   0,    9999,          1200,   },
};

int16 jim1=0;
int16 jim2=0;
int16 jim3=0;
int8 index=0;

void main()
{
   setup_oscillator(OSC_16MHZ | OSC_NORMAL);
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);

   while(1)
   {
   jim1=&nvram.lcd_contrast;       // this works
   jim2=data_lines[0].var_ptr;     // this doesn't as the compiler hard codes jim2 to equal start address of nvram
   jim3=data_lines[index].var_ptr; // this doesn't work if padding on line 17 means the struct nvram crosses over 0x0100 in ram
                                   // so 220 works ok but 231 doesn't as jim3 only gets a 8 bit version of the address.
   
   restart_wdt();
   
   }
  }
 



Part of the symbol map when padding = 220 and code works.


Code:

000     @SCRATCH
001     @SCRATCH
001     _RETURN_
002     @SCRATCH
003     @SCRATCH
004     @SCRATCH
005-0FA nvram
0FB-108 rtc_decoded
109-10A jim1
10B-10C jim2
10D-10E jim3
10F     index


Part of the symbol map when padding = 231 and code doesn't work.

Code:

000     @SCRATCH
001     @SCRATCH
001     _RETURN_
002     @SCRATCH
003     @SCRATCH
004     @SCRATCH
005-105 nvram
106-113 rtc_decoded
114-115 jim1
116-117 jim2
118-119 jim3
11A     index



Part of the assembly listing when padding = 220 and code works.

Code:

                     00627 .......................    jim1=&nvram.lcd_contrast;       // this works
0008C 6B0A           00628 CLRF   jim1+1
0008E 0EFA           00629 MOVLW  nvram+245
00090 6F09           00630 MOVWF  jim1
                     00631 .......................    jim2=data_lines[0].var_ptr;     // this doesn't as the compiler hard codes jim2 to equal start address of nvram
00092 6B0C           00632 CLRF   jim2+1
00094 0E05           00633 MOVLW  nvram
00096 6F0B           00634 MOVWF  jim2
                     00635 .......................    jim3=data_lines[index].var_ptr; // this doesn't work if padding on line 17 means the struct nvram crosses over 0x0100 in ram
00098 510F           00636 MOVF   index,W
0009A 0D14           00637 MULLW  14
0009C 50F3           00638 MOVF   PRODL,W
0009E 6B11           00639 CLRF   @@x11
000A0 6F10           00640 MOVWF  @@x10
000A2 0E04           00641 MOVLW  04
000A4 2510           00642 ADDWF  @@x10,W
000A6 6E01           00643 MOVWF  @01
000A8 0E00           00644 MOVLW  00
000AA 2111           00645 ADDWFC @@x11,W
000AC 6E03           00646 MOVWF  @03
000AE 5001           00647 MOVF   @01,W
000B0 CFF2 F112      00648 MOVFF  INTCON,@@112
000B4 9EF2           00649 BCF    INTCON.GIE
000B6 0100           00650 MOVLB  0
000B8 DFA5           00651 RCALL  0004
000BA 0009           00652 TBLRD*+
000BC CFF5 F003      00653 MOVFF  TABLAT,03
000C0 0101           00654 MOVLB  1
000C2 BF12           00655 BTFSC  @@x12.7
000C4 8EF2           00656 BSF    INTCON.GIE
000C6 6F0D           00657 MOVWF  jim3
000C8 C003 F10E      00658 MOVFF  03,jim3+1



Part of the assembly listing when padding = 231 and code doesn't work.

Code:

                     00627 ........................    jim1=&nvram.lcd_contrast;       // this works
0008C 0E01           00628 MOVLW  nvram+-4
0008E 6F15           00629 MOVWF  jim1+1
00090 0E05           00630 MOVLW  nvram
00092 6F14           00631 MOVWF  jim1
                     00632 ........................    jim2=data_lines[0].var_ptr;     // this doesn't as the compiler hard codes jim2 to equal start address of nvram
00094 6B17           00633 CLRF   jim2+1
00096 6F16           00634 MOVWF  jim2
                     00635 ........................    jim3=data_lines[index].var_ptr; // this doesn't work if padding on line 17 means the struct nvram crosses over 0x0100 in ram
00098 511A           00636 MOVF   index,W
0009A 0D14           00637 MULLW  14
0009C 50F3           00638 MOVF   PRODL,W
0009E 6B1C           00639 CLRF   @@x1C
000A0 6F1B           00640 MOVWF  @@x1B
000A2 0E04           00641 MOVLW  04
000A4 251B           00642 ADDWF  @@x1B,W
000A6 6E01           00643 MOVWF  @01
000A8 0E00           00644 MOVLW  00
000AA 211C           00645 ADDWFC @@x1C,W
000AC 6E03           00646 MOVWF  @03
000AE 5001           00647 MOVF   @01,W
000B0 CFF2 F11D      00648 MOVFF  INTCON,@@11D
000B4 9EF2           00649 BCF    INTCON.GIE
000B6 0100           00650 MOVLB  0
000B8 DFA5           00651 RCALL  0004
000BA 0009           00652 TBLRD*+
000BC CFF5 F003      00653 MOVFF  TABLAT,03
000C0 0101           00654 MOVLB  1
000C2 BF1D           00655 BTFSC  @@x1D.7
000C4 8EF2           00656 BSF    INTCON.GIE
000C6 6F18           00657 MOVWF  jim3
000C8 C003 F119      00658 MOVFF  03,jim3+1


Last edited by Jim Hearne on Wed Feb 25, 2009 7:29 am; edited 1 time in total
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Wed Feb 25, 2009 6:42 am     Reply with quote

I just realized, that you are assigning a pointer value to an integer in the said cases, also in the previously posted code. Generally, these variables can't be considered assignment compatible, so the compilers action is basically undefined. Can you please try again with a code according to the C standard?

You are also mentioning problems with arrays crossing memory space boundaries, but it's unclear if theses are related to the other observations. If you feel that these additional restrictions are causing the problem, can you retry with a memory layout that avoids them?
Jim Hearne



Joined: 22 Dec 2003
Posts: 109
Location: West Sussex, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Wed Feb 25, 2009 7:28 am     Reply with quote

I don't think theres a problem, CCS seem to treat pointers the same as a normal variables. As long as it's big enough it should be fine.

Just to be sure i've recomplied with jim1, 2 and 3 declared as pointers, the problem is still there and the assembly code is still the same.

In the real program it is treated as a pointer in code like

Code:
   for(l=0;l<NO_OF_DATA_LINES;l++)  // init all nvram values   {
      size=data_entry[l].var_size;
      if(size==1)
         *(int8 *)data_entry[l].var_ptr=(int8)data_entry[l].deflt;
      else if(size==2)
         *(int16 *)data_entry[l].var_ptr=(int16)data_entry[l].deflt;
      else if(size==4)
         *(int32 *)data_entry[l].var_ptr=data_entry[l].deflt;
   }


Which initalizes all the variables refered to in the data_entry structure.

The problem with the array crossing the boundry is the same problem, it only occurs when the array crosses 0x0100 in ram.
My original example at the top simplified things too much and seems to show up another problem which doesn't matter at the moment.

Thanks,

Jim
Jim Hearne



Joined: 22 Dec 2003
Posts: 109
Location: West Sussex, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Wed Feb 25, 2009 8:11 am     Reply with quote

Further testing reveals that the problem continues at 256 byte boundaries.
So if an extra array of
int8 more_padding[260];
is added before the nvram structure is declared then both jim2 and jim3 get the incorrect address of 0x0109 and only jim1 gets the correct result of 0x0209

This means i can't get round the problem by that method as in the real program structure nvram is larger than 255 bytes.

Jim
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Wed Feb 25, 2009 10:02 am     Reply with quote

I remember, that a 256 byte offset restriction could be observed in some situations, but it think, there have been workarounds. Unfortunately I'm busy with some projects now, but I would like to look into it, unless other forum members have solved the issue in between.

Sorry for leading you on a wrong track with the pointer versus integer topic, but I learned from experience, that a compiler sometimes can be very strict in this regard.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Wed Feb 25, 2009 3:23 pm     Reply with quote

I tried to figure what's actually happening with your code and found two similar, but different bugs, both described correctly in your comments to the assembly code.

The first, more general is regarding pointers to structure members with offsets above 0xff. They are only evaluated correctly in some situation, e. g. simple assignments as jim1=&nvram.lcd_contrast; but incorrectly when calculating pointer constants as used to fill data_lines. This bug isn't particularly related to ROM constants, it also happens when data_lines is located in RAM.

In your example, a possible workaround is to split nvram in several partial arrays, that are placed consecutively in RAM and thus can be accessed also by a continuous index.

A more special bug reveals with jim2=data_lines[0].var_ptr; . It only affects ROM constants, and is caused apparently by a not well designed CCS C shortcut, intended to save the TBLRD overhead, when the constant value can be easily calculated at compile time. Unfortunately the shortcut seems to ignore structure member offsets. I didn't yet find a workaround other than your index=0 construct for jim3.

Don't forget to report the bug at CCS and in win a free update when it has been finally fixed.

P.S.: I saw that you stated splitting nvram doesn't work, but I saw it working, can you try a new with partial arrays below 0x100 size?
Jim Hearne



Joined: 22 Dec 2003
Posts: 109
Location: West Sussex, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Thu Feb 26, 2009 2:35 am     Reply with quote

Many thanks FvM for taking the time to confirm the bugs.
A pity CCS aren't so quick at replying, i emailed them several days ago before i posted the first message here and again yesterday after i narrowed it down.

PCW ver 8.086 then stopped working completly, crashing at startup and CCS have been helping with that problem, the difference being i emailed support@ccsinfo.com directly instead of going through the support request option in the compiler.
I'll try the direct address with these bugs, i've not had any support via the normal route in the last 6 months or more despite a current subscription.

Splitting nvram was my next attempt to get round the problem, it's a bit of a pain as the struct nvram is read and written from a loop to backup all the variables in it to EEPROM. So i'll have to duplicate that code and the checksums on it to handle 2 stuctures but it can be done.

Thanks again for your help.

Jim
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Feb 26, 2009 3:37 am     Reply with quote

My idea with splitting nvram was to use an alias integer array spanning the full range, e.g. for copy operations or checksum generation, but I don't know, if this fits your application.

I'm waiting for several PCD bug fixes since october 2008, I'll decide about a software maintenance plan, when I see substantial progress in this regard. Unfortunately, most bug reports have a status of "we have not had time to further review your e-mail" or at best "A priority has not yet been determined for this issue". However, some arbitray bug reports have been processed rather quickly.

So these guys are apparently very busy, but working somehow.

Frank
Jim Hearne



Joined: 22 Dec 2003
Posts: 109
Location: West Sussex, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Thu Feb 26, 2009 5:58 am     Reply with quote

Alias ? Do you mean union ?, i wonder if that would work.....
I'm hanging on for today in the hope that CCS will reply with a bug fix but i guess they have only just got up over in the US


Out of interest how can i find out where in rom the compiler stores const data, i can't find it in the list lising or symbol files.
In debugging mode do eval on const variables just gives an "unable to read RAM error" !
Mine you even the mouse over has never worked on const's, either giving garbage values or a similar ram error.

Jim
Jim Hearne



Joined: 22 Dec 2003
Posts: 109
Location: West Sussex, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Thu Feb 26, 2009 10:19 am     Reply with quote

Using a union of the struct nvram split into 2 plus an array the size of them both has given me a work around.

Abit at the expense of making the code a bit messy.

I now have to use nv.ram.a.lcd_contrast instead of just nvram.lcd_contrast but i can live with it.

Thanks,

Jim
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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