Coldfire divide-by-zero exception handler

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Coldfire divide-by-zero exception handler

1,472 Views
JOA2
Contributor I
Hy 

I am using a COLDFIRE 5475 with FreeRTOS. I would like to trap and continue after a divide-by-zero execption. I can hook interrupt vector 5, but when I return from the interrupt instructions is executes again. I need to skip over this instruction.

Does anyone how can I do this.

Thank you in advance.

Oscar Alegría

Labels (1)
0 Kudos
4 Replies

771 Views
TomE
Specialist II

From the "ColdFire Family Programmer’s Reference Manual":

 

> An attempt to divide by zero results in a divide-by-zero exception

> and no registers are affected. The resulting exception stack frame

> points to the offending divide opcode.

 

The "DIVU" and "DIVS" instructions operates on a destination register (Dx) and a source (y) which can be a register, immediate or point to memory. There are 11 different modes available to specify the source operand. The instruction executes as "Dx = Dx / y". A divide-by-zero trap results when "y" is zero.

 

So your interrupt service routine can look back on the stack frame, extract the failed PC, load that and thereby inspect the instruction opcode. At that point there are two options:

 

1 - Decode the "DIVx" instruction, work out which of the 11 different addressing modes is used for the source, find the source data (which is currently a zero) and change it to something that is non-zero. This won't work if the data is in ROM or if it is an immediate operand (unless you want to have self-modifying code, and you'd also have to flush the caches to write the new instruction back). Don't do this at home...

 

2 - Decode the instruction, work out how many 16-bit words long it is (either 1, 2 or 3 depending on the mode) and then increment the saved program counter (on the stack) by that many words to skip over the instruction on the return. You may also want to work out which "Dx" register the instruction was going to write the answer to, and then set that to zero, 0xffffffff or whatever is appropriate to the failed arithmetic. For 16-bit divides the result is 16 bits of remainder, 16 bits of result, so you may want different "defaults" for 16 and 32 bits.

 

Watch out that "DIVS" and "DIVU" aren't the only one to generate the divide by zero trap.  You have to handle "REMU" and "REMS", and they're either 2 or 3 words long with 5 different modes and two result registers (dividend and remainder). In fact looking at disassembled code I find gcc is more likely to generate one of these for a divide than use a real divide instruction.

 

So it isn't exactly easy! It is also VERY hard to test as you have to manually generate all of the possible DIV and REM variants in assembly code (or manually in raw HEX) and then test to see if the trap did the right thing in all cases. If you get this wrong the CPU may then generate an illegal instruction trap (if you're lucky) as you've returned to the wrong place in the instruction stream.

 

The other alternative is to always test (in your C code) to see if the source data is zero before performing the division and spitting out an error message (and/or setting a default value). This is better coding practice anyway. Don't you care that the code has just been given dud data and has tried to generate an invalid result?

 

More common than this are the overflows that result from multiplications. This CPU doesn't have the ability to trap overflows. The 68k on which it is based at least set the Overflow flag, but this one doesn't even do that! So code that cares about this has to go through hoops range-checking both numbers before performing each multiply operation.

 

Tom

 

 

0 Kudos

771 Views
JOA2
Contributor I

Thank you  Tom.

 

I am now decoding PC and incrementing 4 or 2 depending instruction start with 0x4---- or 0x8---- .Now is working but I have to see other error posibilities.

 

Oscar 

0 Kudos

771 Views
TomE
Specialist II

> I am now decoding PC and incrementing 4 or 2 depending instruction start with

> 0x4---- or 0x8---- .Now is working but I have to see other error posibilities.

 

That will only work with the register modes of the instructions, but you've spotted some good simplifications that I missed.

 

DIVU and DIVS are 0x8XXX for short (1 word) and 0x4XXX for long format (2 words)

REMU and Rems are 0x4XXX and are always 2 words.

 

For all of them, the extra length depends on the "Source Effective Address field" in the lower 6 bits of the first instruction.

 

Modes 0, 2, 3 and 4 don't have any extra words.

Modes 5 and 6 have one extra word.

Mode 7, Reg values 0, 2, and 3 have one extra word

Mode 7, Reg values 1 has two extra words

Mode 7, Reg values 4 has one word for "word" mode (0x8XXX) and two for "Long" (0x4XXX).

 

Make sure you double-check the above.

 

Tom

 

 

0 Kudos

771 Views
JOA2
Contributor I

Thanks again Tom.

A am only using register modes. But I think that I am going to program all cases. 

0 Kudos