|
|
View previous topic :: View next topic |
Author |
Message |
chenzhuo
Joined: 17 Jan 2015 Posts: 8 Location: 美国
|
rom space of two const arrays overlap |
Posted: Sat Jan 17, 2015 5:40 am |
|
|
compiler: 5.025
Hardware: PIC18F46K22
IDE: MPLAB X
It is probably a compiler issue, but i'm not sure. Hence i post it and see who else encounter the same issue.
The symptom is when multiple const array defined in different compilation unit, the generated rom spaces of two arrays overlap.
User Memory space: rom
00FFF2-00FFFF b
00FFF2-00FFFF a
Below code is the a simple code fragment which demonstrates the issue:
main.c
Code: |
#include <main.h>
int8 const b[] = {2,2,2,2,2,2,2,2,2,2,2,2,2,2};
void main()
{
int8 i;
for(i=0; i<5;i++){}
int8 c = b[0];
}
}
|
This is another compilation unit: unit1.c
Code: |
#include <main.h>
int8 const a[] = {1,1,1,1,1,1,1,1,1,1,1,1};
|
The header file: main.h
Code: |
#include <18F46K22.h>
#device const=rom
|
The expected value of array a[i] is 1, however, the actual return value is 2. Hence i checked the symbol file and found the spaces/address of the two const array overlap.
Code: |
ROM Allocation:
000004 @READ_PROGRAM_MEMORY
000024 main
000024 @cinit1
000046 @cinit2
User Memory space: rom
00FFF2-00FFFF b
00FFF2-00FFFF a
|
Note above symbol, array a and b are of the identical space, which also result in error in my project.
Is there anyone know this issue? Or it is just because an incorrect compilation switch is used? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Sun Jan 18, 2015 8:53 am |
|
|
Of course they will.....
If you want to reserve space in one module for another, then you need to add the commands to the module to do this.
It looks as if you are compiling what are effectively two separate programs, and expecting the compiler to magically 'know' about the other. It won't.
Look at the example 'mcu.zip', which shows how to configure multiple compilation units. |
|
|
chenzhuo
Joined: 17 Jan 2015 Posts: 8 Location: 美国
|
|
Posted: Sun Jan 18, 2015 9:50 am |
|
|
Thanks for replying, Ttelmah
The multiple compilation units work fine in my project except this rom space overlap issue. I checked the mcu.zip you mentioned but I didn't find anything about how to setup a const/rom configuration. However, i opened the project in mcu.zip with mplab X and defined two const arrays in two different c files respectively, the result is just the same to my own project: the rom space of two const arrays overlap.
I guess you are saying that the #device const=rom can not be used in multiple compilation units, because it causes the two const arrays are placed in the same rom space, this is how the #device const=rom designed. Am I right?
I checked all the documents CCS provided and also searched via google but I failed to find a document which describes how the #device const=rom behaves in multiple compilation units...
Ttelmah wrote: | Of course they will.....
If you want to reserve space in one module for another, then you need to add the commands to the module to do this.
It looks as if you are compiling what are effectively two separate programs, and expecting the compiler to magically 'know' about the other. It won't.
Look at the example 'mcu.zip', which shows how to configure multiple compilation units. |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Sun Jan 18, 2015 10:10 am |
|
|
I'm not sure how you are configuring the code, but by default the location for a const, is controlled by the 'default' in a build statement. If you are building a component separately from another, then you need to define where this sits to avoid constants overlapping. |
|
|
chenzhuo
Joined: 17 Jan 2015 Posts: 8 Location: 美国
|
|
Posted: Sun Jan 18, 2015 10:33 am |
|
|
Two const arrays locate in separated rom spaces, which is expected, if #device const=rom is not defined in header.
Hence I think the abnormal behavior is caused by this directive.
Anyway, the purpose that I use #device const=rom is to work around another issue - Const array returns incorrect value when it is accessed in my project. I found if the #device const=rom is added in the header the const array returns correct value.
Ttelmah wrote: | I'm not sure how you are configuring the code, but by default the location for a const, is controlled by the 'default' in a build statement. If you are building a component separately from another, then you need to define where this sits to avoid constants overlapping. |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Mon Jan 19, 2015 4:30 am |
|
|
I'd guess you are trying to use pointers to the array?.
Look in the manual.
The standard 'const' behaviour, does not allow pointers to be constructed. The pass strings in RAM option allows them to be built. The alternative is to use rom, instead of const, which generates a rom constant, for which pointers can be built (but the pointers have to be declared as rom pointers).
A search here will find a lot about this. It is caused by the memory architecture of the PIC (Harvard, as opposed to Von Neumann). With the Harvard architecture, there are two separate memory spaces for rom, and ram, as opposed to the single linear architecture. Hence 'address 0' for example, is present in both memory spaces separately. So if you use a pointer to a const, it'll be looking at the wrong memory space. The 'pass strings' option tells the compiler to virtualise the access 'through' a temporary ram memory area. The rom pointer and rom declaration, instead tell the compiler to create the code to access the second memory space, without this virtualisation:
Code: |
int8 rom silly_data[] = {1,2,3,4,5,6,7,8,9}; //constant data
int8 rom* ptr; //pointer to constant data
int demo;
ptr=&silly_data[4];
demo=*ptr; //5 from the array.
|
|
|
|
chenzhuo
Joined: 17 Jan 2015 Posts: 8 Location: 美国
|
|
Posted: Mon Jan 19, 2015 7:09 am |
|
|
No, i know the pointer to const issue/limitation.
My usage is almost the same as below code, no pointer is involved.
Code: |
const BYTE b[] = {1,2,3,4};
void foo()
{
int8 i;
for(i=0; i<5;i++){
int8 c = b[i]; //<=b[i] doesn't return the correct value
...
}
}
|
By searching the forum, i found one or two similar cases were reported, but no solution found.
Once I thought it may be caused by some error I made in another place and impact this const array. But by analyzing the generated ASM code i found the ASM of two const array are almost identical except the data address from where the program memory is read. One works fine, another doesn't.
Ttelmah wrote: | I'd guess you are trying to use pointers to the array?.
Look in the manual.
The standard 'const' behaviour, does not allow pointers to be constructed. The pass strings in RAM option allows them to be built. The alternative is to use rom, instead of const, which generates a rom constant, for which pointers can be built (but the pointers have to be declared as rom pointers).
A search here will find a lot about this. It is caused by the memory architecture of the PIC (Harvard, as opposed to Von Neumann). With the Harvard architecture, there are two separate memory spaces for rom, and ram, as opposed to the single linear architecture. Hence 'address 0' for example, is present in both memory spaces separately. So if you use a pointer to a const, it'll be looking at the wrong memory space. The 'pass strings' option tells the compiler to virtualise the access 'through' a temporary ram memory area. The rom pointer and rom declaration, instead tell the compiler to create the code to access the second memory space, without this virtualisation:
Code: |
int8 rom silly_data[] = {1,2,3,4,5,6,7,8,9}; //constant data
int8 rom* ptr; //pointer to constant data
int demo;
ptr=&silly_data[4];
demo=*ptr; //5 from the array.
|
| [/code] |
|
|
chenzhuo
Joined: 17 Jan 2015 Posts: 8 Location: 美国
|
|
Posted: Mon Jan 19, 2015 7:27 am |
|
|
Hi there,
I found a easy way to reproduce the issue:
Code: |
const BYTE a[] = {1,2,3,4,5,6};
const BYTE b[] = {11, 12,13,14,15,16};
void main(){
systemInit();//init the system if it is necessary
for(int i = 0; i< sizeof(a)/sizeof(BYTE) ; i++){
printf("a = %u, b=%u \r\n", a[i], b[i]);
}
}
|
My compiler is 5.025, IDE is mplab X.
The output is:
Code: |
a = 1, b=0
a = 2, b=0
a = 3, b=0
a = 4, b=0
a = 5, b=0
a = 6, b=0
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Mon Jan 19, 2015 8:35 am |
|
|
Have just tried that code in MPLAB (not X), with 5.025, and it merrily gives:
Code: |
a = 1, b=11
a = 2, b=12
a = 3, b=13
a = 4, b=14
a = 5, b=15
a = 6, b=16
|
Cut and pasted from the UART window.
Gives the same if IN_RAM is selected or not.
Used 5.025, since this is what you have. |
|
|
chenzhuo
Joined: 17 Jan 2015 Posts: 8 Location: 美国
|
|
Posted: Mon Jan 19, 2015 10:45 am |
|
|
Interesting discovery:
If I compiled in a single compilation unit, the result is just what I expected:
Code: |
a = 1, b=11
a = 2, b=12
a = 3, b=13
a = 4, b=14
a = 5, b=15
a = 6, b=16
|
However, when another compilation unit with any content is added into project, the result is incorrect:
Code: |
a = 1, b=0
a = 2, b=0
a = 3, b=0
a = 4, b=0
a = 5, b=0
a = 6, b=0
|
I hope i am wrong but all clues indicate it should be a compiler issue. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Mon Jan 19, 2015 1:46 pm |
|
|
I do have to ask 'why' you are using the multiple compilation units?.
As has been outlined in the past, CCS is at heart a single pass compiler. It optimises better when only used this way. Given that it usually takes perhaps 100* as long to program the chip as the compiler takes for even a 50000 line program, using multiple compilation units is not normally done. |
|
|
chenzhuo
Joined: 17 Jan 2015 Posts: 8 Location: 美国
|
|
Posted: Mon Jan 19, 2015 8:46 pm |
|
|
From software engineering perspective, i'd like to separate my code into several different module, hence the source code conflict could be avoided when collaborate with my partner and also code is of more readability.
Yes, i have realized that CCS as embedded chip compiler is of a lot of limitation/restrictions that prevent my project from utilizing some typical technology. For example the pointer to function can not nest, and pointer to function has difficulty in complex structure. Although all of them could be worked around but it really gave me a lot of troubles and funs.
Anyway, thank you Ttelmah. You really help me to identify the issue, as the root cause now is clear then I can find a workaround.
Ttelmah wrote: | I do have to ask 'why' you are using the multiple compilation units?.
As has been outlined in the past, CCS is at heart a single pass compiler. It optimises better when only used this way. Given that it usually takes perhaps 100* as long to program the chip as the compiler takes for even a 50000 line program, using multiple compilation units is not normally done. |
|
|
|
|
|
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
|