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

bit field changes from 3.098 to 3.245

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



Joined: 15 Feb 2007
Posts: 17

View user's profile Send private message

bit field changes from 3.098 to 3.245
PostPosted: Sun Feb 18, 2007 3:55 pm     Reply with quote

particulars: PIC16F877A, PCM 3.245, MPLAB 7.50

history: working on a project in 3.098 but upgraded to 3.245 because of RAM bank paging bugs in 3.098. Now portions of my code which worked before compile but don't produce the expected output

I am essentially doing a directed word ladder application. 4-character words are stored with "scoring information" packed into a 32-bit structure in an external FRAM chip (5 bits/char + 12 bits of scoring info).

In my code, I define the following structs

Code:

struct FRAM_word_data {
  int   iscore:3;      // the inherent value of the word
  char  c1:5;         // the first letter of the word
  int     cscore:3;      // the current value of the word
  char  c2:5;         // the second letter of the word
  int   good_end:1;      // "good ending" flag
  int   sexy:2;         // sexiness score
  char    c3:5;         // the third letter of the word
  int   cat3:1;         // category 3 flag
  int   cat2:1;         // category 2 flag
  int   cat1:1;         // category 1 flag
  char    c4:5;         // the fourth letter of the word
};

typedef struct {
  struct FRAM_word_data      data;
  char                  letters[5];
  int16                  index;
} dictionary_word;


The order of the FRAM_word_struct entries is odd because I found that (at least in 3.098) not only do all bit fields together have to fit within a multiple of int, they also need to end on int boundaries within the struct. That may have changed with 3.245.

Then, the relevant part of main looks like:

Code:

main {
  dictionary_word start_word;
  int16 address;

    for (address=0;address<2;address++) {
      start_word.index = address;
      read_word(&start_word);
    }

  ...
}


with

Code:

void read_word(dictionary_word * word)
{
  int data_bytes[4];
  int32 word_data=0;

  for (i=0;i<4;i++)
    data_bytes[i]=FRAM_read((4*(*word).index)+i);
 
  word_data=make32(data_bytes[3],data_bytes[2],data_bytes[1],data_bytes[0]);
  (*word).data=(struct FRAM_word_data)word_data;

  printf("1: 0x%LX\n\r",word_data);
  printf("2: %c,%c,%c,%c\n\r",(*word).data.c1,(*word).data.c2,(*word).data.c3,(*word).data.c4);
  printf("3: %u,%u,%u,%u\n\r",(*word).data.c1,(*word).data.c2,(*word).data.c3,(*word).data.c4);
  printf("4: %c,%c,%c,%c\n\r",(*word).data.c1+64,(*word).data.c2+64,(*word).data.c3+64,(*word).data.c4+64);
  printf("5: %u,%u,%u\n\r",(*word).data.c1,(int)(*word).data.c1,(int)((*word).data.c1+64));

  (*word).letters[0]=(*word).data.c1+64;
  (*word).letters[1]=(*word).data.c2+64;
  (*word).letters[2]=(*word).data.c3+64;
  (*word).letters[3]=(*word).data.c4+64;
  (*word).letters[4]=0x00;               // null terminator for printing

  printf("6: %s\n\n\r",(*word).letters);

}


The printf's in there are part of my current debugging.

So the 4 bytes are read from FRAM, combined into an int32, which is then mapped onto the FRAM_word_data struct. Characters are stored as numbers from 1-26, so need to have 64 added to them to get the right ascii code.

This code used to work when compiled with 3.098. Reading the first two words from FRAM now produces the following output:

Code:

1: 0xA62A140C
2: ,,,
3: 1,2,5,20
4: Y,@,C,@
5: 1,12,64
6: @@@@

1: 0xA1AA1109
2: ,,,
3: 1,2,21,20
4: X,@,C,@
5: 1,9,64
6: @@@@


The first word is ABET, the second word is ABUT. Line 1 of the output confirms that what I think is in the FRAM is being read into word_data. The unprintable characters on line 2 are the correct ones in my output (i.e., the ascii equivalents of chr(1),chr(2),chr(5),chr(20) and chr(1),chr(2),chr(21),chr(20)), as seen in line 3. This confirms that word_data is getting mapped to the data structure correctly.

Questions:

1. in line 4, how do those characters make sense? Y is not chr(1+64) (nor are the others right) and why would the 2nd and 4th characters be the same?

2. in line 5, why does casting as (int) change the integer value of (*word).data.c1? Is it because that's a 5-bit field and casting as int (as opposed to just using it as one) is picking up other bits? But then wouldn't they add at least 32? And why is it different each time through, even though the value of (*word).data.c1 is 1 both times?

3. in line 5, why does adding 64 and THEN casting as int give 64?

4. in line 6, these characters should essentially be identical to those in line 4 because of the way they're assigned, but they're different... ??

I noticed in this thread that the treatment of bit fields may have changed at some point between 3.098 and 3.245 (is there a comprehensive changelog somewhere?)

http://www.ccsinfo.com/forum/viewtopic.php?t=28966

Does anyone know if this is perhaps a result of those changes? I tried setting +Y=0 but to no avail.

Help appreciated!

Rob.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Feb 18, 2007 4:58 pm     Reply with quote

This is a massive post. Is there anyway you can condense it ?
Maybe just one example and one question. Post a very small
test program. Show what you're getting and show what you
want to get. Reduce the structure size and everything. I mean, small.
rbgorbet



Joined: 15 Feb 2007
Posts: 17

View user's profile Send private message

PostPosted: Sun Feb 18, 2007 5:06 pm     Reply with quote

Hmmm...I'll try. I went to a lot of trouble to clarify what I'm trying to do and I'm worried that if I write something new and it doesn't work, I won't know if it would have worked in 3.098, since I don't have it any more. On the other hand, if a smaller test program works, that doesn't mean that the larger one isn't suffering from something related to RAM bank switching in large programs, etc (but then, I would know something I don't now).

I'll try to do that in the next hour.

Rob.
rbgorbet



Joined: 15 Feb 2007
Posts: 17

View user's profile Send private message

PostPosted: Sun Feb 18, 2007 6:01 pm     Reply with quote

Okay, here's the gist. I made the structure smaller, used constant bytes instead of reading from RAM, and removed the function call. I kept the bit fields because I think that's part of the issue. The code section is still a bit long but I've commented it so it should be readable.

Code:

struct FRAM_word_data {
  int   iscore:3;      // the inherent value of the word
  char  c1:5;         // the first letter of the word
  int     cscore:3;      // the current value of the word
  char  c2:5;         // the second letter of the word
};

typedef struct {
  struct FRAM_word_data      data;
  char                  letters[3];
  int16                  index;
} dictionary_word;

...

dictionary_word word;
dictionary_word * wordptr;

// These two bytes will be mapped onto the FRAM_word_data struct. 
// The 5 high bits of each byte contain a number 1-26 corresponding to A-Z.
// For this example, the low 3 bits are not important.
    bytes[0]=1<<3;                      // character A
    bytes[1]=26<<3;                    // character B

// Map the 16-bit packed data onto the structure
    word_data = ((int16)bytes[1]<<8) | bytes[0];
    word.data = (struct FRAM_word_data)word_data;

// Conver the 1-26 character indices into a string 
    word.letters[0]=word.data.c1+64;
    word.letters[1]=word.data.c2+64;
    word.letters[2]=0x00;

    printf("word data: %LX\n\r",word_data);
    printf("c1=%u, c2=%u\n\r",word.data.c1,word.data.c2);
    printf("%c%c = %s\n\r",word.data.c1+64,word.data.c2+64,word.letters);

// Do it again with pointers
    (*wordptr).data = (struct FRAM_word_data)word_data;
 
    (*wordptr).letters[0]=(*wordptr).data.c1+64;
    (*wordptr).letters[1]=(*wordptr).data.c2+64;
    (*wordptr).letters[2]=0x00;

    printf("word data: %LX\n\r",word_data);
    printf("c1=%u, c2=%u\n\r",(*wordptr).data.c1,(*wordptr).data.c2);
    printf("%c%c = %s\n\r",(*wordptr).data.c1+64,(*wordptr).data.c2+64,(*wordptr).letters);


The output for this is:

Code:

word data: D008
c1=1, c2=26
AZ = AZ
word data: D008
c1=1, c2=26
X@ = @@


The behaviour I'm trying to achieve is that seen when accessing the structure directly, but I need to pass the structure by reference to a function so I want to use pointers. In 3.098, the pointer version was behaving as expected, but now the output for the two pieces of code are different. Why?

I hope this is shorter and more readable.

[edit: I've gone to 16-bit pointers since I was working in 3.098 to get more RAM, so that's probably the issue, but I still don't understand why it wouldn't work...]

Thanks,
Rob.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Feb 18, 2007 6:21 pm     Reply with quote

Can you post the desired output of the program, vs. the bad output.
Example:

Here is the good output from 3.098:

// fill it in here.


Here is the bad output from 3.245.

// Fill it in here.


To get that information, compile your program under each version
of the compiler.

In other words, the reason I'm asking all this is because I don't want
to have to assume anything. I want it all crystal clear.
rbgorbet



Joined: 15 Feb 2007
Posts: 17

View user's profile Send private message

PostPosted: Sun Feb 18, 2007 8:32 pm     Reply with quote

Okay, took a while because I had to figure out how to have both installed at once. I also stripped down the code to the point where there is not much more in the code than what's below.

Essentially the problem seems to be with the way I'm using indirect access to get into the struct (either I'm doing it wrong and 3.098 was forgiving, or 3.245 isn't doing it right).

Code:

...
struct FRAM_word_data {
  int   iscore:3;      // the inherent value of the word
  char  c1:5;         // the first letter of the word
  int     cscore:3;      // the current value of the word
  char  c2:5;         // the second letter of the word
};

typedef struct {
  struct FRAM_word_data      data;
  char                  letters[3];
} dictionary_word;
...
void main()
{
   dictionary_word word;
   dictionary_word * wordptr=&word;
   int bytes[2];
   int16 word_data;

...

  // the following two lines place a 1 and 26 so that they line up
  // with the c1 and c2 bit fields in the struct.  I don't care about the
  // score fields for this example.
    bytes[0]=1<<3;
    bytes[1]=26<<3;

    word_data = ((int16)bytes[1]<<8) | bytes[0];
    word.data = (struct FRAM_word_data)word_data;
 
    word.letters[0]=word.data.c1+64;
    word.letters[1]=word.data.c2+64;
    word.letters[2]=0x00;

    printf("word data: %LX\n\r",word_data);
    printf("c1=%u, c2=%u\n\r",word.data.c1,word.data.c2);
    printf("%c%c = %c%c = %s\n\r",word.data.c1+64,word.data.c2+64,word.letters[0],word.letters[1],word.letters);

    (*wordptr).data = (struct FRAM_word_data)word_data;
 
    (*wordptr).letters[0]=(*wordptr).data.c1+64;
    (*wordptr).letters[1]=(*wordptr).data.c2+64;
    (*wordptr).letters[2]=0x00;

    printf("word data: %LX\n\r",word_data);
    printf("c1=%u, c2=%u\n\r",(*wordptr).data.c1,(*wordptr).data.c2);
    printf("%c%c = %c%c = %s\n\r",(*wordptr).data.c1+64,(*wordptr).data.c2+64,\
                                  (*wordptr).letters[0],(*wordptr).letters[1],(*wordptr).letters);
 


The output compiled under 3.908 is

Code:

word data: D008
c1=1, c2=26
AZ = AZ = AZ
word data: D008
c1=1, c2=26
AZ = AZ = AZ


The first three lines and second three lines are identical, as I expected. The second three lines are printed accessing the variables indirectly using a pointer.

The output compiled under 3.245 is

Code:

word data: D008
c1=1, c2=26
AZ = AZ = AZ
word data: D008
c1=1, c2=26
EH = AB = AB


The indirect access isn't working.

Because I've stripped the code down, there is no need in this sample to use 16-bit pointers so this is with *=8.

Rob.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Feb 18, 2007 10:54 pm     Reply with quote

The problem appears to be fixed in PCM vs. 3.249. It has this output:
Quote:

word data: D008
c1=1, c2=26
AZ = AZ = AZ

word data: D008
c1=1, c2=26
AZ = AZ = AZ

I've tried to find a work-around for vs. 3.245 but no success so far.

Maybe you can report this bug and get CCS to upgrade you to 3.249
on Monday. They'd probably do it because it's the last of the 3.xxx
compilers and your version isn't too far away from it.
rbgorbet



Joined: 15 Feb 2007
Posts: 17

View user's profile Send private message

PostPosted: Sun Feb 18, 2007 11:07 pm     Reply with quote

Wow, well thank you for confirming I'm not out of my head. I will report it tonight before I go to sleep and point to this thread.

[edit: Just to confirm: were you able to reproduce the problem in 3.245? So I know it's not my setup.]

Thanks again for all your help!

Rob.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Feb 18, 2007 11:24 pm     Reply with quote

Vs. 3.245 does this:
Code:

word data: D008
c1=1, c2=26
AZ = AZ = AZ

word data: D008
c1=1, c2=26
A@ = AB = AB
rbgorbet



Joined: 15 Feb 2007
Posts: 17

View user's profile Send private message

PostPosted: Sun Feb 18, 2007 11:42 pm     Reply with quote

Great, thanks.

If you're still looking for clues, I've noticed that depending on...something...the last line will be

ab = cd = cd

where "cd" is always the same (and so far always "AB"), but "ab" seems to depend on the compile (where things are allocated?)

In my posted example, "ab" was "EH" but in yours it was "A@".

Rob.
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