Code: Select all
math_abort: MSDOS compatibility FPU exception
Code: Select all
math_abort: MSDOS compatibility FPU exception
I haven't done either of those and it now works, though I've yet to see what happens when I do something more complex than just loading a number into the FPU and back to a different memory location. I'll have to look at CR0 to see what those bits are set to at the moment...Gigasoft wrote:You have to clear CR0.EM (bit 2), and you should also set NE (bit 5) to turn off MS-DOS compatibility mode.
Famous last words.DavidCooper wrote:Edit: seems to be fine anyway...
Well, I've now checked to see what these bits actually do. Bit 2 simply tells you if there's an FPU or not, so there's no point in changing it, but it'll obviously be useful for finding out if a 386 or 486 has one. Bit 5 seems to be for enabling exceptions, so I can probably just leave it clear as I intend to avoid generating errors to begin with, but I'll have to try it out and see what happens if I divide by zero, after creating an interrupt routine to handle that. I think from memory that's the same interrupt as the system timer, so that could complify things a bit.Solar wrote:Famous last words.
Bit 9 of CR4 is only for SSE and has nothing to do with FPU.DavidCooper wrote:It's working now after adding this code: F 20 D8 (CR4 into EAX) D 0 2 0 0 (set bit 9) F 22 D8 (EAX into CR4)
That's recommended (for OS initialisation code).DavidCooper wrote:DB E3 (fninit)
For "32-bit FPUs" (80386 and later), the FSETPM instruction is treated as a NOP - it has no effect. For 80287 it mattered (it effected loads/stores done by the FPU), and for older FPUs it wasn't supported. Your code is probably "80386 or later" anyway, so the "FSETPM" instruction is a waste of time.DavidCooper wrote:DB E4 (FPU instruction to set protected mode - probably unnecessary).
Bit 2 doesn't tell you if there's an FPU or not. It determines how the WAIT instruction interacts with hardware task switching.DavidCooper wrote:Well, I've now checked to see what these bits actually do. Bit 2 simply tells you if there's an FPU or not, so there's no point in changing it, but it'll obviously be useful for finding out if a 386 or 486 has one.
Um, no.DavidCooper wrote:Bit 5 seems to be for enabling exceptions, so I can probably just leave it clear as I intend to avoid generating errors to begin with, but I'll have to try it out and see what happens if I divide by zero, after creating an interrupt routine to handle that. I think from memory that's the same interrupt as the system timer, so that could complify things a bit.
I was going by http://wiki.osdev.org/FPU, and this bit in particular:-Brendan wrote:I'm not sure if you're reading every third word of the manual and then filling in the blanks with fan fiction or something, but...
Bit 9 of CR4 is only for SSE and has nothing to do with FPU.DavidCooper wrote:It's working now after adding this code: F 20 D8 (CR4 into EAX) D 0 2 0 0 (set bit 9) F 22 D8 (EAX into CR4)
It seems that that information is wrong (the OSDev wiki being a hotbed of fan fiction), but following it did at the time appear to make the FPU start to function, though in reality the real cure was simply the fninit instruction (DB E3), which I added at the same time after finding the correct hex values for it on a x86 instruction set website - I previously had the wrong values for those two bytes due to an error in a book borrowed from the library years ago (not sure which, but it might have been Barry B. Brey's Programming the 80286, 80386, 80486 and Pentium-Based Personal Computer, or more likely Peter Norton's Programmer's Guide to the IBM PC - the notes I made from those two books are usually the first place I look for things). I'm not even sure I actually made any change to CR4 as I can't find any information on the correct rrr value to select it, so I may have changed bit 9 in CR3 instead - no one provides comprehensive lists of machine code instructions in hex form, so I sometimes have to guess what they are and use a bit of trial and error. (It's ridiculous, but it seems that I'll have to get hold of an assembler and spend weeks trying to work out how to use it just to use it to get the hex values of a handful of rare instructions.)Setting the 9th bit (OSFXSR) in the CR4 tells the CPU that we intend on using the FXSAVE, FXRSTOR, and SSEx instructions. If this bit is not set, a #UD exception will be generated on use of the FPU or any SSE instructions.
It's harmless to use it though. I thought it might be necessary as information I copied from one of those books years ago suggested it might matter on a 386 and perhaps on a 486, though that may well be wrong.For "32-bit FPUs" (80386 and later), the FSETPM instruction is treated as a NOP - it has no effect. For 80287 it mattered (it effected loads/stores done by the FPU), and for older FPUs it wasn't supported. Your code is probably "80386 or later" anyway, so the "FSETPM" instruction is a waste of time.
The fan-fiction source I used for that was http://en.wikipedia.org/wiki/Control_register, the relevant part being this:-Bit 2 doesn't tell you if there's an FPU or not. It determines how the WAIT instruction interacts with hardware task switching.
I know that Wikipedia isn't entirely reliable, but if you don't google for things you tend to get attacked by people here, so there's a pressure on everyone just to experiment with unreliable data rather than daring to ask any experts here if they already know of a fully reliable source that they could maybe point to.2 EM Emulation If set, no x87 floating point unit present, if clear, x87 FPU present
Um, indeed no. In this case I was going by the same Wikipedia page where it said:-Um, no.DavidCooper wrote:Bit 5 seems to be for enabling exceptions, so I can probably just leave it clear as I intend to avoid generating errors to begin with, but I'll have to try it out and see what happens if I divide by zero, after creating an interrupt routine to handle that. I think from memory that's the same interrupt as the system timer, so that could complify things a bit.
but I didn't understand it (as it doesn't appear to make a real distinction of any kind), so I guessed at its meaning - I was in a hurry and it wasn't immediately important - I was just happy to have got the FPU to speak to me at last and was keen to start experimenting with it. I also mis-remembered where the system timer interrupt IDT entry is too as it's 8 entries further on from the divide by zero exception, and now it isn't clear to me whether the divide by zero exception is even used by the FPU at all.5 NE Numeric error Enable internal x87 floating point error reporting when set, else enables PC style x87 error detection
That makes a lot of sense. I'm still trying to see through the fog here, but it's beginning to look as if all the FPU exceptions trigger an exception using the 17th IDT entry (vector 16) if the NE flag is set. The divide by zero (vector 0) and overflow (vector 4) which I had assumed could be triggered by the FPU are, I now suspect, restricted to integer arithmetic done in the main processor, but I've never found any source of information that spells this kind of thing out (unless it's cunningly hidden deep within tons of other information that I don't need).Originally, when there's a floating point error the FPU (in a separate chip) used IRQ13 and the PIC chip to tell the CPU that an error occurred. This was stupid (causes race conditions, etc) and fails completely in systems with multiple CPUs. For CPUs that have built-in FPUs (80486 and later) it makes far more sense for a floating point error to be treated like any other error and cause an exception instead, where IRQs and the PIC chips aren't involved at all. However, Intel couldn't suddenly change how floating point errors are handled because that would've caused backward compatibility problems for old software (e.g. DOS); so they added the NE flag in CR0. If this flag is set then floating point errors trigger an exception, and if the flag is clear then floating point errors get delivered as IRQ13 instead.
So I really need to enable them all, but start with them disabled and enable just one at a time while I try to write code to handle it.In general (for applications), "precision", "underflow" and "denormal operand" errors can be safely disabled (unless you care a lot about the accuracy of calculations); and all other errors indicate serious problems with your software (and should therefore be enabled).
Well, no. If I simply substitute "or" with "for", or substitute "the" with "these", it is factually accurate, and you should have realized something was amiss when the first and second sentence are contradicting each other to some extent.DavidCooper wrote:I was going by http://wiki.osdev.org/FPU, and this bit in particular:-It seems that that information is wrong (the OSDev wiki being a hotbed of fan fiction)Setting the 9th bit (OSFXSR) in the CR4 tells the CPU that we intend on using the FXSAVE, FXRSTOR, and SSEx instructions. If this bit is not set, a #UD exception will be generated on use of the FPU or any SSE instructions.
I have copies of Intel manuals which are not clear about the hex of some instructions, and I'm fed up of trawling through different manuals looking for the ones that might. I found finit/fninit by doing a search just as you did - that wasn't a problem, and I did that when I realised the info in the book had given me values for finit that were the same as another instruction which couldn't possibly share them. It isn't nearly so easy to find the second byte value for instructions like mov eax,CR4 , though it doesn't look as if I need it at the moment. I guessed years ago that 192 was the right value for CR0, but I don't know if I should add three lots of 8 to that or four to get the value for accessing CR4. Anyway, looking at the source code for nasm might be a viable solution, though I don't know how easy it is to read through. I suspect it would still be easier to download an assembler and try to find out how to get it to convert mnemonics into hex. Would you recommend NASM for that?berkus wrote:Mmm, not true. Afaik Intel manuals have the hex form of the insns as well. Or you could look them up in nasm sources as a nifty table.DavidCooper wrote:no one provides comprehensive lists of machine code instructions in hex form,
If you already know how things work, turning "or" into "for" might seem obvious, but it wasn't to me. I still can't work out which "the" to turn into "these" - the only one that would survive grammatically would make no real change to the meaning. I'm also failing to pick out the contradiction due, no doubt, to lack of some knowledge that probably doesn't relate to what I need to do with the FPU. The difficulty is always trying to gain enough knowledge to be able to recognise whether information is correct or not, and yet you have to acquire this expertise from sources containing all manner of errors (and which tend to assume tons of knowledge which you don't yet have and often don't need at that stage). We all come into this by different routes and have different errors and holes in our knowledge (and some of us with more than others), but that's where a forum helps as people can put each other right. So, thanks again to the people in this thread (and others) for steering me in the right direction. Your help is much appreciated.Combuster wrote:Well, no. If I simply substitute "or" with "for", or substitute "the" with "these", it is factually accurate, and you should have realized something was amiss when the first and second sentence are contradicting each other to some extent.DavidCooper wrote:I was going by http://wiki.osdev.org/FPU, and this bit in particular:-It seems that that information is wrong (the OSDev wiki being a hotbed of fan fiction)Setting the 9th bit (OSFXSR) in the CR4 tells the CPU that we intend on using the FXSAVE, FXRSTOR, and SSEx instructions. If this bit is not set, a #UD exception will be generated on use of the FPU or any SSE instructions.
That is truly excellent - it's rare to find anything spelt out so clearly. Thank you.Combuster wrote:Also did some updates to the FPU page to avoid further confusion.
My apologies - I was (incorrectly) thinking of the MP flag and not the EM flag when I wrote that.DavidCooper wrote:The fan-fiction source I used for that was http://en.wikipedia.org/wiki/Control_register, the relevant part being this:-Bit 2 doesn't tell you if there's an FPU or not. It determines how the WAIT instruction interacts with hardware task switching.
Just use NASM to convert the instructions into machine code and then use "hexdump" to find out what the opcodes are. Better yet, just use NASM.DavidCooper wrote:I have copies of Intel manuals which are not clear about the hex of some instructions, and I'm fed up of trawling through different manuals looking for the ones that might.
I've actually just been downloading nasm and working out how to use it. I've downloaded an assembler before which took an hour to install, gave dire warnings about how it might trash my machine and then which I never managed to work out how to do anything with. By way of contrast, nasm downloaded in the blink of an eye and produced this shortly afterwards:-Brendan wrote: Just use NASM to convert the instructions into machine code and then use "hexdump" to find out what the opcodes are. Better yet, just use NASM.
Code: Select all
1 00000000 0F20C0 mov eax,cr0
2 00000003 0F20C8 mov eax,cr1
3 00000006 0F20D0 mov eax,cr2
4 00000009 0F20D8 mov eax,cr3
5 0000000C 0F20E0 mov eax,cr4
Then think again - I always point out that it's easier to program in machine code than to use assembler (so long as you have an indexing system). I'm impressed by massochists who use assembler, so from my point of view they are the ones setting their testicles on fire. As I've also said before, my original reason for wanting to program directly in machine code was that that is the most obvious way for A.I. to write its code - I see no point in it going through a mnemonic stage as it's far simpler for it to edit machine code directly in memory where it will run and miss out any unnecessary translation stages. Programming in machine code is nothing to boast about, but if you want to see me boast about something, just wait twelve months.The only reason I can think of for anyone to use machine code is as a way of seeking attention - something to brag about when among programmers. It's a bit like setting your testicles on fire at the local pub - your peers/friends will seem impressed, but it can be hard to know if they're impressed by your skills or impressed at how stupid you are, and it'd be a mistake to assume the former when it'd be the latter most of the time.