We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
How can one locate a table of constants at a certain address in C ?
So that leaves the Linker, then. BTW: Why do these constants need to be at a particular address?
Well, let us suppose we have a measurement system and these constants represent calibration coefficients. Any time the sensors are calibrated, we have to redefine the table of coefficients. To redefine the coefficients, we must know where they are are located in program memory ( I mean flash memory, of course).
Well, Andrew Neil asked a good question - why do you need with fixed address? For simple example, you have 4 tables of coefficients, each one contains 8 bytes. So then do something like (put your values here):
unsigned char code tables[4][8] = { {1,2,3,4,5,6,7,8}, {11,12,13,14,15,16,17,18}, {31,32,33,34,35,36,37,38}, {71,72,73,74,75,76,77,78}, };
unsigned char *current_table; switch (redefine_condition) { case condition_1: current_table=tables[0]; break; case condition_2: current_table=tables[1]; break; case condition_3: current_table=tables[2]; break; case condition_4: current_table=tables[3]; break; }
"To redefine the coefficients, we must know where they are are located in program memory" But why does it need to be fixed? The compiler can find the address of any object at run-time by using the '&' address-of operator!
To redefine the coefficients, we must know where they are are located in program memory Do you mean without modifying the source file and building the project and re-flashing the entire program to memory? Jon
>But why does it need to be fixed? I want to rewrite the table of coefficients with the help of bootloading software. I set my chip in 'BIOS' mode, perform the necessary operations and then reactivate my program. In 'BIOS' mode my chip doesn't 'know' where the coefficients are located. In this mode it can only perform generic read/write operations. So I must provide the fixed address.
Okay, if you always know about values of fixed addresses then you may use direct addressing in your program. For example, coefficients' tables are always placed at addresses 0x1234, 0x2345, 0x3456 and 0x4567. Then for redefinition, just use: current_table = 0x2345 etc. Good days!
"Do you mean without modifying the source file and building the project and re-flashing the entire program to memory?" Jon, Imagine this scenario: The product reads data from various sensors which have to be individually calibrated in isolation from the product. Production need to be able to combine the calibration coefficients (generated by some 3rd party utility) with the hex file output by Keil before programming the 8051 code space. For ease of development you want to have a default set of coefficients present in the source code. The only reasonable way to achieve the above is to separate all these coefficients out into a single source file, select "Keep variables in order" and link this at the appropriate address. Oh, and watch out that you don't have any uninitialised constants in that file as "Keep variables in order" is ignored for them. Before you ask why I use uninitialised constants: they act as padding in some situations. I wouldn't need them if I could locate and initialise with the _at_ keyword. Another problem with the above approach is that the linker will allow you to link the resulting object code outwith the code space defined in the project options without giving a warning. How nice it would be to be able to use the _at_ keyword to declare and initialise code space constants at a place in the source code which is appropriate to the structure of the program? This question comes up again and again and again - when are you guys going to implement this? Stefan
The problem arises from your try to use the compiler to do things that are not a compiler's job. Arguably, the error is that the _at_ keyword even exists, not the way it's implemented. The project you outline can be handled with next to no hassle, without hardwiring any addresses or the _at_ keyword. Here's how: 1) Compile the project straightforwardly, let the linker decide wherever it wants to place those constants. 2) Look into the map file to find the addresses the linker placed the relevant objects. 3) Let the 3rd-party tool generate a raw binary file for the replacement data. 4) Using the address from step 2) and the file from step 3), create a correctly addressed hex file 5) merge that with your application .hex file 6) burn.
"The problem arises from your try to use the compiler to do things that are not a compiler's job. Arguably, the error is that the _at_ keyword even exists, not the way it's implemented." Well, I disagree with this. The Keil compiler is intended to address a specific problem - programming embedded systems. Extensions such as the _at_ keyword are very useful and appropriate in this environment. Unfortunately your solution is too restrictive - every time the code is modified the linker will probably place the constants at a different address. I would have to modify the utility that merges the constants with the code to read the .map file for each build, I would have to issue the .map file along with each build etc etc, and the possibility of error increases with each step. Stefan
"...and the possibility of error increases with each step." Of course my ever-unpopular response (you've heard it all before) is to incorporate software tools (sed, awk, perl, etc.) to automate your build process.
Production need to be able to combine the calibration coefficients (generated by some 3rd party utility) with the hex file output by Keil before programming the 8051 code space. For ease of development you want to have a default set of coefficients present in the source code. Are you saying that the third party utility generates a HEX file? That's what "Production need to be able to combine the calibration coefficients (generated by some 3rd party utility) with the hex file output" sounds like to me. If that's right, then one can assume that the calibration data is stored in ROM (CODE space). And, merging the calibration data with the HEX file really means replacing the calibration data from the C program with the calibration data from the 3rd party utility. So, if that's the case, why can't you just have a HEX file with default calibration data that gets merged in by default? The only reasonable way to achieve the above is to separate all these coefficients out into a single source file, select "Keep variables in order" and link this at the appropriate address. I don't know that that's the ONLY reasonable way to do it. Off the top of my head I could see using an assembly file to do that. With more details about what the ultimate goal is, I can probably dream up more ways than that. I've got numerous products in the field that have default and calibrated configuration data and I didn't have to jump through hoops to get it to work. ...the linker will allow you to link the resulting object code outwith the code space defined in the project options without giving a warning. I'm not sure what you mean here. How nice it would be to be able to use the _at_ keyword to declare and initialise code space constants at a place in the source code which is appropriate to the structure of the program? This question comes up again and again and again - when are you guys going to implement this? As I've said before, this modification would require changes to the object code generated (new record types would have to be added because this is not supported in the Intel OMF51 specification). Adding new record types would require that we contact every emulator and other third party vendor that uses the OMF51 object module specification. That's about 100 vendors or so. When we have made changes in the past, it typically took 3-5 years for other vendors to catch-up and implement support for these new record types. Needeless to say, when we add that feature (yes, it is on the list of features to add) we will likely be plagued by developers who can't use it with their existing tools. That means they'll need to upgrade all of those tools. And, that just makes Keil look like the bad guy. Jon
All this sounds like a discussion on comp.lang.c.moderated this Saturday when a poster asks: "how does one align a static struct to a 4kb boundry? [sic]" We get two radically different answers from two renowned C experts: Dan Pop replies "In standard C, one doesn't." Jack Klein says "One doesn't, in standard C." I had to utter a little chuckle. Of course, help was provided on how to do it with the proper elements in a typical toolchain (e.g., assembler, linker, and yes the compiler too -- but with #pragma). In fact, I've got a PowerPC compiler here that has a pragma for specifying special alignment. Now back to the request of extending the _at_ extension specifically, Jon says "yes, it is on the list of features to add". Well, kudos to Keil for listening to their customers, but I also have to give kudos to all those customers who solve these kinds of problems day in and day out without the need for language extensions or extended language extensions. At least we won't have this to talk about any longer. Jon, I have to wonder if this OMF extension could be switched on at the command lines of the compiler and linker, so that for the vast majority of users not requiring the _at_-initializer feature, it would be "transparent".
Extensions such as the _at_ keyword are very useful and appropriate in this environment. Just because a feature is useful doesn't mean it's a good idea to add it. All the more so if the feature isn't strictly necessary to achieve the goal. The same functionality you get with the rather limited _at_ feature can be had completely without it. You would put the relevant objects into named sections of their own, and then tell the linker that those sections are to be placed at certain absolute addresses. Done. With that in mind, _at_ is really just syntactic sugar, and, as Jon pointed out in his reply, it's actually not all that sweet sugar, either. Another thing to keep in mind is that if you insist on a fixed address for your configuration data, that means you put an unmovable obstacle somewhere inside the code memory range. This will result usually in a hole in code space usage, i.e. waste of precious resources --- something I would have guessed would bother you considerably.
Jon, I have to wonder if this OMF extension could be switched on at the command lines of the compiler and linker, so that for the vast majority of users not requiring the _at_-initializer feature, it would be "transparent". Yes, but do we really need to add another command-line directive and checkbox in uVision? Jon
"Yes, but do we really need to add another command-line directive and checkbox in uVision?" The alternative being what -- always generating the new OMF51+ format only? Or is it that the command-line (and checkbox) is an idiotic way to support old and new OMF51 formats? Sorry, I was merely making a suggestion for how to keep developers and tool vendors happy during the 3-5 year catch-up period and not "look like the bad guy". I did not necessarily intend to say "you must use a command line switch", but rather to suggest keeping support for the standard OMF51 format by default so nobody's tools break until they absolutely must have this _at_-initializer thing. By the way, if you need an example of what an embedded customer/developer is willing to tolerate as far as the number of command-line options, take a look at gcc! :-) http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Option-Summary.html#Option%20Summary