|
|
View previous topic :: View next topic |
Author |
Message |
rbgorbet
Joined: 15 Feb 2007 Posts: 17
|
bit field changes from 3.098 to 3.245 |
Posted: Sun Feb 18, 2007 3:55 pm |
|
|
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
|
|
Posted: Sun Feb 18, 2007 4:58 pm |
|
|
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
|
|
Posted: Sun Feb 18, 2007 5:06 pm |
|
|
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
|
|
Posted: Sun Feb 18, 2007 6:01 pm |
|
|
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
|
|
Posted: Sun Feb 18, 2007 6:21 pm |
|
|
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
|
|
Posted: Sun Feb 18, 2007 8:32 pm |
|
|
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
|
|
Posted: Sun Feb 18, 2007 10:54 pm |
|
|
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
|
|
Posted: Sun Feb 18, 2007 11:07 pm |
|
|
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
|
|
Posted: Sun Feb 18, 2007 11:24 pm |
|
|
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
|
|
Posted: Sun Feb 18, 2007 11:42 pm |
|
|
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. |
|
|
|
|
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
|