System: CW 10.0 beta 3
Target: MCF51QE128
Language: C++
I'm letting Processor Expert do much of the work, and it's constructed an __initialize_hardware() routine in its cpu.c that does what I want, such as turning off the watchdog and enabling the external reset input. However, that code isn't getting included in my build. Instead, it was using a different (empty) __initialize_hardware() function that was declared with "#pragma overload" in startcf.c , even though "#pragma overload" is supposed to make that a weak symbol that would be replaced by my function.
I've commented out the startup.c function, but now a new __initialize_hardware() function has taken precedence; that code just clears D0-D7 and A0-A4 and then returns. Perhaps that code came from the EWL library.
What can I do to have the linker use the __initialize_hardware() function that's in cpu.c? I see no way to specify link order in CW 10.0 beta 3.
Wayne
Solved! Go to Solution.
Did you create a C++ project?
I did not see this bug when creating a C project, but for a C++ project the wizard enables "Force C++ Compilation" in the settings
(which I find a bit unfortunate if you ever want to mix real C code with C++ code). This option causes that the processor expert module gets compiled as C++, hence the __initialize_hardware gets name mangled.
Follow-up: Yes, the 2nd substitute __initialize_hardware() function did come from the EWL library: the EWL runtime Coldfire library's librt.a which had been built from CF_startup.c long ago. CF_startup.c's function is marked with the "#pragma overload" just like the startcf.c's is:
/* * Dummy routine for initializing hardware. For user's custom systems, you * can create your own routine of the same name that will perform HW * initialization. The linker will do the right thing to ignore this * definition and use the version in your file. */#pragma overload void __initialize_hardware(void);asm __declspec(register_abi) void __initialize_hardware(void){ clr.l d0 clr.l d1 clr.l d2 clr.l d3 clr.l d4 clr.l d5 clr.l d6 clr.l d7 movea.l #0,a0 movea.l #0,a1 movea.l #0,a2 movea.l #0,a3 movea.l #0,a4 rts}
So I still have my problem. How can I get startcf.c's call to __initialize_hardware() to invoke the __initialize_hardware() routine in the Processor Expert's cpu.c, rather than this runtime version? cpu.c is located in my "(project name)/Generated Code" subdirectory.
Wayne
Follow-up: perhaps part of the problem is mixed assembly code and C/C++ code:
The startcf.c caller invokes __initialize_hardware() from ColdFire V1 assembly code:
asm __declspec(register_abi) void _startup(void){ /* disable interrupts */ move.w #0x2700,sr /* Pre-init SP, in case memory for stack is not valid it should be setup using MEMORY_INIT before __initialize_hardware is called */ lea __SP_AFTER_RESET,a7; /* initialize memory */ MEMORY_INIT /* initialize any hardware specific issues */ jsr __initialize_hardware /* setup the stack pointer */ lea _SP_INIT,a7 /* (etc.) */ rts
and that's the call that is getting matched with the __initialize_hardware() function from the EWL library, as noted above. That library function is also written in ColdFire v1 assembly language.
However, the cpu.c source file created by Processor Expert defines __initialize_hardware in C (or C++, if C++ compilation is forced by a compile flag):
/*** ===================================================================** Method : __initialize_hardware (component MCF51QE128_64)**** Description :** Configure the basic system functions (timing, etc.).** This method is internal. It is used by Processor Expert only.** ===================================================================*/void __initialize_hardware(void){ /* ### MCF51QE128_64 "Cpu" init code ... */ /* PE initialization code after reset */ /* Common initialization of the write once registers */ /* SOPT1: COPE=1,COPT=1,STOPE=0,WAITE=1,??=0,RSTOPE=0,BKGDPE=1,RSTPE=1 */ setReg8(SOPT1, 0xD3); /*(etc.)*/}
Can someone clear up this issue of symbol resolution for me?
I don't want to modify the cpu.c routine, since that's regenerated by Processor Expert whenever there's a change in the CPU properties, so the change would have to be made in the startcf.c routine instead. Do I need a wrapper function to go from assembly to C/C++?
Wayne
Did you create a C++ project?
I did not see this bug when creating a C project, but for a C++ project the wizard enables "Force C++ Compilation" in the settings
(which I find a bit unfortunate if you ever want to mix real C code with C++ code). This option causes that the processor expert module gets compiled as C++, hence the __initialize_hardware gets name mangled.
Good catch! That was exactly the problem. I had created the project as a C++ project, and "Force C++ Compilation" was checked on in Project Properties / ColdFire Compiler / Language Settings. Unchecking that caused the __initialize_hardware code in cpu.c to be included.
I had also included Processor Expert component Term (which included inherent component AsynchoSerial), and the Watchdog component . Those are defined in .c and .h sources, but my code that calls them is a .cpp and .hpp source, and so generated C++ external names from their prototypes. That caused their entry points to be undefined symbols during the link. (I had kept the Force C++ Compilation option to cure that problem.) I fixed the problem instead by changing my calling code's C++ mode to C for the includes of the component .h sources:
#pragma cplusplus off#include "Term1.h" // asynchronous serial terminal#include "Inhr1.h" // asynchronous serial device#include "WDog1.h" // watchdog timer#pragma cplusplus reset
Thanks! You get credit for the solution.
Wayne