This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

variable

How to declare and assign variables in ROM to an specific address

Parents
  • I want it too! It would be useful to reserve a place for a CRC/checksum value or for placing configuration data at the prom programming stage independently of the compilation.

    It would seem that many users want the feature and that we all imagine that it cannot really be all that difficult to implement.

    However, the most annoying thing is that that Keil does not seem to be listening. So, the key questions are:

    Is the demand real?
    Is it really difficult to implement?

    I think we should be told.

Reply
  • I want it too! It would be useful to reserve a place for a CRC/checksum value or for placing configuration data at the prom programming stage independently of the compilation.

    It would seem that many users want the feature and that we all imagine that it cannot really be all that difficult to implement.

    However, the most annoying thing is that that Keil does not seem to be listening. So, the key questions are:

    Is the demand real?
    Is it really difficult to implement?

    I think we should be told.

Children
  • "It would seem that many users want the feature"

    I know; I raised that very point on this forum a while ago:
    http://www.keil.com/forum/docs/thread1163.asp

    And again here:
    http://www.keil.com/forum/docs/thread856.asp

    "and that we all imagine that it cannot really be all that difficult to implement."

    I believe that the Raisonance compiler does it already - so why can't Keil!?

    "However, the most annoying thing is that that Keil does not seem to be listening."

    Yes, that is very annoying.

    "Is the demand real?"

    I think we've already answered that one!

    At the very least, as I've said before, the workaround should be properly documented in the manual - not hidden away in some App Note or Knowledgebase article.

  • Keil already has this feature in the '167 toolset. The command line 'ASSIGN' function to the linker creates a public symbol with a numeric value which can be used to fill an unresolved symbol. Maybe the problem is that nobody uses the '51 (just joking).
    Best luck

  • LX51 (but not BL51) has this option but, from the description in the manual, I don't think it's quite what this question is after: it assigns an address to an unresolved symbol.

    The question, if I understand correctly, wants to assign a specific value and a specific address to a symbol?

    Standard 'C' initialisation can do the value, and Keil's _at_ extension can do the address, but C51 - for some unknown reason - won't let you use the two together :-(

    We await a reply from Keil to tell us why this is so...
    (as Graham noted, we've been waiting some time...)

  • Is the demand real? Is it really difficult to implement?

    Yep. The demand for this is obviously real. And, Yep, it's also going to be difficult to implement.

    It is on the list of feature that we will add, however, there are lots of features on this list and many of them have no work-arounds. Needless to say, we fix or implement those first.

    Since there are numerous ways to use fixed addresses for checksums, CRCs, configuration data, MCU reset configurations, and so on WITHOUT locating an initialized variable, it is not considered a critical situation.

    Let me elaborate...

    Checksum/CRC

    Does the C program REALLY need to assign the value of the CRC or checksum as shown in the following code?

    unsigned int code my_programs_crc = 0x1234 _at_ 0xFFFF;
    

    I don't even think so. The checksum or CRC is best done by an external utility that calculates it based on the contents of the HEX file or BINARY ROM image. The value can be stuffed into the HEX or BINARY file and when that's done the following works just fine.

    unsigned int code my_programs_crc _at_ 0xFFFF;
    

    The following knowledgebase article gives a little more information on using checksums.

    http://www.keil.com/support/docs/494.htm

    FYI, I've never used a variable in my program to hold the checksum or CRC. I always force the checksum or CRC to come out to a fixed value (like the binary representation of my initials). I calculate the CRC/checksum for the whole ROM and the result better be 0x4A57 (JW). I use the last 2 bytes of the ROM for my offset value. Then tell the linker that the rom is 0xFFFD bytes long (instead of 0x10000). Of course, I calculate the checksum over the whole ROM.


    Configuration Data

    Why should configuration data should be pre-initialized? Suppose you have configuration data defined as follows:

    struct config_st
      {
      unsigned int hi;
      unsigned int lo;
      unsigned int span;
      unsigned int hi_limit;
      unsigned int lo_limit;
      unsigned char warm_start_flag;
      };
    
    xdata struct config_st my_config_data =
      {
        20, 4, 16, 18, 7
      } _at_ 0x1000;
    

    The configuration data gets initialized EVERY TIME the program runs (i.e. on every reset). Is that REALLY what you want to happen? If there is a way to CHANGE the configuration data dynamically, wouldn't the following be better?

    struct config_st
      {
      unsigned int hi;
      unsigned int lo;
      unsigned int span;
      unsigned int hi_limit;
      unsigned int lo_limit;
      unsigned int warm_start_flag;
      };
    
    xdata struct config_st my_config_data _at_ 0x1000;
    
    code struct config_st reset_config_data = { 20, 4, 16, 18, 7, ~0xDEAD };
    
    .
    .
    .
    if (my_config_data.warm_start_flag != ~0xDEAD)
      {
      // Config Data is Trash -- Cold Start
      my_config_data = reset_config_data;
      }
    else
      {
      // Config Data is OK
      }
    


    MCU Configuration

    Sometimes it would be nice to initialize a specific memory address from C for microcontrollers that have memory-mapped (CODE) configuration registers. For all of these devices, we have implemented special startup code (because in many cases just setting some value in ROM is not all that is required).


    Conclusions?

    Ii is very rare to see an application that absolutely requires initialized data at a specific address. Typically, someone wants to be able to look at an address in the ROM to see what the configuration parameters are set to or something like that. In that case, my suggestion is to put the data in a struct and locate it using the linker.

    That's the one case where I agree that initializing and locating at the same time would be a convenient feature.

    Jon

  • Jon,
    You should be considering how best the problem can be solved instead of trying to catalog all the possible situations in which it occurs. My issue is that my system stores code in flash memory, and I reserve a sector for configuration storage there, too. I'd like to burn the default configuration into flash before pc assembly. That saves an operation in manufacturing.

    My solution is not elegant, but it DOES work. My project includes an assembly language STARTUP file instead of letting the compiler generate start up. Within that file, I am free to locate and initialize a section of code memory. The name can be declared PUBLIC. For example,

    CSEG AT 0xc000
    PUBLIC config
    config:
    DB 0, 5, 0x55,...

    Over on the C side, I just declare

    extern code data_type config;

    No need to redeclare the address. The linker already knows its location.

    There are two obvious problems with this solution.
    * First, you MUST include an assembly language file in the build. Most of us would like to avoid that because it is non-portable.
    * Second, it's a maintenance nightmare. If the data struct is very complicated, it is SO easy to get off by one byte. Then it could take forever to get back on track.

    No doubt, it would be sweeter to write the whole thing in C, but depending on your desperation factor, you might stoop to my level.

    Jeff.

  • Jeff, my comments are not necessarily directed to you specifically. You just drew them out of me.

    Reordering quotations...

    "No doubt, it would be sweeter to write the whole thing in C, but depending on your desperation factor, you might stoop to my level."

    Well Jeff, I would contend that your level is just fine.

    "There are two obvious problems with this solution.
    * First, you MUST include an assembly language file in the build. Most of us would like to avoid that because it is non-portable."


    Maybe most of you would like to avoid assembly language because you don't know/like/whatever assembly language, but what is the "portable" way to do it? Certainly using an enhancement to a non-portable C language extension does not suddenly make it portable. If anything, the way you are doing it would be more familiar to those who have solved the same problem on other platforms, since it is the "conventional" way of going about it.

    "* Second, it's a maintenance nightmare. If the data struct is very complicated, it is SO easy to get off by one byte. Then it could take forever to get back on track."

    [rant]
    If a configuration data structure is complex enough to be even remotely considered a maintenance nightmare, you should be using other tools to generate it anyway. Folks should take their blinders off and expand their software tools use beyond just the assembler, compiler, linker. Software tools that were created by software developers for software developers, have been around a long time. In these cases of complex configuration data structures (especially if they change from time to time), consider expressing the configuration in form easy and familiar to the configurer, and use Perl, awk, etc. to programmatically generate an assembly source file from the configuration file as one step in your build process.
    [/rant]

    Sigh. I'm going to go off and reread Jon Bentley's "Programming Pearls" and "More Programming Pearls" for my mental health ;-)

  • Sorry, I just have to share this because it is so relevant.

    Just to illustrate the "maintenance nightmare" issue using an example, and this is literally an issue I was asked to help with today coincidentally...

    A client of mine who will remain nameless, is a "device" manufacturer. Their high-end parts are big and complex, having embedded CPU(s) and BGA packages with pin (ball) counts as high as 1704. The databook for this device is around 2000 pages. The databook contains pinout tables for 256, 456, 672, 676, 896, 1148, 1152, 1517, 1696, and 1704 pins (some pins missing in an otherwise regular "row" by "column" pin array). Some poor documentation fellow has to take the "source" package/pinout text documents output early in the IC design and packaging engineering process and verify BY HAND/EYEBALL that the PDF databook pinout tables match. For the big packages, these tables are upwards of 48 pages! Well guess what? A pin got dropped somewhere along the way in the databook creation process and a customer caught it. Oops. There you go. Now that's and error-prone maintenance nightmare! The documentation fellow has a remarkable attention to detail and ability to focus, but he's only human after all. He also gets to recheck all the other tables to verify that nothing has changed if there's an edit performed to another table.

    So what we do is use those marvelous text processing software tools my forefathers created for me, write a surprisingly simple script (program) to parse out the pins from the the engineering source document and the PDF (or from old PDF and new PDF), process one against the other looking for inconsistencies, and BAM! that poor fellow's hair starts growing back in.

    The moral of the story is that there is usually a way to make a complex problem simpler using the right tools. Since you are not likely to be the first one to encounter your complex problem or something very similar to it, there's a good chance that a tool exists to help you.