View previous topic :: View next topic |
Author |
Message |
freddy_mp
Joined: 07 Jun 2013 Posts: 1
|
address calculation problem with new compiler version |
Posted: Fri Jun 07, 2013 7:59 am |
|
|
Hi
I used the version V3 for a lot of projects.
Now I change to Version5. (V5.005 )
And I have some unexpected failures.
I use this to split a long int to lo and hi byte:
Code: | #define hi(x) (*(&x+1))
#define lo(x) (*(&x))
long int h;
h=0x1122;
lo(h) gives 0x22 (correct)
hi(h) gives 0x22 (incorrect, expect 0x11 )
|
It works fine with later versions of the compiler.
But with the actual compiler I got the low-byte every time.
What is changed and what is the solution for this problem?? |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Fri Jun 07, 2013 8:48 am |
|
|
do you know about the make8() function?
it is VERY code efficient and works in all compiler versions. |
|
|
drh
Joined: 12 Jul 2004 Posts: 192 Location: Hemet, California USA
|
|
Posted: Fri Jun 07, 2013 8:53 am |
|
|
There was a change in one of the 4.xxx versions. This is from the V4.139 readme file:
Quote: | Users that have old code with expresions of the form:
*(&data + i)
need to change them to:
*((int8 *)(&data) + i)
A compiler change was made to be ANSI compliant.
|
Jumping from V3.xxx to V5.005, you have missed about 141 "versions" _________________ David |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Jun 07, 2013 1:07 pm |
|
|
Quote: | Users that have old code with expresions of the form:
*(&data + i)
need to change them to:
*((int8 *)(&data) + i)
A compiler change was made to be ANSI compliant. |
The change is regarding the pointer type assumed in address arithmetic. The ANSI standard expect
an address increment according to the type of the variable. To address the high byte, you need a typecast to
int8 pointer type.
Although the suggested change does "work" (= gives correct result) in CCS V4.xxx, it produces ridiculous long
winded code, as you can see below. compare with make8() code.
Code: | 00531 .................... b = lo(h);
010C 6A03 00532 CLRF 03
010E 0E4B 00533 MOVLW 4B
0110 6EE9 00534 MOVWF FE9
0112 C003 FFEA 00535 MOVFF 03,FEA
0116 CFEF F048 00536 MOVFF FEF,48
00537 .................... b = hi(h);
011A 6A4E 00538 CLRF 4E
011C 0E4B 00539 MOVLW 4B
011E 6E4D 00540 MOVWF 4D
0120 0E01 00541 MOVLW 01
0122 244D 00542 ADDWF 4D,W
0124 6E01 00543 MOVWF 01
0126 0E00 00544 MOVLW 00
0128 204E 00545 ADDWFC 4E,W
012A C001 FFE9 00546 MOVFF 01,FE9
012E 6EEA 00547 MOVWF FEA
0130 CFEF F048 00548 MOVFF FEF,48 |
Code: | 00550 .................... b=make8(h,0);
0134 C04B F048 00551 MOVFF 4B,48
00552 .................... b=make8(h,1);
0138 C04C F048 00553 MOVFF 4C,48 |
The original hi(x) code accesses the byte at offset +2, thus it does not return the low byte. Either the
respective byte holds the value 0x22 by chance, or there's a new bug in CCS V5.005.
I was assuming PCH (PIC18 code).
P.S.: I checked with PCH V5.006, the code is working as with recent V4.xxx versions. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Fri Jun 07, 2013 1:45 pm |
|
|
and, I should point out that it is not just ANSI, but the original K&R definitions that require a pointer to increment by the object size.
It was a major bug in the earlier CCS versions, in terms of 'C' as a whole...
Best Wishes |
|
|
drh
Joined: 12 Jul 2004 Posts: 192 Location: Hemet, California USA
|
|
Posted: Fri Jun 07, 2013 3:13 pm |
|
|
And we can probably expect and should be prepared for the standard "first 50 versions are buggy" feature in version 5. _________________ David |
|
|
drh
Joined: 12 Jul 2004 Posts: 192 Location: Hemet, California USA
|
|
Posted: Fri Jun 07, 2013 3:15 pm |
|
|
asmboy wrote: | do you know about the make8() function?
it is VERY code efficient and works in all compiler versions. |
This is what I did. _________________ David |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Fri Jun 07, 2013 3:56 pm |
|
|
i almost forgot . this is just as efficient as make8() and for
some situations - perhaps more notationally compact ?
Code: |
typedef struct {
int8 lowb;
int8 highb;
}ezmake;
ezmake myvar;
// myvar becomes effectively an unsigned int16
// low byte , int8 myvar.lowb
// high byte , int8 myvar.highb
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Fri Jun 07, 2013 11:35 pm |
|
|
The slightly more 'complete' version, is using a union:
Code: |
typedef struct {
int8 lowb;
int8 highb;
}ezmake;
union {
ezmake b;
int16 word;
} val;
int bval;
val.word=0x1122;
bval = val.b.lowb;
//reads 0x22
bval = val.b.highb;
//reads 0x11
val.b.lowb=0x44;
val.b.highb=0x22;
//val.word, is now 0x2244
|
Now the nice thing is the assembler.
Code: |
.................... val.word=0x1122;
0114: MOVLW 11
0116: MOVWF 1A
0118: MOVLW 22
011A: MOVWF 19
.................... index = val.b.lowb;
011C: MOVFF 19,1B
.................... index = val.b.highb;
0120: MOVFF 1A,1B
....................
.................... val.b.lowb=0x44;
0124: MOVLW 44
0126: MOVWF 19
.................... val.b.highb=0x22;
0128: MOVLW 22
012A: MOVWF 1A
|
As efficient as possible, and the code looks nice too.
Best Wishes |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sat Jun 08, 2013 3:26 am |
|
|
Quote: | And we can probably expect and should be prepared for the standard "first 50 versions are buggy" feature in version 5. |
This was my first thought when hearing about CCS C V5 release. But hopefully it isn't the case. It depends
on how much the compiler core design has been touched with the implementation of new features.
I ought a comment on the CCS way of translating (*(&x)) in my previous post. Experienced CCS users
avoid such constructs because they know about the limited compiler capabilities to understand it's meaning.
But why is it so? CCS C seems to evaluate these constructs stepwise like a school starter reads a sentence,
(creating a pointer and dereferencing it), so it manages to blow up 2 instructions cycles to 7 or even 13.
Poorly supported standard C constructs like (*(&x)) are an issue when software components or full projects
are ported between processor platforms or different tools and involve a lot of manual rework. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Jun 08, 2013 1:14 pm |
|
|
Quote: |
seems to evaluate these constructs stepwise like a school starter reads a sentence
|
I have noticed this in other instances too -
but could it be that this is simply an unavoidable consequence
of being a single pass compiler?
You can chalk it up to my paranoia - but i confess openly that i may tend to over-specify nested math to insure correct OoO prioritization and casting
to avoid any potential for ambiguity in the compilation process.
such as :
Code: |
unsigned int8 whatever; // even though unsigned IS the default
unsigned int32 thatone;
// and then
thatone= (unsigned int32) whatever * (33L /( (7L*thatone) * (unsigned int32) (whatever-7)));
|
|
|
|
|