AnsweredAssumed Answered

Coldfire, Interrupts and the "Halting problem"

Question asked by TomE on May 7, 2015
Latest reply on May 12, 2015 by TomE

I've been working on a nasty problem on an MCF5235 for about 2 weeks, and what I've found might help others.


If you don't know the background to "The Halting Problem" you might want to read up on it a bit. It isn't about "Halting", but deciding, by inspection, if a particular program will run the way you expect it to.


I've just found a simple class of program that doesn't run the way I'd expect it to on the MCF5235, and what it actually did resulted in stack corruption and crashes.


It could also result in a buggy program running, but really S L O W L Y and without any obvious reason for it running like that.


Here's an example program. The critical part of this is that it triggers an interrupt, but then doesn't clear it. For simplicity this code is using the "MCF_INTC0_INTFRCL" Interrupt Forcing registers, but forgetting to clear a Peripheral Interrupt would do the same thing.


So, by inspection, what would you experienced Coldfire programmers expect to happen when I run the following code? All 29 of you following this forum apparently.


When I've accidentally done this on other CPUs I've used, the code is now stuck continuously executing the interrupt service routine, and the watchdog usually goes off some time later.


volatile int nStuckCounter = 0;  __attribute__((interrupt_handler)) static void stuck_int(void) { /*  INT_UNFORCE(int_task_switch); */      nStuckCounter += 1; }  void test(void) {     int i;      INT_SET_VECTOR(int_task_switch, stuck_int);      printf("Prior to Force, nStuckCounter = %u\n", nStuckCounter);      INT_FORCE(int_task_switch);      for (i = 0; i < 40; i++) {         counts[i] = nStuckCounter;     }     for (i = 0; i < 40; i++) {         printf("Loop %d, nStuckCounter = %d\n", i, counts[i]);     }      INT_UNFORCE(int_task_switch);      printf("After Unforce, nStuckCounter = %u\n", nStuckCounter); }



  1. If it locked up like I expected I wouldn't be asking.
  2. In the Interrupt Service Routine the proper thing to do is to clear the "Force" using the "INT_UNFORCE()" macro, but I've deliberately commented that out.
  3. "INT_FORCE", "INT_UNFORCE" and "INT_SET_VECTOR" work as expected. They're not important and not a problem here.
  4. "printf()" works as expected (polled printing to the serial port)


For "bonus points", here's the disassembly of the counting loop above, and with that information you should be able to tell me what the printed "nStuckCounter" values will be...


If I could paste disassembly into this forum, but after years of complaining about not being able to simply "paste code", and TWO "updates" this forum STILL can't do that. It is trying to paste the disassembly into a table and then word-wrapping and mangling it!


More multiple tries (you can't see how long this took). I had to manually remove all the spaces, paste it in and then reinstate all the spaces. Now it looks OK.


80101eea: 280e           movel %fp,%d4 80101ef8: 0684 ffff ff60 addil #-160,%d4  for (i = 0; i < 40; i++) {     counts[i] = nStuckCounter; } 801024d4: 2044           moveal %d4,%a0 801024d6: 2039 8080 003c movel 8080003c <nStuckCounter>,%d0 801024dc: 20c0           movel %d0,%a0@+ 801024de: bdc8           cmpal %a0,%fp 801024e0: 66f4           bnes 801024d6 <main+0xb34>


I'll post the printout I have next week.


More bonus points. Where, and in what manual is this behaviour documented?