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 support@ccsinfo.com

ROMable Structure Use

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



Joined: 04 May 2015
Posts: 2

View user's profile Send private message

ROMable Structure Use
PostPosted: Mon May 04, 2015 9:54 am     Reply with quote

I have a structure:
Code:

typedef struct __attribute__((packed))
{
    byte yVersion;
    byte yFWMonth;             
    byte yFWDay;             
    byte yFWYear;         
} Info;

I declare a static const instance
Code:

static ICNInfo const sm_info = { VERSION_NUMBER, VERSION_MONTH, VERSION_DAY, VERSION_YEAR };

I try to use it in code:
Code:

memcpy(&sm_rx_buf[3], &info, sizeof(Info));

This gives a compiler error:
*** Error 28 "xxx.c" Line 533(28,35): Expecting an identifier

This is valid C code. I want to put this structure in ROM since it never changes. If I change the declaration to an array of size 1, remove the reference in the memcpy, error goes away. Does anybody know if CCS can’t handle structures like this without being an array? I've looked at other similar examples here on the forum but they tend to be arrays. Am I missing something fundamental here? THANKS!
Ttelmah



Joined: 11 Mar 2010
Posts: 19369

View user's profile Send private message

PostPosted: Mon May 04, 2015 11:40 am     Reply with quote

This goes back to a key understanding of the PIC.

The PIC has Harvard architecture. In this, the ROM, and RAM, are different memory spaces. You cannot directly access ROM with a simple read, the processor has to do a table read or a (on older PIC's), it is not even possible!... Memcpy, _only copies RAM_. Accessing ROM needs different instructions. From the manual: "Copies n bytes from source to destination in RAM".

Then you don't show info being declared.

Then 'comment' static is pointless. A const is _constant_.

Code:

typedef struct __attribute__((packed))
{
    byte yVersion;
    byte yFWMonth;             
    byte yFWDay;             
    byte yFWYear;         
} Info_type; //keep type names distinct.

Info_type const sm_info = { VERSION_NUMBER, VERSION_MONTH, VERSION_DAY, VERSION_YEAR };

//then in the actual code.
   Info_type info;

   info=sm_info; //just copy it.
mswilk67



Joined: 04 May 2015
Posts: 2

View user's profile Send private message

PostPosted: Mon May 04, 2015 12:03 pm     Reply with quote

Thanks, much appreciated. I am used to developing on 16 and 32 bit processors where ROMable (CODE space) data is (generally) directly accessible. I am obviously new to using the PIC and the CCS compiler. As you indicated, on the PIC it's a separate memory space. That's all fine and good except that with the CCS compiler, I see so many things it does for you, I figured it would also be smart enough to do this behind the scenes like it does in so many other places. I take it it needs to be declared this way as a hint to the compiler...?

You made a comment that I appreciate about static declaration with const being pointless. You are correct since the CCS compiler puts everything in a single compilation unit. I declared as static out of practice to give it module scope. This is from a long history of OO programming practices. If there's a side effect of doing this, I would love to know.
Ttelmah



Joined: 11 Mar 2010
Posts: 19369

View user's profile Send private message

PostPosted: Mon May 04, 2015 2:09 pm     Reply with quote

Some more comments then... Smile

First, 'const' in most compilers is a way of signalling that a RAM based variable should not be changed. On chips with actual memory management systems, and generally no way for the code to actually write to rom, this makes sense.
With CCS you actually have lots of ways of dealing with the ROM, each with different meanings:

1) #ROM. This places a value at a physical ROM address, as a table in memory.
2) const. This generates a value stored directly in ROM with the code added to allow it to be directly read as a standard variable. _But_ you cannot construct a memory address of this value directly. &x won't work. Instead you have to use the 'label_address' instruction to find where in the ROM the actual data is.
3) rom. Used just like 'const', but allows for the automatic construction of it's memory address, and the addition of the code.

The reason for '2' is historic. CCS's use of 'const' as a way of storing things in ROM, pre-dates ANSI. It was introduced on the early PIC's which had no way to directly access the ROM, and the code to allow the access was included as part of the data stored in ROM. The address returned by &, points to this code, rather than the actual data. '3' was introduced for later chips that didn't need this.

You can declare a variable as rom, and directly copy it, using read_program_memory, so:

Code:

typedef struct __attribute__((packed))
{
    byte yVersion;
    byte yFWMonth;             
    byte yFWDay;             
    byte yFWYear;         
} Info_type; //keep type names distinct.

Info_type rom sm_info = { VERSION_NUMBER, VERSION_MONTH, VERSION_DAY, VERSION_YEAR };

   //then in the actual code.
   Info_type info;

   read_program_memory(&sm_info,&info,sizeof(info));

But there is a big caveat. This copies the declared block of memory. Problem is that the actual value stored in ROM may not be this size.

If you look at the PIC24/30 chips, their ROM memory space is organised at a 32bit wide memory space with only 24bits present in each word. So using the copy, you would receive the first three bytes of the rom variable, and then an empty (0xFF) byte. The next byte is actually stored in the next word....

Similarly on the PIC16's, their memory is 16bit wide, with only 14bits present.

This if the big advantage of just copying the variable as already shown. The compiler then 'knows' the difference between ROM size, and RAM size, and automatically handles the different sizes.

99% of processors use the Von Neumann architecture instead. Single linear address space with both ROM and RAM, and the same instructions can read both, and both are the same width. The advantage of the Harvard architecture is that with separate spaces, separate access lines can be used, so the processor can talk simultaneously to both memory spaces in the same instruction. Gives high speed without the cost of needing cache, but makes it unsuitable for a general processor since you'd then need so many address and data lines. However for a single chip microcontroller it is useful, provided you understand the limitations it brings.....
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