|
|
View previous topic :: View next topic |
Author |
Message |
nurquhar
Joined: 05 Aug 2006 Posts: 149 Location: Redditch, UK
|
#ORG controls CONST data but not ROM data ? |
Posted: Sun Mar 10, 2013 5:19 am |
|
|
I was looking to place read only data structs into some program memory at a a fixed address.
If I use const in combination with #org I can place my data where I like. However since const puts some extra code in front of the data you can't then use a pointer to the memory address to access it. As the manual says you should use expression an expressions like x = value[9] to access it and not a pointer.
The alternative provided by CCS for address pointer access to program memory data is the 'rom' keyword. This works fine and seems by default to place the data a the top of the PICs memory.
However putting a #org in front of the declaration has no effect on where the compiler places the data in memory.
So for this :
Code: | #define OUTPUTS 36
// Each element of route
typedef struct {
int8 hour ; // Start Time, hour
int8 min ; // Start Time, min
int1 path[OUTPUTS] ; // Path of points
} element ;
// Time table
typedef struct {
int1 days[7] ; // Valid days of week 0=Sun,1=Mon ...
int8 beg ; // First element
int8 end ; // Last element
} table ;
#org 0x9000,0x9FFF
// The Elements
rom element table_e[] = {
// Hr,Mn 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
{12,0, 1,0,0,0,0,0,0,0}, // 0
{12,30, 1,1,1,0,0,0,0,0}, // 1
{12,45, 1,1,1,1,0,0,0,0}, // 2
{13,0, 0,0,0,0,0,1,0,0}, // 3
{13,30, 1,1,1,1,1,1,0,0} // 4
} ;
// The timetable
rom table table_t[] = {
// S,M,T,W,T,F,S b, e
{0,1,0,1,0,1,0, 1, 2},
{1,0,1,0,1,0,1, 3, 4}
} ;
#org default |
I get the data place here :
Code: | ROM data:
01FFCE: 2A 01 02 55 03 04
01FFD4: 0C 00 01 00 00 00 00 0C 1E 07 00 00 00 00 0C 2D
01FFE4: 0F 00 00 00 00 0D 00 20 00 00 00 00 0D 1E 3F 00
01FFF4: 00 00 00
|
So why does CCS not allow #org to work with rom keyword Is there another way to control address at which 'rom' place the data ?
I am using PCH V4.133 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Sun Mar 10, 2013 5:33 am |
|
|
Use #ROM......
const, puts the program to retrieve the data in front of the data.
rom, add further code, to allow pointers to be generated to the constant data. This requires it to have a separate table to hold the pointers. By default this second table is in the code where the rom is declared, and the actual data table is put at the top of the available address range.
You can locate both of these at locations in memory, by declaring a function to contain then, and using #ORG to specify where this is to be located. 'label_address' can then be used to find where the actual data table is located. In this case, the pointer table will be near the start of the ORG range, and the data table at the end.
The one that locates a value at a specified location without any control program, is #ROM
So:
Code: |
#ROM int16 0x0800 = { 0x0002,
0x0091,0x007E,
0x02A6,0x02BD,
0x0052,0x0052,
0x0333,0x0333,
0x2082,0x0000,
0x0000,0x0000,
0x232B
}
|
Generates a table of 28bytes located at 0x800 in the ROM, with no control programs attached.
Best Wishes |
|
|
nurquhar
Joined: 05 Aug 2006 Posts: 149 Location: Redditch, UK
|
|
Posted: Sun Mar 10, 2013 6:57 am |
|
|
Yes, I can se how these suggestions might work but all gets a bit messey.
Using a function wrapper around the data with a label means the scope of the label is only within the function. Thus label_address would have to be used only in that function. So to get the address you would have to pick it up at run-time by executing the function.
Having had a little try at the wrapper idea I am not sure it works.
Code: | #org 0x9000,0x9FFF
void GetElement(element *e, int8 n)
{
adr_table_e:
// The Elements
rom element table_e[] = {
// Hr,Mn 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
{12,0, 1,0,0,0,0,0,0,0}, // 0
{12,30, 1,1,1,0,0,0,0,0}, // 1
{12,45, 1,1,1,1,0,0,0,0}, // 2
{13,0, 0,0,0,0,0,1,0,0}, // 3
{13,30, 1,1,1,1,1,1,0,0} // 4
} ;
int32 adr ;
//adr = &table_e + (n * sizeof(element)) ;
adr = label_address(adr_table_e) ;
printf(termPutc, "Read %d @ %lx\r\n", n, adr) ;
adr += (n * sizeof(element)) ;
printf(termPutc, "Read %d @ %lx\r\n", n, adr) ;
read_program_memory(adr, e, sizeof(element)) ;
} |
Still puts data at top of memory :
Code: | ROM data:
01FFCE: 2A 01 02 55 03 04
01FFD4: 0C 00 01 00 00 00 00 0C 1E 07 00 00 00 00 0C 2D
01FFE4: 0F 00 00 00 00 0D 00 20 00 00 00 00 0D 1E 3F 00
01FFF4: 00 00 00
|
Using #ROM means sacrificying the readability of the structure assignment to a list of hex bytes. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Sun Mar 10, 2013 9:08 am |
|
|
Note how I'm telling the compiler to place an array of int16 values.
You need to add 'default' to the #org declaration.
Remember rom declarations are are in the rom, so inherently static. Their scope is universal. You just need to copy the label address return value into a global variable.
Best Wishes |
|
|
nurquhar
Joined: 05 Aug 2006 Posts: 149 Location: Redditch, UK
|
|
Posted: Sun Mar 10, 2013 9:42 am |
|
|
I don't see how putting the 'rom' data declartion inside a function realy helps any. As even if the function is #org'ed to a fixed memory address the compiler puts the function at the #org address ok but it still puts the data where it likes at the top of memory.
Using #ROM with a list of words will work as you suggest but makes the code much less readable as compared to the struct assignement syntax.
It just seems odd that 'const' can be controlled with #org and 'rom' can't. Seems like a usefull feature to me if CCS are listening. |
|
|
nurquhar
Joined: 05 Aug 2006 Posts: 149 Location: Redditch, UK
|
|
Posted: Sun Mar 10, 2013 10:34 am |
|
|
Well it could be I mis-understood something. I just went back to trying 'const' again and I don't see any code before the program data for the structure access.
That is :
Code: | #define OUTPUTS 36
// Each element of route
typedef struct {
int8 hour ; // Start Time, hour
int8 min ; // Start Time, min
int1 path[OUTPUTS] ; // Path of points
} element ;
// Time table
typedef struct {
int1 days[7] ; // Valid days of week 0=Sun,1=Mon ...
int8 beg ; // First element
int8 end ; // Last element
} table ;
#org 0x1000, 0x10FF default
// The Elements
const element table_e[] = {
// Hr,Mn 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
{11,0, 1,0,0,0,0,0,0,0}, // 0
{11,30, 1,1,1,0,0,0,0,0}, // 1
{11,45, 1,1,1,1,0,0,0,0}, // 2
{13,0, 0,0,0,0,0,1,0,0}, // 3
{13,30, 1,1,1,1,1,1,0,0} // 4
} ;
// The timetable
const table table_t[] = {
// S,M,T,W,T,F,S b, e
{0,1,0,1,0,1,0, 0, 2},
{1,0,1,0,1,0,1, 3, 4}
} ;
#org default |
Now put this into memory :
Code: | Line Address Opcode Label Disassembly
2045 00FF8 D9D6 usb_init_cs RCALL usb_detach
2046 00FFA EF19 GOTO 0x1432
2047 00FFC F00A NOP
2048 00FFE FFFF NOP
2049 01000 000B @const1117 TBLRD+*
2050 01002 0001
2051 01004 0000 NOP
2052 01006 0B00 ANDLW 0
2053 01008 071E DECF 0x1e, F, BANKED
2054 0100A 0000 NOP
2055 0100C 0000 NOP
2056 0100E 2D0B DECFSZ 0xb, W, BANKED
2057 01010 000F TBLWT+*
2058 01012 0000 NOP
2059 01014 0D00 MULLW 0
2060 01016 2000 ADDWFC 0, W, ACCESS
2061 01018 0000 NOP
2062 0101A 0000 NOP
2063 0101C 1E0D COMF 0xd, F, ACCESS
2064 0101E 003F
2065 01020 0000 NOP
2066 01022 0000 NOP
2067 01024 002A @const1119
2068 01026 5502 SUBFWB 0x2, W, BANKED
2069 01028 0403 DECF 0x3, W, ACCESS
2070 0102A FFFF NOP
2071 0102C FFFF NOP
2072 0102E FFFF NOP
2073 01030 FFFF NOP |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Mon Mar 11, 2013 2:43 am |
|
|
Lets start with. Second line of your first post:
"However since const puts some extra code in front of the data you can't then use a pointer to the memory address to access it".
Key here is that what extra code you get, depends on the processor involved.
The processor is always generating extra code (rom, or const), but will put it in different locations, depending on processor, and what access you actually do.
Now rom is special. With rom, the compiler generates a 'pointer table', which is stored instead of the actual data in the code, and then the data itself is then stored at the top of the available data range. If you use 'default' with a ORG statement, this sets the available data range. The pointer table, can then be used to generate pointer accesses to the data. This then allows a rom data construct to be put at a known location.
However I have to ask if you really 'need' pointer access?. You can always use address access. Here if a table is at a known location, the read_program_memory function will allow you to access it. Not quite as simple as just using *, but with a couple of macros, this can be made almost as easy.
It is vital to understand, that you can't do 'traditional' pointer access to data in the ROM. This has been described dozens (hundreds) of times before, and is down to the fact that the ROM is not part of the same data space as the RAM on a PIC. So you can't take an address like 0x100, and say fred=*(0x100), and access the ROM. This will access address 100, but in the RAM instead. There is no single instruction fetching of ROM data, instead, you have to setup a table read, to access the ROM area. This is a fundamental difference about the PIC. Now CCS allows this to be hidden, using the rom data construct, automatically generating flags to mark the addresses as 'ROM', but even with this done, you can't then access the table using simple pointers, the compiler at all times has to 'know' that you are using pointers to ROM.
Best Wishes |
|
|
|
|
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
|