[Fwd: Re: [avr-gcc-list] Allocating variables to a fixed address]
Robert, Could you please forward this to the list? My posts are still being blocked. The one below was sent only to the list, but it's not there on http://lists.gnu.org/pipermail/avr-gcc-list . Thanks, Erik On Mon, May 11, 2009 at 10:30:40PM +1000, Erik Christiansen wrote: On Mon, May 11, 2009 at 02:13:41PM +0200, Jan Waclawek wrote: Robert, There is some difference, though: you can't count on such variables to be initialised to zero. Unless you add a custom initialisation loop to crt0, or similar. ;-) Erik OK Erik, forwarded. Robert ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
[Fwd: Re: [Re: [avr-gcc-list] Allocating variables to a fixed address]]
On Wed, May 13, 2009 at 01:16:31PM +0200, Robert von Knobloch wrote: Curiously I could not use e.g. asm (test_pgm_read_byte:jmp pgm_read_byte); undefined reference to 'pgm_read_byte' although it is defined and in scope. Where pgm_read_byte is a library function from avr-libc. I had to supply a stub function of my own [flash_read_byte()] to, in turn, call pgm_read_byte() and then it was happy :-) Did you have a .global pgm_read_byte in your assembler code?;-) That is needed to make the symbol public across compile units, and I can't see it in your example. Could you please forward this to the list also, because I'm still not able to post. mfG, Erik OK Erik -forwarded. No, I didn't - but now fixed. Thanks, Robert ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
[Re: [avr-gcc-list] Allocating variables to a fixed address]
Stu Bell wrote: If I had your problem, this is how I would solve it: Define a real table of function pointers instead of trying to get the linker to create one for you. typedef void (*TestProc) (void*); NOINLINE void test_lcd_2(void* pStr) {PGM_P string = (PGM_P) pStr; prog_lcd_string2(string); } NOINLINE void test_lcd_string(void* pStr) { PGM_P string = (PGM_P) pStr; prog_lcd_string(string); } NOINLINE void test_clearlcd2(void* ign) { clearlcd2(); } NOINLINE void test_lcd_hex4out(void* pByte) { uint8_t byte = * (uint8_t*) pByte; return lcd_hex4out(byte); } ... const TestProc* TestTable[TEST_VECTORS] FUNCTION_SECTION = { test_lcd_2, test_lcd_string, ... }; You will need to modify your calls to either send the pointer to the argument (this forces all calls to have a single parameter of, essentially, a word) or to always send a word. In either case, the receiving routine will then cast the argument to the proper value before passing it on. Do not place the routines or other constants in the same linker section as the function table. If you leave the table in a section of its own, it will always be placed at the head of the section without interference from anything else. Calling the function requires you to pull the function out of the table before calling it: #define TESTPROC_LCD_2 0 #define TESTPROC_LCD_STRING 1 . . . uint16_t test_proc; test_proc = pgm_read_word( (uint16_t) TestTable[ TESTPROC_LCD_2 ] ); *(TestProc*)test_proc( myarg ); . . . You could probably enclose the above stuff in a macro to make your code far more readable: #define CallTestProc(proc,arg) \ do {\ uint16_t test_proc;\ test_proc = pgm_read_word( (uint16_t) TestTable[ (proc) ] ); \ *(TestProc*)test_proc( (arg) ); \ } while (0); . . . CallTestProc( TESTPROC_LCD_2, myarg ); That's my inspiration for the day. It's probably wrong somewhere, but it's how I would approach the problem. Hi Stu, This solution, while a purer 'C' solution would require me to have all my 'internal' functions with similar call/return requirements. This is not, and cannot be, the case. I fear that the magig 'array of function pointers' has only limited use and is unsuitable here. But many thanks for your thoughts, every comment here makes me re-think the problem, which is good. Cheers, Robert ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
[Re: [avr-gcc-list] Allocating variables to a fixed address]
Thanks to all who have helped me to get the best solution. I have eventually decided that an assembler jump table was really the best in my application: /* ** * Function entry points for independent test routines ** */ // Function declarations void test_lcd_2(PGM_P); void test_lcd_string(PGM_P); . . //Snip/ . void test_flash_read(uint16_t); void test_flash_write(uint8_t, uint8_t); void jumptable(void) __attribute__((__naked__)); FUNCTION_SECTION void jumptable(void) { asm (test_lcd_2:jmp prog_lcd_string2); asm (test_lcd_string:jmp prog_lcd_string); . . //Snip/av . asm (test_pgm_read_byte:jmp flash_read_byte); asm (test_pgm_read_word:jmp flash_read_word); } == Curiously I could not use e.g. asm (test_pgm_read_byte:jmp pgm_read_byte); undefined reference to 'pgm_read_byte' although it is defined and in scope. Where pgm_read_byte is a library function from avr-libc. I had to supply a stub function of my own [flash_read_byte()] to, in turn, call pgm_read_byte() and then it was happy :-) Thanks to all, Robert. ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: [Re: [avr-gcc-list] Allocating variables to a fixed address]
Robert von Knobloch wrote: Curiously I could not use e.g. asm (test_pgm_read_byte:jmp pgm_read_byte); undefined reference to 'pgm_read_byte' although it is defined and in scope. Where pgm_read_byte is a library function from avr-libc. I think this is because pgm_read_byte() is a macro. Now another mechanism could have been setup: using an external interrupt pin to generate a software interrupt, and using that software interrupt to perform calls to functions in a PC BIOS way: in that case the caller need not to know the location of the called functions, the interrupt driver compiled and linked with the main application uses its own jump table which is not exposed to external modules. However the API setup is more complex since you have to pass the 'function id' of the called functions in some register before generating the software interrupt. ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: [avr-gcc-list] Allocating variables to a fixed address
David Kelly wrote: On Mon, May 11, 2009 at 08:21:37AM -0600, Weddington, Eric wrote: Sounds to me as if you are making the bootloader too big and should simply link an entire application for every possible target. What you are doing would make more sense if the loadable modules could run out of RAM. That would be no use, the loadables must be non-volatile. This is a tester that will be sent to a factory (somewhere). When a new product is to be tested, I can e-mail them the test routine which they then burn into flash (each of these is 0x900 bytes, there can be up to 0x0a of them). Why is this method superior to having a regular bootloader, and you have N applications, where each application is the individual test routine and the common portion? Why do you have create this custom interface which has its own set of problems? Alternatively, creating a custom Makefile to handle building 10 different applications is certainly easier in comparison. I agree, thats how I would handle it. Either build a custom linked application for each customer or provide the customer with the tools to build one of their own. What he is trying to do is in effect create a run time program linker. Eric, David etc., Thanks for the suggestions but it seems I haven't explained the problem properly. The end users of this equipment will be factory operators who cannot compile, link or do any of these software things. Thus I have developed an extremely simple (read idiot-proof [i hope]) interface to use with a terminal program (minicom, teraterm etc.). This is far more simple than any existing boot loader (OK, I *could* write my own, but I'm too far along now). The loadable elements are small (0x900) and will only ever be updated one at a time. If I compiled and linked the whole lot, then each small change would requite the sending loading of 64k of code, which I think is much too much for these people (and, for compatibilty with modern PCs, the comms. is run over a USB virtual RS-232 port which produces far too many serial errors for my liking - but that's another issue). I have the entire application written and am knocking the last bugs out now. I confess that GCC seems to me to be mostly something to fight with, perhaps I have been spoiled in the past using manufacturer's C compliers that were tailored especially for the target. I simply require a way to fix absolutely this jump table in memory. Whether I write it in C or assembler seems to me to be irrelevant, as is using an array of pointer to functions, because I still have the problem of fixing these at absolute addresses. If anyone knows a way to do this, I would very much appreciate it. Many thanks for all the input, Robert. ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: [avr-gcc-list] Allocating variables to a fixed address
Erik Christiansen wrote: I confess that GCC seems to me to be mostly something to fight with, perhaps I have been spoiled in the past using manufacturer's C compliers that were tailored especially for the target. It just requires leisure time for study and experimentation. ;-) I simply require a way to fix absolutely this jump table in memory. Whether I write it in C or assembler seems to me to be irrelevant, as is using an array of pointer to functions, because I still have the problem of fixing these at absolute addresses. If anyone knows a way to do this, I would very much appreciate it. Robert, if the table is made __attribute__ ((section(.table))) , and section .table is linked in after the vectors, but prior to any code, then its location will be fixed, won't it? In the old linker script I have to hand, that places it here:-. | .text : | {| __code_start = . ;| *(.vectors) / *(.table) ' __ctors_start = . ; *(.ctors) Having shipped firmware to similarly skill constrained recipients, I saw from the OP why you're doing it this way. Nor would I hesitate to do the same, as need (or convenience) arises. After all, how much does it differ from the fixed addresses of BIOS calls in CP/M, or its imitator, MS-DOS? The method seems particularly attractive where the operators would load combinations of modules, perhaps with multiples of some, without the need for you to build every combination. (Most painful where there could be hundreds of them.) mfG, Erik P.S. If this post doesn't appear on the list, would you mind forwarding it? For the last half year, none of my posts have gone through, AFAIR. Aha ! Yes Erik, this is exactly the way I think. In fact it's slightly more complex because I use the same download mechanism to load images that will be flashed into target products with embedded AVR processors. These are, of course, not native code for my host programmer. It is from this necessity that I devised the original method and extended it to the test routines. I am not exactly a young programmer and grew up with many operating systems and machines (Intel ISIS - Motorola Exorset, OS9 etc.). All of the used a similar approach as does indeed BIOS (to call MSDOS an imitator of CP/M insults CP/M IMHO but still..) My solution (non-working till now) is, in principle, the same as your suggestion except I chose a section originating at 0xff00 (after all the .text sections) which may not work well with GCC - it randomises the order of my 'vector table'. (Old experience with Motorola processors makes one tend toward the high address end, of course the AVR architecture is different here). Would you know why this won't happen if I relocate the table as you suggest - just because it would then be before any real code ? I have had another promising suggestion (off-list) that makes the main code write the addresses of its public functions to the eeprom, where the loadable code could find them and use as function pointers. I will try both and see how far I get. Have included your posting in my answer so that it gets on the list. Many thanks, Robert ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: [avr-gcc-list] Allocating variables to a fixed address
I simply require a way to fix absolutely this jump table in memory. Whether I write it in C or assembler seems to me to be irrelevant, as is using an array of pointer to functions, because I still have the problem of fixing these at absolute addresses. If anyone knows a way to do this, I would very much appreciate it. The attachment illustrates what I mean by jumptable in asm, and its usage (see main). Address of .mysection was fixed to 0x00FF by passing it to the linker through avr-gcc (-Wl,--section-start,.mysection=0xFF00). It of course can be a separate asm file, and the individual lines can be generated by a handy macro; but those are only unimportant details. Enjoy! ;-) JW ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
[Fwd: Re: [avr-gcc-list] Allocating variables to a fixed address]
Jan Waclawek wrote: I simply require a way to fix absolutely this jump table in memory. Whether I write it in C or assembler seems to me to be irrelevant, as is using an array of pointer to functions, because I still have the problem of fixing these at absolute addresses. If anyone knows a way to do this, I would very much appreciate it. The attachment illustrates what I mean by jumptable in asm, and its usage (see main). Address of .mysection was fixed to 0x00FF by passing it to the linker through avr-gcc (-Wl,--section-start,.mysection=0xFF00). It of course can be a separate asm file, and the individual lines can be generated by a handy macro; but those are only unimportant details. Enjoy! ;-) JW Thanks Jan, This is effectively what I have done, except I used C stubs instead of assembler: [.section origin is at 0xff00] void test_func_1(uint16_t foo) { func_1(foo); } void test_func_2(uint16_t foo) { func_2(foo); } Why would the compiler respect assembler any more than my C calls (it changes the order of them as they are stored in memory, so I cannot guarantee the address of test_func_1()) If GCC will respect the order of the assembler jumps (and thus the absolute address) then that is my easiest solution. At the moment I can't really see any difference between assembler and C here. Or does someone know better ? You see I really distrust the compiler now :-) Robert ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: Re: [avr-gcc-list] Allocating variables to a fixed address]
Robert von Knobloch wrote: Why would the compiler respect assembler any more than my C calls (it changes the order of them as they are stored in memory, so I cannot guarantee the address of test_func_1()) There is nothing in the C language that tells the compiler to preserve the ordering of global and static objects. GCC is perfectly within its rights to change the order of your functions. To preserve their relative order, you need to use function pointers and make them elements in a single array or structure which, if you avoid padding, will have the memory layout you expect. Or, use assembler, which the compiler won't mess with. Graham. ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: [Fwd: Re: [avr-gcc-list] Allocating variables to a fixed address]
Jan Waclawek wrote: Why would the compiler respect assembler any more than my C calls Because the compiler knows nothing on assembly language. It simply passes it as a string to the assembler: it does not attempt to parse it (except for the escape sequences), so it has no chance to modify the order of anything. On the other hand, a compiler is free to do whatever it wants to do with statements you pass to it: it can reorder and insert voids wherever and whenever it wants. This is the very principle of high level languages: you give up part of control in exchange of increase in convenience. If you want to re-gain control for whatever reason, the best thing to do is to revert to assembler. As I said, you can make this a standalone assembler source, if you feel more comfortable with it, and the link it together. The same thing can be done with variables, see attachment - this avoids the need to put all variables into a single struct (to ensure their fixed order); but I don't say this is the best way to do with variables. JW Jan, OK, sounds good, If GCC really will leave my assembler alone then that would be the best way to go. I am no longer so worried about the variables, although they were my original concern - I have written helper functions which make them transparent to the 'other side' and I think this is better practice. All I need now is the jump table... David, While it's good practice to design your protocol to handle errors, you shouldn't be seeing ANY errors wether or not the port is USB. I'd look to solving that problem. Are you sure that your baud rate is correct? Yes, quite sure. This is a known (to me) issue with FDDI USB to serial chips. If use a level converter and 'proper' RS-232 with the same setup I never ever get an error. The receive side uses a circular buffer with high low water marks and therefore can do 'proper' handshaking. It's just that i cannot rely on a modern (cheap) PC having a serial bus. The errors are only very occasionally, hardly an issue with my data volumes. They would become a problem if I started transferring large chunks. Tracking the FDDI down will have to wait. Many thanks for all your comments, they are really a big help, Robert ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: [Fwd: Re: [avr-gcc-list] Allocating variables to a fixed address]
Erik Christiansen wrote: On Tue, May 12, 2009 at 02:26:38PM +0200, Jan Waclawek wrote: On the other hand, a compiler is free to do whatever it wants to do with statements you pass to it: it can reorder and insert voids wherever and whenever it wants. This is the very principle of high level languages: you give up part of control in exchange of increase in convenience. If you want to re-gain control for whatever reason, the best thing to do is to revert to assembler. While I would, based on experience with gcc on various targets, have expected multiple functions from one compile unit to end up in .text in the same order as they appear in the source code, we can enforce the order if that doesn't happen. Just put each of the ten functions (there were 0x0a of them, IIRC) in a separate section, e.g. mit_gewalt_0 to mit_gewalt_9, using __attribute__ ((section(.xxx))) . Then in the linker script: /* Ok, it is the table which was to be */ .mit_gewalt_0 0xff00 : /* at 0xff00? Use another address to */ { .mit_gewalt_0 } text /* fix the location of the functions? */ .mit_gewalt_1 : AT ( ADDR(.mit_gewalt_0) + SIZEOF(.mit_gewalt_0) ) { .mit_gewalt_1 } text .mit_gewalt_2 : AT ( ADDR(.mit_gewalt_1) + SIZEOF(.mit_gewalt_1) ) { .mit_gewalt_2 } text etc. One caveat: It's a while since I did such things regularly, so there might be a typo|thinko in there, given the hour and the fact I'm not allowed coffee. The gnu tools are flexible enough to do most thing several ways, either in C or assembler, or (often conveniently) with a mix. In a post which I don't yet see on the list, Robert wrote: I chose a section originating at 0xff00 (after all the .text sections) which may not work well with GCC - it randomises the order of my 'vector table'. But if that is just an array of function pointers, then it's the programmer who initialises it, isn't it? Then the order of entries is fixed in code, and only the pointer values may be randomised if care is not taken to prevent the possibility. mfG, Erik P.S. Aaaah, when I cut my teeth on the Siemens grey version of the Intel ISIS blue box, you could count the macros being assembled, by the one long and four short head seeks on the 8.5 floppy drives, taking several seconds. There was more than time enough for too much coffee back then. :-) P.P.S. Looks like this needs to be forwarded to the list too. (Perhaps the dynamic IP range that I'm in is blocked?) Hi Erik, it seems that your block has been lifted. I had the ISIS box (8008 I think) plus the drives (they were 7, following the sizes of music records at first). The head seeks were often drowned by the teleprinter I had as hard copy device, but yes, you got used to the rhythms and knew when an assembly was finishing. /nostalgia Thinking about your answer, yes an array of pointers (and nothing else in the section) could be a good answer. GCC can't randomise the subscripts. I had simply written a sequence of stub functions, but their written order is not the order they appear in in code. I like your 'mit Gewalt' solution, it could also work - just need to be careful not to waste too much space - i.e. know the sizes of the functions. Many thanks, Robert ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: [avr-gcc-list] Allocating variables to a fixed address
Robert, There is some difference, though: you can't count on such variables to be initialised to zero. JW - Original Message --- Schwichtenberg, Knut wrote: Robert, there is no difference in handling. So create your special section and put the variables into it as you would do it with the flash. Cheers Knut -Original Message- Is there any way of 'fixing' a few, specific global variables at a known Thanks Knut, I couldn't find this documented and I expected the Harvard architecture to make life difficult. It's nice when the answer is simple. ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
[Fwd: Re: [avr-gcc-list] Allocating variables to a fixed address]
Jan Waclawek wrote: Robert, There is some difference, though: you can't count on such variables to be initialised to zero. JW This is obvious, I think, but thanks for the tip anyway. Robert ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
RE: [avr-gcc-list] Allocating variables to a fixed address
-Original Message- From: avr-gcc-list-bounces+eric.weddington=atmel@nongnu.org [mailto:avr-gcc-list-bounces+eric.weddington=atmel@nongnu. org] On Behalf Of Robert von Knobloch Sent: Monday, May 11, 2009 3:39 AM To: avr-gcc-list@nongnu.org Subject: [avr-gcc-list] Allocating variables to a fixed address Is there any way of 'fixing' a few, specific global variables at a known location? In flash, I can use a '.section' to do this. Is there an equivalent for ram? I notice that the compiler puts static variables before globals, which make it impossible to predict where the globals will be. I am writing modular software and to be version independant, I must define a simple API. I have flash under control, but now ram is the problem. Why do you need global variables to be at a specific address? ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: [avr-gcc-list] Allocating variables to a fixed address
Weddington, Eric wrote: Why do you need global variables to be at a specific address? Because my software consists of a: A fixed part - main plus User Interface - This is test equipment for small electronic products and Several loadable parts which can be loaded via rs232 as Intel hex and 'blown' into the flash as required - These are custom-built for each product. The entire code is one entity, loadables will be added and removed and I cannot have this affecting the main code. I need separation so that updates to any part of the software do not disturb the relationship between the main part and the 'loadable' parts. To this end, I need to fix all calls variables that are common to the 2 parts of the system - what I am calling an 'API'. I thought that I had the flash part all under control but now see that the compiler is out to get me again: I have defined all cross-module routines and give them 'psuedo-calls' in a vector table so: /* ** * Function entry points for independent test routines ** */ // LCD Display FUNCTION_SECTION NOINLINE void test_lcd_2(PGM_P string) { prog_lcd_string2(string); } FUNCTION_SECTION NOINLINE void test_lcd_string(PGM_P string) { prog_lcd_string(string); } FUNCTION_SECTION NOINLINE void test_clearlcd2(void) { clearlcd2(); } FUNCTION_SECTION NOINLINE void test_lcd_hex4out(uint8_t byte) { return lcd_hex4out(byte); } FUNCTION_SECTION NOINLINE void test_lcd_hex8out(uint8_t byte) { return lcd_hex8out(byte); } FUNCTION_SECTION NOINLINE void test_lcd_hex16out(uint16_t word) { return lcd_hex16out(word); } ../snip Where FUNCTION_SECTION is located at 0xff00 Now I see that the compiler is no longer preserving the order of these vectors: avr-nm -n main.elf gives: ff00 T test_read_mSecDownCnt ff10 T test_write_mSecDownCnt ff1e T test_geta2d ff3c T test_nSec400Wait ff42 T test_lcd_hex4out ff48 T test_lcd_hex8out ff4e T test_lcd_hex16out ff54 T test_lcd_string ff5a T test_clearlcd2 ff60 T test_lcd_2 ff66 T test_milliSecDelay ff6c T test_getkey ff72 T test_getkey_blink ff78 T test_pollkey ff7e T test_isp_connect ff84 T test_flash_read ff8a T test_flash_write ff90 T test_eeprom_read ff96 T test_eeprom_write ff9c T test_fuse_read ffa2 T test_fuse_write ffa8 T test_isp_disconnect Is there a way to achieve this? The project is much too big for assembler (not enough time maintenance). I can force variable access through functions, of couse. But this doesn't help when I can't trust my vector table to stay constant. ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: [avr-gcc-list] Allocating variables to a fixed address
On Mon, May 11, 2009 at 02:55:17PM +0200, Robert von Knobloch wrote: Weddington, Eric wrote: Why do you need global variables to be at a specific address? Because my software consists of a: A fixed part - main plus User Interface - This is test equipment for small electronic products and Several loadable parts which can be loaded via rs232 as Intel hex and 'blown' into the flash as required - These are custom-built for each product. The entire code is one entity, loadables will be added and removed and I cannot have this affecting the main code. Sounds to me as if you are making the bootloader too big and should simply link an entire application for every possible target. What you are doing would make more sense if the loadable modules could run out of RAM. -- David Kelly N4HHE, dke...@hiwaay.net Whom computers would destroy, they must first drive mad. ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: [avr-gcc-list] Allocating variables to a fixed address
David Kelly wrote: Sounds to me as if you are making the bootloader too big and should simply link an entire application for every possible target. What you are doing would make more sense if the loadable modules could run out of RAM. That would be no use, the loadables must be non-volatile. This is a tester that will be sent to a factory (somewhere). When a new product is to be tested, I can e-mail them the test routine which they then burn into flash (each of these is 0x900 bytes, there can be up to 0x0a of them). This will never be so often as to compromise the flash lifetime, but I must create a system whereby the 'resident' code is fixed (but maintainable) and the loadable parts can be freely added, overwritten etc. I think you will see that this needs the interface to be completely fixed (variable access, call locations) for all common parts, while the internals of e.g. the resident part is immaterial to the loadables. Provided strict adherence to the interface is observed, then a working system is realisable (I have written such systems in the past but not with AVRs or GCC). To realise this interface (API), I must be able define the variables/function calls in the resident part at known (or. at least fixed) addresses. Robert ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
RE: [avr-gcc-list] Allocating variables to a fixed address
-Original Message- From: avr-gcc-list-bounces+eric.weddington=atmel@nongnu.org [mailto:avr-gcc-list-bounces+eric.weddington=atmel@nongnu. org] On Behalf Of Robert von Knobloch Sent: Monday, May 11, 2009 7:57 AM To: avr-gcc-list@nongnu.org Subject: Re: [avr-gcc-list] Allocating variables to a fixed address David Kelly wrote: Sounds to me as if you are making the bootloader too big and should simply link an entire application for every possible target. What you are doing would make more sense if the loadable modules could run out of RAM. That would be no use, the loadables must be non-volatile. This is a tester that will be sent to a factory (somewhere). When a new product is to be tested, I can e-mail them the test routine which they then burn into flash (each of these is 0x900 bytes, there can be up to 0x0a of them). Why is this method superior to having a regular bootloader, and you have N applications, where each application is the individual test routine and the common portion? Why do you have create this custom interface which has its own set of problems? Alternatively, creating a custom Makefile to handle building 10 different applications is certainly easier in comparison. ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
RE: [avr-gcc-list] Allocating variables to a fixed address
The jumptable could just as easily be written in C. -Original Message- From: avr-gcc-list-bounces+eric.weddington=atmel@nongnu.org [mailto:avr-gcc-list-bounces+eric.weddington=atmel@nongnu. org] On Behalf Of Jan Waclawek Sent: Monday, May 11, 2009 8:21 AM To: Robert von Knobloch; avr-gcc-list@nongnu.org Subject: Re: [avr-gcc-list] Allocating variables to a fixed address I'd write the *jumptable* in asm. That's easy and means one less degree of freedom for the compiler and co. JW -Original Message- To realise this interface (API), I must be able define the variables/function calls in the resident part at known (or. at least fixed) addresses. ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
RE: [avr-gcc-list] Allocating variables to a fixed address
I have defined all cross-module routines and give them 'psuedo-calls' in a vector table so: /* ** * Function entry points for independent test routines ** */ // LCD Display FUNCTION_SECTION NOINLINE void test_lcd_2(PGM_P string) { prog_lcd_string2(string); } FUNCTION_SECTION NOINLINE void test_lcd_string(PGM_P string) { prog_lcd_string(string); } FUNCTION_SECTION NOINLINE void test_clearlcd2(void) { clearlcd2(); } . . . Where FUNCTION_SECTION is located at 0xff00 Now I see that the compiler is no longer preserving the order of these vectors: avr-nm -n main.elf gives: ff00 T test_read_mSecDownCnt ff10 T test_write_mSecDownCnt ff1e T test_geta2d ff3c T test_nSec400Wait ff42 T test_lcd_hex4out ff48 T test_lcd_hex8out . . . Is there a way to achieve this? The project is much too big for assembler (not enough time maintenance). I can force variable access through functions, of couse. But this doesn't help when I can't trust my vector table to stay constant. If I had your problem, this is how I would solve it: Define a real table of function pointers instead of trying to get the linker to create one for you. typedef void (*TestProc) (void*); NOINLINE void test_lcd_2(void* pStr) {PGM_P string = (PGM_P) pStr; prog_lcd_string2(string); } NOINLINE void test_lcd_string(void* pStr) { PGM_P string = (PGM_P) pStr; prog_lcd_string(string); } NOINLINE void test_clearlcd2(void* ign) { clearlcd2(); } NOINLINE void test_lcd_hex4out(void* pByte) { uint8_t byte = * (uint8_t*) pByte; return lcd_hex4out(byte); } ... const TestProc* TestTable[TEST_VECTORS] FUNCTION_SECTION = { test_lcd_2, test_lcd_string, ... }; You will need to modify your calls to either send the pointer to the argument (this forces all calls to have a single parameter of, essentially, a word) or to always send a word. In either case, the receiving routine will then cast the argument to the proper value before passing it on. Do not place the routines or other constants in the same linker section as the function table. If you leave the table in a section of its own, it will always be placed at the head of the section without interference from anything else. Calling the function requires you to pull the function out of the table before calling it: #define TESTPROC_LCD_2 0 #define TESTPROC_LCD_STRING 1 . . . uint16_t test_proc; test_proc = pgm_read_word( (uint16_t) TestTable[ TESTPROC_LCD_2 ] ); *(TestProc*)test_proc( myarg ); . . . You could probably enclose the above stuff in a macro to make your code far more readable: #define CallTestProc(proc,arg) \ do {\ uint16_t test_proc;\ test_proc = pgm_read_word( (uint16_t) TestTable[ (proc) ] ); \ *(TestProc*)test_proc( (arg) ); \ } while (0); . . . CallTestProc( TESTPROC_LCD_2, myarg ); That's my inspiration for the day. It's probably wrong somewhere, but it's how I would approach the problem. Best regards, Stu Bell DataPlay (DPHI, Inc.) ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: [avr-gcc-list] Allocating variables to a fixed address
On Mon, May 11, 2009 at 03:56:34PM +0200, Robert von Knobloch wrote: David Kelly wrote: Sounds to me as if you are making the bootloader too big and should simply link an entire application for every possible target. What you are doing would make more sense if the loadable modules could run out of RAM. That would be no use, the loadables must be non-volatile. This is a tester that will be sent to a factory (somewhere). When a new product is to be tested, I can e-mail them the test routine which they then burn into flash (each of these is 0x900 bytes, there can be up to 0x0a of them). Yes, what I said before, link an entire application for every possible target. If a factory needs a new module added to their tester then link an application with all the modules they need if you are not able to make a single application that supports all known modules. Another way to pull this off would be to ship the avr-ln application, object files, and let the customer link their selected module set to flash the tester. You could wrap everything up and hide the process in a script or application. Strip the debugging stubs from the object files but leave the linking symbols. Otherwise for an example of how to statically allocate global variables look in the include files for how registers are defined. -- David Kelly N4HHE, dke...@hiwaay.net Whom computers would destroy, they must first drive mad. ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Re: [avr-gcc-list] Allocating variables to a fixed address
On Mon, May 11, 2009 at 08:21:37AM -0600, Weddington, Eric wrote: Sounds to me as if you are making the bootloader too big and should simply link an entire application for every possible target. What you are doing would make more sense if the loadable modules could run out of RAM. That would be no use, the loadables must be non-volatile. This is a tester that will be sent to a factory (somewhere). When a new product is to be tested, I can e-mail them the test routine which they then burn into flash (each of these is 0x900 bytes, there can be up to 0x0a of them). Why is this method superior to having a regular bootloader, and you have N applications, where each application is the individual test routine and the common portion? Why do you have create this custom interface which has its own set of problems? Alternatively, creating a custom Makefile to handle building 10 different applications is certainly easier in comparison. I agree, thats how I would handle it. Either build a custom linked application for each customer or provide the customer with the tools to build one of their own. What he is trying to do is in effect create a run time program linker. -- David Kelly N4HHE, dke...@hiwaay.net Whom computers would destroy, they must first drive mad. ___ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list