Reply 20 of 24, by UselessSoftware
superfury wrote on 2025-04-08, 21:42:Afaik (at least older) Linux should plain work without FPU instructions (and using FPU emulation by trapping those opcodes if it […]
UselessSoftware wrote on 2025-04-08, 18:09:Ah! Didn't realize that, thanks. I'll get that fixed. […]
superfury wrote on 2025-04-08, 10:45:Have you tried test386.asm yet? […]
Have you tried test386.asm yet?
Also regarding the BT* instructions, isn't the offset (based on the shr 4(16) or 5(32) bit position shifted left by one(16) or two(32)) supposed to be signed? So bits 8000h is actually byte r/m offset-2048, bit 0(as a 16-bit word read and written)?
So for R/M offset 10000h, it's at a lower address.Edit: Added a simple MS-DOS based testsuite for bit test string instruction (it tests both 16-bit and 32-bit versions on a 3 doubleword bit string in memory, with the pointer on the middle doubleword).
It will test the first doubleword (positive addresses, at the base address), then the second doubleword (base+1), then the previous doubleword (base-1).It's fully running in 16-bit MS-DOS mode, but the 32-bit addresses will use operand and address size overrides (it uses EDX for addressing easily).
In UniPCemu's current commits, it seems to run properly at least (with additional bugfixes in the emulator performed). Oddly enough, the test386.asm testsuite doesn't verify that the positive and negative ranges are functioning properly (it just tests the register version of those opcodes for some odd reason).
I found a Youtube video that seems to explain it nicely:
https://www.youtube.com/watch?v=en_7DtfT8CgAh! Didn't realize that, thanks. I'll get that fixed.
I did quickly put in a printf debug line that tells me if any BT opcodes are operating on an offset with the sign bit set but it never triggered. So that's not the cause of my current problems, but definitely still need to fix.
I did run test386 before, it runs successfully up into some of the protected mode tests that fail just because I haven't implemented a number of protections yet. I guess it's time to do those. Or comment out those tests and re-compile so it continues and get to them later.
I actually wonder if my FPU is just extremely broken and that's causing the problems. I've barely worked on it, and I do see that Linux executes a few FPU instructions as it loads. Maybe some errors there are tripping it up, I'm just not sure how much it relies on it for the boot process.
Afaik (at least older) Linux should plain work without FPU instructions (and using FPU emulation by trapping those opcodes if it's not implemented on a x87 (using a specific fault handler, enabled using a CR0 bit (EM) for opcodes D8-DFh. Those can be safely ignored (NOP except with a modr/m, no immediate) to emulate without a FPU (the OS will usually execute FNINIT and FNSTSW):
FNINIT
FNSTSW WORD PTR [FPU_STATUS]
My emulator simply does the following for example:
- FNINIT/FNSTSW: Disassemble, behave like a NOP.
- Any other FPU (D8-DF) instruction without EM set: NOP, but disassemble as an 'unimplemented FPU instruction'. Also fetch instruction ModR/M, but ignore it (to continue onwards to any next instruction).
- Any FPU instruction with EM set: trap to the OS using the emulation exception (#NM), like other CPU faults (in this case, just like #UD, except fetching modr/m for the undocumented instruction, as D8-DF instruction fetching is handled first).
In a way, it's like 0F18-0F1F, but all behaving like 0F1F, except optionally throwing an exception on execution (#NM) depending on the EM and TS bits in CR0.
I figured the old kernels shouldn't care, but they were still running a couple of FPU ops so it made me suspicious.
That's close to what I've been doing. When my CPU core is in no-FPU mode, it sets EM in CR0, moves past the ModRM byte, and does an #NM but I was doing it for every FPU op including FNINIT/FNSTSW.