I'm porting firmware written for 68040 using another vendor's toolset into a Coldfire application for V2 (MCF52100) using CodeWarrior 10.1. The board is our custom design with the Coldfire replacing the 68040. All peripherals are on the board rather than using the internal peripherals, i.e. using the Coldfire as a processor only interfacing with memory mapped devices. This allows the board to be a "drop-in" replacement for our previous design. That's the theory, anyway. The code is in C with some inline assembly as needed.
I am relatively new to both Coldfire and CodeWarrior but have extensive uP and uC experience with some experience with 68K processors.
My problem is that I'm getting a perpetual interrupt when setting the IPL to 0 in the SR. At initialization, the IPL is loaded with 7 and all of the unused exceptions are initialized to a routine "uninit" to perform as a default handler for each vector in the table (original program worked this way). A specific interrupt routine is then added in the user vector area to service our on-board UART. This is the only interrupt we really need. At the start of the main loop the IPL is then changed to 0 and one of the default handlers appears to be fired in an infinite loop. I haven't determined which vector caused it. I don't see where any "interrupt clearing" is done so I wonder if that is missing in the original code and/or is done differently for Coldfire. Also, the listing file from CodeWarrior shows that the "uninit" routine does execute "strldsr $2700" which should mask the interrupt from reoccurring yet it appears that it still fires.
I tried to change the priority level of the routine by modifying the declaration of the function to "_declspec (interrupt:1) void uninit()" and then set the IPL to 3 instead of 0 hoping that this interrupt would not be executed but it still does. Comparing the S19 files for this build to the previous build shows the exact same file so is this not the way to set the interrupt priority level? It is the only method that I have found documented anywhere. Is setting the priority level the right way to ignore the exceptions I don't want?
Obviously I'm really confused and could use some help.
The Coldfire works in a similar way to the 68k, with the addition of the Interrupt Controller and all of its registers. These registers need to be programmed in addition to what your existing code is doing.
The MCF52 series is tricky (the MCF53 series is easier to work with). Specifically, make sure you get this right
14.3.6 Interrupt Control Registers (ICRnx)It is the responsibility of the software to program the ICRnxregisters with unique and non-overlapping level and priority definitions.
You should be able to find out what is going on with a debugger. Have you got one? If not, I'd suggest that you get one. It will be useful for other things. If you do have one, stop in the "uninit" routine and examine all the interrupt controller registers. IPRH0 and IPRL0 will show which ones are pending. Read IRLR0 and IACKLPR0.
You might have a hardware problem. Are all the interrupt request lines pulled up? Are any of them stuck down? Write EPIER to zero to disable all Edge Port interrupts.
You might also want to search for "interrupt" in the forum and follow a few links.
This one might help you:
What would really help would be a DIAGRAM of the interrupt sources and their path through the controller to the CPU. As far as I can tell, none of the Coldfire manuals have a diagram like this. It would help your understanding to draw one while reading the interrupt controller chapter.
> At the start of the main loop the IPL is then changed to 0 and one of the default
> handlers appears to be fired in an infinite loop. I haven't determined which vector caused it.
The first thing you have to do is to find out which one is doing it. Have the service routine read the interrupt controller registers to see which interrupt requests are active, or read them in the debugger.
> Also, the listing file from CodeWarrior shows that the "uninit" routine does
> execute "strldsr $2700" which should mask the interrupt from reoccurring
> yet it appears that it still fires.
Two possibilities. If that service routine returns, then the status register (and the priority level) are returned to what they were before by the RTS instruction. So any pending interrupts will happen again. You may be getting traps of some kind rather than interrupts. Point the CPU error traps to a different routine, preferably a different one for each trap.
Thanks for the suggestions. I'll go research these and post results later.
We are working to get a debugger through our purchasing department. Unfortunately my schedule is short and they usually take forever so I'm attempting what I can until then.
> We are working to get a debugger through our purchasing department.
We use the PE Micro USB-ML-CFE. It costs all of US$249. Make sure it works with your CW development system debugger first.
Raid the Petty Cash Tin. It can pay for itself for every DAY it saves you.
I had problems with a "purchase department" that was happy to waste tens of thousands of dollars of engineering time so as to delay paying $99 for the compiler I needed! I think I badgered my boss at the time to buy it on his personal credit card.
These things haven't been "optional luxuries" for at least the last 20 years. They are a required part of standard development. Like your desk, chair, the PC on your desk, the printer and the water cooler of coffee machine in the kitchen.
How are you programming the part? You have to have some USB-to-Debugger-port cable. What sort of 'programming cable" did you get with CW that isn't also the debugger pod? Or are you still burning UV-Erase EPROMS or socketable FLASH chips and plugging them into the 68040 base board? :smileyhappy:
(I use CodeSourcery and command-line GDB with the PE, so I don't know what comes with which versions of Code Warrior).
I agree about having the tools. Going around purchasing in my company can (and will) get you fired so I tend to follow the rules Buying it myself has gotten me in hot water as well (unless I work on it at home).
I'm loading code through a bootloader that uses the external UART on our board. One of the problems I have is trying to write Coldfire code that will be backward-compatible with our original 68040 boards so that only one program is necessary. I've got to get it working on Coldfire before I venture into the 68040.
Our final customer wants to use only one program so that the two boards will be interchangeable with the same firmware loaded. Frankly, I'm not sure it can be done based on the exception handling differences not to mention register differences, especially based on what I'm getting right now. Freescale has convinced management that it is possible so I now have to prove or disprove it. It should have been relatively easy to take 68040 source and create a version to run on Coldfire using V2 but you can see I'm still struggling with it. I have my doubts that the Coldfire executable will work on the 68040. I've said as much but I'm being told to "make it work if at all possible".
Using one program with hooks in it to modify operation based on detection of the processor is an option but I'm unsure how to detect which one is present on the board. Most of the documentation I have found states to try an illegal instruction and let the exception handler decide. Tough to do that when I haven't gotten the exception handling perfected yet. Sure would be nice if there was an ID word somewhere, like most other uCs use. If there is one, I haven't stumbled across it yet.
> Our final customer wants to use only one program so that the two boards will be
> interchangeable with the same firmware loaded.
I didn't think they were compatible at the assembly code level, but comparing the programming manuals shows they haven't changed anything basic that they didn't have to. The ColdFire is closer to a 68000 than a 68020 to 68040 (or even CPU32+) as they left out a lot of the advanced addressing modes. Is the application using hardware floating point? I think that changed a lot on the CF chips that have FP, but I don't think the MCF52100 has FP at all.
I've found there's a section in a very old MCF5102 manual on Freescale's web site (from 1995, I suggest you read it) documenting an "Evaluation Module" that was a drop-in replacement for an MC68EC040. The MCF5102 was deliberately made to be code compatible with the MC68040 to aid porting, but later chips in the family dropped that ability.
If you wanted to change from using an MC68040 to a ColdFire chip, then it would have been easier to use an MCF5102 back in 1995 and not a different one 17 years later.
> but I'm unsure how to detect which one is present on the board.
These things usually have a "CPU Feature Register" of some sort. The ColdFire chips do:
"1.10 Hardware Configuration Information
ColdFire hardware configuration information is loaded into the D0 and D1 general-purpose registers after system reset."
Yu can't use that as the older ones don't seem to do that, at least not from a quick read of the programming manual. I don't think they have a "known initial state" for those registers, so they could accidentally wake up looking like the new one. The chip-specific data sheet may show something more. You may have to find an instruction that works on one architecture and traps on the other one.
> One of the problems I have is trying to write Coldfire code that will be backward-compatible
> with our original 68040 boards so that only one program is necessary.
You can't use the old compiler unless it has a "ColdFire" switch, but I see you're using CW. I don't know how anyone can guarantee that CW will generate code suitable for both a CF and a 68040 with the same configuration settings. Have Freescale given a written guarantee of that together with documentation on how to configure CW?
It would be far safer to generate two completely separate binaries and burn them both to the FLASH. Have the chip decide which binary it wants to run on startup. That would require double the FLASH storage compared to the code, and you probably aren't that lucky.
You're going to have to become a 68040 expert and a ColdFire expert to the level of knowing all the differences. That's a very tough job. Start by downloading the 68040 manuals from Freescale and reading them cover to cover. Likewise the ColdFire manuals.
>I didn't think they were compatible at the assembly code level, but comparing the programming manuals shows they haven't changed anything basic that they didn't have to. The ColdFire is closer to a 68000 than a 68020 to 68040 (or even CPU32+) as they left out a lot of the advanced addressing modes. Is the application using hardware floating point? I think that changed a lot on the CF chips that have FP, but I don't think the MCF52100 has FP at all.
That's the rub. The app doesn't use FP and I have the old compiler for 68040 running on an XP machine but it doesn't include Coldfire. Our HW guys are looking at several options for Coldfire; this was the first one they wanted to try. They are now leaning toward using a V2 burnable core (compatible with MCF5208) instead so my work is a moving target . What I have been able to do is compile the tweaked source using CW and then load it to an old 68040 board I have on hand. It works up to a point and gets caught in an exception. It appears that the exception stack frame is different between 68040 and MCF52100 (and MCF 5208). so I haven't been able to determine the cause. I may need to create a separate handler for each exception just so I can determine what vector/address caused the problem. Sure could use a better debugging system but I'm at the mercy of others right now.
17 years later was out of my control. The original design dates to 1990 and the configuration of the board is under our customer's control. They have been buying them from us since then and did not allow us to redesign the board after repeated obsolescence warnings. They finally accepted that they need a new replacement but they want the same firmware to run on both versions. We tried to warn them.
As to reading the manuals, you're right. I've spent a tremendous amount of time doing just that. And will probably have to continue to do so.
> The app doesn't use FP
That's lucky and a little surprising, unless the board is really using an MC68EC040 and not an MC68040. Which one is it using? Is their code ignoring the MMU as well? MMUs can be used for neat tricks apart from their traditional uses.
> They are now leaning toward using a V2 burnable core (compatible with MCF5208)
"burnable core"? Do you mean a CPU with onboard FLASH or a core to build into an FPGA or custom chip? I'd stay away from the latter unless you have a lot of time to develop it as the CPU is now hidden behind a lot of other hardware that can stop you from debugging it easily and can cause other problems. For instance on the dedicated chip the memory bus timing is specified in the data sheet. For a core inside another chip the timing is the core timing modified by whatever other silicon is between there and the pins on the chip, and that may now no longer be a clean match to the memory chips that are on it. With a standalone chip I can prove the memory timing is OK in 10 minutes using just the data sheets and a pencil. For an embedded core you have to simulate everything to validate the timing, and that could take weeks to do properly.
> they want the same firmware to run on both versions
Motorola made the MCF5102 code compatible with the MC68EC040. That might be the only one they made like that. If the customer insists on "same code runs on both CPUs" then you need an MCF5102.
The status of that part is "no longer manufactured", as I'd expect.
Why the same firmware? Maybe they want proof of the Tooth Fairy and "World Peace in our Time" as well. I assume they want this under the naive assumption that "if you don't change anything in the code then no new bugs can creep in", or maybe they only want to validate one code set - or don't want to RE-validate the code for the new CPU.
Are you sure there's no "timing loop" code in there that might go wrong if the CPU is running a lot faster, or even a little faster? Given the old board didn't use a CPU with internal hardware timers, what does the old code use for "real time"?
It may be possible to try and make "one binary". I wouldn't trust it as far as I could throw it, as you may be asking the compiler to do something outside what it is normally used for. If the compiler does have some switches to try and limit the instructions it uses, it is likely that these haven't been exercised or tested in something like 17 years. Running into compiler bugs can really hurt your schedule.
There may be a choice between "two reliable binaries" or "one you can't trust to work on either CPU".
IPextreme is a Freescale partner that offers a V2 core that is burned into FPGA. Freescale convinced our HW gurus that is the way to go. I've made my arguments against. There have been some convincing arguments in favor as far as hardware is concerned. Continued availability is also longer using that approach rather than a new part. Keep in mind this system has been in use with few changes 24/7 for about 20 years and our customer is still buying systems.
I confess that this is an experiment to find out IF we can do it. The customer is adamant to have a single program for both boards if at all possible; the end of the experiment may be that we can't. In that case most of the problems should go away (except convincing the customer that it is the right way to go). Better debugging capability is obviously desired.
The board is part of a large switching system with muliple copies of this board. Since it predominately controls digital I/O there is no need for FP. The 68040 was chosen for different reasons years ago. The customer wants the board to be a true drop-in replacement, including a single binary file for both versions. Sometimes the only answer is "give the customer what he wants", as long as it isn't illegal, immoral or against the laws of physics.
The timing is established by hardware on the board, not in the CPU. For compatibility, none of the MCF5208 I/O will be used so the original hardware at the original addresses can be implemented. Timing should not be an issue since the clocking external to the CPU controls when things occur. The event timing is not particularly fast so both CPUs spend a lot of time in wait states.
> V2 core that is burned into FPGA.
Minimum evaluation is one of those on a development board with a complete working development system consisting of compiler and graphical debugger, with debugger hardware. IPextreme might be able to provide or loan you such a setup. That would at least get you a debugger quickly :smileyhappy:.
> The customer is adamant to have a single program for both boards
That is easy. Just have two complete separate copies of the code in the one file, one compiled for 68040 and the other for ColdFire. Have the CPU execute "it's copy" after determinining what it is on startup. The main problem with that is that this doubles the size of the code file and it may not fit in available memory (FLASH or RAM).
If there's enough memory to do this you have your solution. If not, then...
Does the code run from FLASH or is it loaded into RAM and executed from there? RAM is usually faster than FLASH so a lot of systems do this. If there's not enough FLASH for two copies, but it runs from RAM, then store the two binaries compressed in the FLASH with a small boot loader that decompresses the right version into RAM and runs it from there.
If it doesn't run from RAM you could ship the code as a "package" that hsa a boot loader and two compressed binaries. The boot loader loads into RAM, decompresses the correct binary and then burns it into FLASH, so the next time it starts it runs the correct version that has been burned to FLASH.
This is very old technology. When the Macintosh went from 68k to PPC they were shipping "Fat Binaries" with two sets of code in them. They also ran a 68k emulator on the PPC. Why not do the same, then there's no need to run a ColdFire chip - the hardware could run anything (PPC, ARM whatever) and simply emulate the 68040. That gets you a "single binary", the old one.
> The board is part of a large switching system with muliple copies of this board.
So those boards might not even hold their own code. The code might be loaded from a "master controller" somewhere into RAM. That RAM-loaded code could do something similar to the above.