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.
Hallo!
I have boot loader written in asm and have to translate it to C-language (probably with asm inserts) to simplify life for successors. Keil does the following: a) for the very first code, it always put jump instruction to transfer control to either generated C_STARTUP code section (if no startup asm module in the project) or to the startup asm module if it was added to the project b) puts all associated startup code to the executable c) generates jump back to main()
00000000 FA000800 JMPS ?C_STARTUP(0x8) ... 00000XXX FA000400 JMPS main(0x4)
Questions: 1) Is there any way to avoid this jump instructions, suppress startup code generation and just have "plain" compiler output 2) This plain executable should be aligned to the adress (FA60h) at which I need to place my bootloader entry point
So, the idea is how to get rid of all the code not written by you, i.e. with no any piece of code added by IDE s/w.
Does anybody have answers?
Thanks & Regards, Nikolay.
Hallo, All!
FYI (to whom it may concern):
Since there was no any reply, I went through and figured out simple solution on how to write any bootloader-like f/w in C (with inline ASM inserts if needed) with influence of Keil IDE avoided. The influence involves requirement to have c_startup code section and if you exclude startup ASM module from the project, the IDE will generate some default code you do not need; as well, by default Keil inserts jumps from reset vector to the startup section and backward jump to the C-module main() entry point after the startup initialization done.
The solution is as follows:
1. Use something like this fake startup ASM module in Keil IDE project. This code does nothing in reality:
; ; Stub to get boot-loader compiled from C source files ; w/o any undesirable code created by IDE, ; i.e. this stub is to avoid the c_startup code and JMPS between ; reset vector, c_startup and main() ; ; THIS CODE DOES NOTHING IN REALITY, THIS IS JUST A STUB ; ; Bkl/Sep-2007 ; $MOD167 ; C167 mode ; No real influence on HEX file out of memory model analyzed here $CASE $IF NOT TINY $SEGMENTED ; boot-loader/monitor better uses EXTS $ENDIF ; below, all directives almost "fake" to make Keil happy _STKSZ SET 1 _STKSZ1 SET 2 $IF NOT TINY ASSUME DPP3:SYSTEM ASSUME DPP2:NDATA $ENDIF NAME ?C_STARTUP PUBLIC ?C_STARTUP $IF MEDIUM OR LARGE OR HLARGE OR XLARGE Model LIT 'FAR' $ELSE Model LIT 'NEAR' $ENDIF EXTRN main:Model PUBLIC ?C_USRSTKBOT ?C_USERSTACK SECTION DATA PUBLIC 'NDATA' $IF NOT TINY NDATA DGROUP ?C_USERSTACK $ENDIF USTSZ EQU 80H ?C_USRSTKBOT: DS USTSZ ?C_USERSTKTOP: ?C_USERSTACK ENDS ?C_MAINREGISTERS REGDEF R0 - R15 ; No actual code will be generated (!) _TOS EQU 0FC00H _BOS EQU _TOS - (1024 >> _STKSZ1) PUBLIC ?C_SYSSTKBOT PUBLIC ?C_SYSSTKTOP ?C_SYSSTKBOT EQU _BOS ?C_SYSSTKTOP EQU _TOS SSKDEF _STKSZ ; ; Empty c_startup section as formal requirement to be fulfilled ; ; No jump to main() and jump to here from reset will make ; debugging more hard but allows to produce from C source files ; nicely aligned HEX file as it being compiled from an ASM source ; ; To debug the code itself, either home-made s/w may require ; or a separate debug target options with this stub being re-modelled ; ; this boot-strap start location (0xFA60) ; has no code originated from c_startup ?C_STARTUP_CODE SECTION CODE AT 0FA60H ; RESET = 0 is fake vector since ignored due to NOVT directive in IDE ?C_RESET PROC TASK C_STARTUP INTNO RESET = 0 ?C_STARTUP: LABEL Model $IF TINY ; JMP main ; COMMENTED OUT INTENTIONALLY $ELSE ; JMP FAR main ; COMMENTED OUT INTENTIONALLY $ENDIF ?C_RESET ENDP ?C_STARTUP_CODE ENDS END
The startup ASM code is just a stub which does not produce real code so all STARTUP stuff must be done in C source files.
2. You should define your <User Classes> in <Target Options\L166 Locate> tab. E.g.: BOOTCODE(0xFA60-0xFDFF), BOOTDATA(0xFC00-0xFDFF), NDATA(0xFC00-0xFDFF). Uncheck <Use Memory Layout from Target Dialog>. Also, you may want to define User Sections as well. <DPPUSE> can also be unchecked if you take care of addressing (but be careful about it)
3. Under <Target Options\L166 Misc\Misc Controls> put NOVT linker directive to get avoid JUMS from 0x0 address to the c_startup added to output HEX file. Remember, the JUMPS from c_startup to the main() is commented out in fake ASM module
4. Put #pragma RENAMECLASS (NCODE=BOOTCODE) (see example on user-defined classes above) before the main(). Check you have no executable code before or at this address except the main()
The main.c module (example) is shown below:
// // Second-stage bootloader // C16x MCU family, Keil compiler // #include <intrins.h> #include <c167cs.h> #pragma SMALL #pragma RENAMECLASS (NCODE=BOOTCODE) // ************************************************************* // ENTRY POINT OF BOOT-LOADER STAGE #2 // ************************************************************* void main(void) { // the 3 instructions below are executed in 32-byte boot-loader // _diswdt_(); // TFR= ZEROS; // PSW= ZEROS; STKOV= 0xFA00; STKUN= 0xFC00; SP= 0xFC00; CP= 0xFC00; SYSCON= 0x0; BUSCON0= 0x0; BUSCON1= 0x0; ADDRSEL1= 0x0; /* BUSCON2= 0x0; ADDRSEL2= 0x0; BUSCON3= 0x0; ADDRSEL3= 0x0; BUSCON4= 0x0; ADDRSEL4= 0x0; */ __asm { JMPS 0, FAR PTR init_sys init_sys: } DPP0= 0x0; DPP1= 0x1; DPP2= 0x2; DPP3= 0x3; _einit_(); // YOUR CODE HERE ... while(1); }
As a result, "plain" hex file is generated, with no undesirable instruction in it, i.e. All instructions are 1:1 controlled in C-source/inline ASM:
:020000040000FA :10 FA60 00 E60A00FAE60B00FCE60900FCE60800FC EA :10 FA70 00 E6890000E6860000E68A0000E60C0000 49 :04 FA80 00 FA0084FA 0A :10 FA84 00 E6000000E6010100E6020200E6030300 CE :06 FA94 00 B54AB5B50DFF F7 :00000001FF
This HEX is equivalent to the ASM:
0000FA60 E60A00FA MOV STKOV,#0xFA00 0000FA64 E60B00FC MOV STKUN,#0xFC00 0000FA68 E60900FC MOV SP,#0xFC00 0000FA6C E60800FC MOV CP,#0xFC00 0000FA70 E6890000 MOV SYSCON,#0x0000 0000FA74 E6860000 MOV BUSCON0,#0x0000 0000FA78 E68A0000 MOV BUSCON1,#0x0000 0000FA7C E60C0000 MOV ADDRSEL1,#0x0000 0000FA80 FA0084FA JMPS 0x00FA84 0000FA84 E6000000 MOV DPP0,#0x0000 0000FA88 E6010100 MOV DPP1,#0x0001 0000FA8C E6020200 MOV DPP2,#0x0002 0000FA90 E6030300 MOV DPP3,#0x0003 0000FA94 B54AB5B5 EINIT 0000FA98 0DFF JMPR CC_UC,0x00FA98
P.S. An useful example on bootstraping for further reading can be found at: www.rigelcorp.com/.../isp97.pdf
Regards, Nikolay.
Hey Nikolay,
Thank you for taking the trouble of following up on your own post and sharing what you've found. Nice netiquette!
Some thoughts I had about this:
We are not using the IDE at all (editor + GNU make instead) but apparently the IDE/linker requires a startup file (which we have so no problems there)? I haven't been able to find a directive to turn this off. But it got me thinking, would it be possible to rename your main.c file to c_startup.c ?
Your startup file does contain some other definitions/symbols (stack, etc.) but I guess you could put them in the same .c file using #pragma asm.
I'm not sure if it would be possible to rename the module name from inside a .c file. It's normally just the filename, see http://www.keil.com/support/man/docs/c166/c166_ap_sgc.htm That way you could make a single bootloader.c that contains some symbol definition asm from the startup file and is renamed to C_STARTUP to keep the linker happy.
[...]
Ah, take a look at: http://www.keil.com/support/man/docs/l166/l166_name.htm
You could do it using the linker like so:
C166 bootloader.c L166 bootloader.obj NAME(C_STARTUP) NOVECTAB
Not sure it this works though :-)
Thanks for the NOVECTAB/NOVT directive, didn't know it yet.
Good luck.
Kind regards, Joost
Hmm, the linker directive NAME from http://www.keil.com/support/man/docs/l166/l166_name.htm seems to do something different. It's a module name (?) (not the output file name) of the resulting absolute image file.