Page 1 of 1

Floating-point exception in pascal

Posted: Sun Aug 19, 2007 3:15 am
by inflater
Greetings,
after these tiny problems there grew a big one:
I'm trying to use FPU inside free pascal. I didn't make my own functions because I can use the functions from go32v2 extender. And here's the catch:

Code: Select all

{$ASMMODE intel}
    function round(d : extended) : longint;assembler;[internconst:in_const_round];
      var
        oldcw,
        newcw : word;
        res   : longint;
      asm
            cli
            fnstcw oldcw
            fwait
            mov  newcw,1372h
@@blah1:
            cmp  cx,3
            jne @@blah1
            fldcw newcw
            fwait
            fld d
            fist res
            mov eax,res
            fldcw oldcw
            sti
      end ['EAX'];
{$ASMMODE ATT}
This function works fine, but if that function has been called many times (10 or such), Bochs will start to panic:

01236716631i[CPU0 ] math_abort: MSDOS compatibility FPU exception
And this is right in the instrunction "fwait", right before the fldcw. And after fwait, every floating point instruction will fail and Bochs will generate very big log with all this. I wonder why this isn't called right on the first FPU instruction, always it would start after some calls (program is computing circles to draw a color spiral on the screen).
That program worked fine in DOS though...

After PortixOS would boot in protected mode, I initalize the FPU with this:

Code: Select all

feni
	fclex
	fwait
	finit
	fstcw word[TempW]
	mov ax,TempW
        and ax,3FFh
        mov [TempW],ax
	fldcw word[TempW]
	ret

TempW dw 0
This wouldn't generate a exception. That CLI and STI in the code are only for debugging, I thought that i need to disable IRQs or something (I read that Bochs will fire IRQ 13 when this exception arise).

This seems a harder nut to crack... Should I after every calls of round(); call finit?
Thanks for help.

//EDIT: The "MSDOS compatibility exception" will arise only in the second fwait, fld, fist and the last fldcw (the 2nd part of my code). Other code that works with FPU doesn't generate this exception, for example
y := MidY + round(Phase2*cos(Phase1)/1.2);
when counting cosine of Phase1 and dividing it by 1.2, it wont generate this exception:
(disassembly)
fcos
fld qword ptr ss:[ebp+0xffffffe8]
fld qword ptr ss:[ebp+0xfffffff0]
fmulp st(1), st(0)
fld tbyte ptr ds:0x401b59
fdivp st(1), st(0)
- this works fine.

Regards
inflater

Re: Floating-point exception in pascal

Posted: Sun Aug 19, 2007 4:29 am
by binutils
inflater wrote: 01236716631i[CPU0 ] math_abort: MSDOS compatibility FPU exception
And this is right in the instrunction "fwait", right before the fldcw. And after fwait, every floating point instruction will fail and Bochs will generate very big log with all this. I wonder why this isn't called right on the first FPU instruction, always it would start after some calls (program is computing circles to draw a color spiral on the screen).
That program worked fine in DOS though...
What is your Bochs version? it looks like Bochs has bug for Floating-point, IMHO.

(FYI, i don't even know pascal programming language.)

Posted: Sun Aug 19, 2007 4:40 am
by inflater
binutils wrote:What is your Bochs version? it looks like Bochs has bug for Floating-point, IMHO.
2.3, the latest Win32 binary. I think I have bug in my code because it refuses to work on QEMU and even physical hardware :( On QEMU it will automatically exit (neither key was pressed or not), and real HW - freeze. :cry:

Any post will be appreciated! :)

Regards
inflater

Posted: Sun Aug 19, 2007 4:53 am
by binutils

Posted: Mon Aug 20, 2007 3:09 am
by Combuster
Read: Intel 1, ch 7.7.3. In essence you should at the very least set the native error handling bit if you want to get done with it the easy way. (CR0.NE -> 1)

It is not a bug in bochs.

Posted: Mon Aug 20, 2007 8:44 am
by inflater
Read: Intel 1, ch 7.7.3 (...) CR0.NE -> 1
Already tried this. INT 7 after first FPU instruction, which was weird because I did not set up the EM flag.

The problem was fixed by adding FINIT before every pascal fpu procedure. My dev PC worked fine without it (well almost), but Bochs and my old testbed didn't. :)

I'm sorry for too much posts by the same author... :(

inflater

Posted: Mon Aug 20, 2007 3:20 pm
by Combuster
inflater wrote:
Read: Intel 1, ch 7.7.3 (...) CR0.NE -> 1
Already tried this. INT 7 after first FPU instruction, which was weird because I did not set up the EM flag.
If you looked at the possible causes of an int 7 (Intel 3 Ch 5.12, Coprocessor not available), you'll notice three options:
1. CR0.EM is set. Obviously, it should be clear whenever you have a FPU onboard and set when one isn't present. CPUID will tell you wether one is installed, and you can try some manual probing when CPUID isn't available. If you can't bother with 386s and 486s, just clear it to be sure.

2. CR0.TS is set. This is most likely the cause. The processor will set TS whenever you change tasks. Subsequent FPU accesses will generate exceptions until the bit is cleared. Adding a CLTS instruction will fix it.

3. CR0.TS and CR0.MP are set, and a fpu wait instruction is executed. Again, use CLTS

The only reason you wouldn't be getting errors without NE is that those errors are routed via the chipset. Enabling NE gives far more predictable behaviour. The so-called MSDOS compatibility mode is IMHO plain ugly