I notice that, for some reason, various applications that support the 80286(Windows 3.0, Day of the Tentacle) crash for no obvious reason. They suddenly start executing at wrong locations for some reason. There shouldn't be any IRQ conflicts that are causing this. The BIOS starts booting with almost no problems (other than the CMOS containing uninitialized settings, 601 Diskette Error due to the Floppy Disk Controller not being accurate enough for it, 301 Keyboard error due to not accurate enough Keyboard emulation). Otherwise, pressing F1 makes it continue booting correctly. Sound Blaster 2.0 drivers and himem load without problems. The trouble starts after the Dos prompt is shown.
- When I try to run Day of the Tentacle, the hard drive has problems writing to it to save the settings. When starting it with Dosbox-configured settings, it gives me a black screen, with the Sound Blaster spewing out some strange sound continuously. https://www.dropbox.com/s/w8vcw6fbmvaxbbr/rec … ing_25.wav?dl=0
- When I try to boot Windows 3.0(which boots without problems on the 80(1)86 emulation), it crashes into an infinite loop after showing the windows logo.
- When I try to open edit(MS-DOS editor), it loads files correctly, but saving them back to disk causes the file to be loaded with a long stream consisting of the first two characters in the file(DE, which is the first row containing a DEVICE= setting).
Since the IBM PC XT emulates without problems, this must be an 80286+ or AT-specific problem, but I don't know what causes it. Anyone has a clue why the software won't just work correctly?
1) When Win3.0 worked with 80186 did that work in AT or XT configuration (8042 vs 8255 and 1 vs 2 8259s) ?
2) When Win3.0 worked with 80186 did that use same bios as with 80286?
3) Did you try to have a working config with 80186 that runs Win3.0 properly and ONLY replace the CPU with 80286. Does that work?
4) Search for WHICHCPU.EXE and run it in both 80286 and 8086. What CPU does it tell you have. Alternatively you can use CHECKIT. The key is to find out if the CPU that you are using is properly detected.
5) Do you have any program that correctly execute ENTER/LEAVE ? If you screw up somehow the stack in those instructions you will end up executing in the bushes.
6) It could be IRQ related. Disable all the devices like Sound Blaster. Have just a bear empty system with 1Mb of RAM. No HIMEM.SYS. Use it with 80826 and run edit.exe.
7) Since edit has issues with writing could be it be that there is a bug in your IDE emulator and AT configuration (since the IRQ might be different once you have 2 8259s)
1. The test were done using XT 8086 and AT 80286 emulation.
2. Running Windows 3.0 on the 80186 XT configuration (Turbo XT BIOS v3.0) makes Windows 3.0 boot correctly. Then, once displaying the program manager and main group items, the screen gets filled with strange coloured lines and the OS hangs(including the mouse, which responds correctly before the program manager starts up).
3. Running Windows 3.0 on XT 80286 configuration starts windows until the screen becomes blue instead of red, then hangs completely.
(Above 3 tests were done with all hardware enabled, with the hard disk being read-only protected)
I've ran checkit on all 8 and 16-bit (except 286, which is 16-bit only) bus settings:
AT 80286 with Turbo XT BIOS v3.0 won't boot (keyboard won't respond and XT-IDE Universal BIOS(AT) hangs directly after Master/Slave detection).
The AT uses 6144KB of RAM, as detected by the AT BIOS. Using the AT BIOS instead of the Turbo XT BIOS on the AT makes the hard disk work correctly again, and boot into MS-DOS(Loaded drivers: Sound Blaster 2.0 drivers, Himem, LT-EMM drivers(doesn't detect)), CuteMouse(Detects mouse at COM1 03F8h/IRQ4 in Microsoft Mouse mode).
Running the System Board test on CheckIt Diagnostics gives the following result:
4. WhichCPU finds:
8088 on 8086 emulation.
8088 on 8088 emulation.
80188 on NEC V30(Actually 80186) emulation.
80188 on NEC V20(Actually 80188) emulation.
80286 on 80286 emulation.
80286 on 80286(8-bit address bus) emulation.
5. I don't know of any such program that executes ENTER/LEAVE and isn't for a 80286+ CPU. Do you know any?
My ENTER/LEAVE instruction emulation:
1extern byte ENTER_L; //Level value of the ENTER instruction! 2void CPU186_OPC8() 3{ 4 word temp16; //ENTER Iw,Ib 5 word stacksize = immw; 6 byte nestlev = immb; 7 debugger_setcommand("ENTER %04X,%02X",stacksize,nestlev); 8 if (checkStackAccess(1+(nestlev?(nestlev&0x1F):0),1,0)) return; //Abort on error! 9 ENTER_L = nestlev; //Set the nesting level used! 10 CPU_PUSH16(®_BP); 11 word frametemp = REG_SP; 12 if (nestlev) 13 { 14 nestlev &= 0x1F; //MOD 32! 15 for (temp16=1; temp16<nestlev; temp16++) 16 { 17 REG_BP -= 2; //Push BP to the next size of BP! 18 CPU_PUSH16(®_BP); 19 } 20 CPU_PUSH16(®_SP); 21 } 22 REG_BP = frametemp; 23 24 if (CPU_StackAddress_size[activeCPU]) //32-bit size? 25 { 26 REG_ESP -= stacksize; //Zero extend! 27 } 28 else //--? 29 { 30 REG_SP -= stacksize; 31 } 32} 33void CPU186_OPC9() 34{ 35 debugger_setcommand("LEAVE"); 36 if (checkStackAccess(1,0,0)) return; //Abort on fault! 37 REG_SP = REG_BP; //LEAVE 38 REG_BP = CPU_POP16(); 39}
The IDE controllers are connected to the IR14(Primary) and IR15(Secondary) lines. The primary controller usually contain the hard disks emulated(2 harddisks max), while the CD-ROM is emulated on the secondary controller when the first contains hard disks(they move to the primary controllers instead when no hard disk is emulated). On the XT they're on the IR5 line(which is shared with the LPT3(if present) and Sound Blaster card(which should theoretically be able to share, since they have an interrupt identification register).
Edit: Just tried the minimum configuration of UniPCemu's AT configuration:
1IR0: PIT0 2IR1: PS/2(AT+) or IBM compatible keyboard 3IR2 (S)VGA vretrace(when enabled in vertical retrace register) 4IR4 UART port 1(XT&AT serial mouse) 5IR6 FDC(Floppy) 6IR7 LPT1(Connected Sound Source, base port 378) 7IR8 RTC(AT+) 8IR14 ATA(AT+) 9IR15 ATA(AT+)
Tried edit.com, says disk not ready. When terminating the application(file - exit), it tells me:
1Invalid COMMAND.COM 2 3Cannot load COMMAND, system halted
Inspection of the harddisk shows it's changed, with seemingly corrupt data in the last-written new sector(Simple new "test.txt" saved in the root directory, with "test" in it's contents.
The XT configuration has much the same IRQs, but it overlaps some because there are limited IR lines.
XT configuration:
10 PIT0 21 IBM compatible keyboard 32 (S)VGA vretrace(when enabled in vertical retrace register), MPU-401*(XT only) 43 UART port 2&4(Unused) 54 UART port 1(XT&AT serial mouse)&3(Unused) 65 ATA**(XT only), LPT3(Unused, base port 3BC), Sound Blaster* 76 FDC(Floppy), LPT2(Unused, base port 278) 87 LPT1(Connected Sound Source, base port 378)
AT configuration:
10 PIT0 21 PS/2(AT+) keyboard 32 (S)VGA vretrace(when enabled in vertical retrace register) 43 UART port 2&4(Unused) 54 UART port 1(XT&AT serial mouse)&3(Unused) 65 LPT3(Unused, base port 3BC), Sound Blaster* 76 FDC(Floppy), LPT2(Unused, base port 278) 87 LPT1(Connected Sound Source, base port 378) 98 RTC(AT+) 109 MPU-401*(AT+) 1110 1211 1312 PS/2 mouse(PS/2+) 1413 1514 Primary ATA**(AT+) 1615 Secondary ATA**(AT+)
* hardware only applied when enabled in the settings
** enabled for hard disk(primary) and cd-rom(secondary(which shift to primary without hard disks)
There's also a big difference between the XT and AT XT-IDE BIOSes(mainly usage of 80186+ instructions on the AT variant). Windows 3.0 shouldn't run using it's normal configuration on an XT 808X, since the VGA drivers require a 80186+ in order to run(new commands are required).
Edit: Booting the disk image again after the fatal error of the COMMAND.COM interpreter not found, the hard disk becomes unbootable while saying the normal unbootable disk message(blah blah, press any key to retry/reboot).
Edit: Upon closer inspection with vbindiff, I notice that the boot sector is utterly destroyed, everying after IO(of the IO.SYS root directory entry) is filled with "49 4F" entries(hexdecimal values). Immediately following is a sector with data starting with E9 35 01(looking further it seems to be the boot sector, which still is intact). That seems to be all that's modified in the disk image.
But on an AT, a device cannot trigger IRQ2 in hardware because it is the cascade for the second PIC, and triggering IRQ9 will execute the IRQ9 vector and that will in turn call INT 0x0A as if it was triggered from IRQ2 (because the XT's ISA IRQ2 signal is IRQ9 on AT ISA).
Although that probably isn't the problem, as the VGA Vretrace interrupt isn't enabled by software by clearing the vertical retrace end register bit 5 and setting bit 4?
Edit: Just confirmed that the VGA isn't causing it by moving it to IR9(Just like MPU-401) on AT architecture. The disk not ready message in edit.com still appears.
This really sounds like you have an IDE/ATA issue. Probably triggered by running in AT mode (since I presume your XT IDE works fine). Since you saw corruption at write it is not a great stretch of imagination to think that you might have corruption on read therefore you can read bad code and crash in some programs.
Especially the fact that the boot sector (and the following sectors containing IO.SYS) is destroyed it means that some rogue writes were issued. 49 4f is ascii for IO (maybe trying to write "IO" over and over again). Try to log your write commands for IDE/ATA and run edit.exe again and see what is happening. And more specifically what is causing those writes.
I've just updated the ENTER instruction behaviour to create a (hopefully) better stack:
1 void CPU186_OPC8() 2{ 3 word temp16; //ENTER Iw,Ib 4 word stacksize = immw; 5 byte nestlev = immb; 6 debugger_setcommand("ENTER %04X,%02X",stacksize,nestlev); 7 if (checkStackAccess(1+(nestlev?(nestlev&0x1F):0),1,0)) return; //Abort on error! 8 ENTER_L = nestlev; //Set the nesting level used! 9 //according to http://www.felixcloutier.com/x86/ENTER.html 10 CPU_PUSH16(®_BP); 11 word frametemp = REG_SP; 12 nestlev &= 0x1F; //MOD 32! 13 if (nestlev) 14 15 { 16 if (nestlev>1) 17 { 18 for (temp16=1; temp16<nestlev; temp16++) 19 { 20 REG_BP -= 2; //Push BP to the next size of BP! 21 CPU_PUSH16(®_BP); 22 } 23 } 24 CPU_PUSH16(&frametemp); //Felixcloutier.com says frametemp, fake86 says Sp? 25 } 26 27 REG_BP = frametemp; 28 REG_SP -= stacksize; //Substract: the stack size is data after the buffer created, not immediately at the params. 29}
The main difference with fake86 being that instead of pushing SP after the frame, the frametemp is stored on the stack instead. Also instead of setting SP to add the first(word) parameter to the start of the frame(thus including the frame createn to the stack size specified), according to the documentation, it's added to the bottom of the window createn(so SP is actually decremented by up to (2*(1(BP) + nestlvl(Actual BP decrements and original frameptr)) + stacksize) instead. Since the stack should not overlap the window created.
Is this new behaviour correct(meaning fake86 has a huge bug there?
Anyone? Jepael? Reenigne? Vladstamate?
Edit: Also, the PUSH SP on the 80286+ vs 8086 oddity is applied here too. Is that correct(In fact, all CPU_PUSH16(®_SP) do this, that's the whole reason it's using a pointer instead of a simple value)? Or is the 80286 just handling it like a 80(1)86?
Last edited by superfury on 2017-01-07, 02:06. Edited 1 time in total.
I've just found a little 'bug' in my 80186+ OUTSB/W instructions: it was using SI to read bytes/words from memory, but increasing DI instead of SI afterwards, thus causing the wrong data(repeated first byte/word of the block/sector) to be outputted to the hard disk controller.
Edit: EDIT.COM now properly saves and loads a test.txt file (With contents Test file):D
I've just found a little 'bug' in my 80186+ OUTSB/W instructions: it was using SI to read bytes/words from memory, but increasing DI instead of SI afterwards, thus causing the wrong data(repeated first byte/word of the block/sector) to be outputted to the hard disk controller.
Edit: EDIT.COM now properly saves and loads a test.txt file (With contents Test file):D
YAY! I love it when I find bugs like this because it means a small code change fixes a lot of programs ran in emulation 😀
One little question about ENTER though: are all values pushed on the stack pointers(SP values) which point to the parent's stack? Currently it contains the values of BP-2, BP-4, BP-6 etc, instead of the values at SS:[BP-2], SS:[BP-4],SS:[BP-6] etc, thus they're actually pointers into the parent stack. Is that correct? Or are those values actually pushed instead of just pointing to it? Are they thus pointers to pointers?
1extern byte ENTER_L; //Level value of the ENTER instruction! 2void CPU186_OPC8() 3{ 4 word temp16; //ENTER Iw,Ib 5 word stacksize = immw; 6 byte nestlev = immb; 7 word bpdata; 8 debugger_setcommand("ENTER %04X,%02X",stacksize,nestlev); 9 nestlev &= 0x1F; //MOD 32! 10 if (checkStackAccess(1+nestlev,1,0)) return; //Abort on error! 11 if (checkENTERStackAccess((nestlev>1)?(nestlev-1):0,0)) return; //Abort on error! 12 ENTER_L = nestlev; //Set the nesting level used! 13 //according to http://www.felixcloutier.com/x86/ENTER.html 14 CPU_PUSH16(®_BP); 15 word frametemp = REG_SP; 16 if (nestlev) 17 { 18 for (temp16=1; temp16<nestlev; ++temp16) 19 { 20 REG_BP -= 2; //Push BP to the next size of BP! 21 bpdata = MMU_rw(CPU_SEGMENT_SS,REG_SS,REG_BP,0); //Read the value to copy. 22 CPU_PUSH16(&bpdata); 23 } 24 CPU_PUSH16(&frametemp); //Felixcloutier.com says frametemp, fake86 says Sp(incorrect). 25 } 26 27 REG_BP = frametemp; 28 REG_SP -= stacksize; //Substract: the stack size is data after the buffer created, not immediately at the params. 29}
Is this more correct? It copies the pointer(s) from the source stack to the destination window.
This is not quite correct. The CPU tries to push just bp first, regardless of the nesting level, and aborts on failure.
It remembers the sp value after that push.
Then it loops and pushes, and it might fail during the loop, but some things will be on the stack at that time.
It pushes the remembered sp value if required.
Then it sets bp to the remembered sp value, and finally adjusts sp according to the stack size.
The CPU tries to push just bp first, regardless of the nesting level, and aborts on failure.
That's done at the CPU_PUSH16(®_BP); line at the start?
peterferrie wrote:
It remembers the sp value after that push.
That's the frametemp variable being loaded with initialization? (word frametemp = REG_SP;)
peterferrie wrote:
Then it loops and pushes, and it might fail during the loop, but some things will be on the stack at that time.
So if an stack exception or page protection exception occurs it leaves the stack(and the SP/BP registers) in an inconsistent state? Isn't this check supposed to be done before executing the entire instruction to prevent inconsistent states? Or is this a 80286-specific CPU bug? Also does it push the pointers(BP register itself is pushed) as in fake86, or does it push the word value the BP register points to (word at address SS:[BP-2], SS:[BP-4], SS:[BP-6] etc. for as many nesting levels used(minus one))?
peterferrie wrote:
It pushes the remembered sp value if required.
That's the CPU_PUSH16(&frametemp); line?
peterferrie wrote:
Then it sets bp to the remembered sp value, and finally adjusts sp according to the stack size.
That's the two last lines of the handling? REG_BP = frametemp; REG_SP -= stacksize; ?
The CPU tries to push just bp first, regardless of the nesting level, and aborts on failure.
That's done at the CPU_PUSH16(®_BP); line at the start?
Yes, but you have a check before that which needs to go away.
superfury wrote:
peterferrie wrote:
It remembers the sp value after that push.
That's the frametemp variable being loaded with initialization? (word frametemp = REG_SP;)
Yes, that part is correct.
superfury wrote:
peterferrie wrote:
Then it loops and pushes, and it might fail during the loop, but some things will be on the stack at that time.
So if an stack exception or page protection exception occurs it leaves the stack(and the SP/BP registers) in an inconsistent state? Isn't this check supposed to be done before executing the entire instruction to prevent inconsistent states? Or is this a 80286-specific CPU bug? Also does it push the pointers(BP register itself is pushed) as in fake86, or does it push the word value the BP register points to (word at address SS:[BP-2], SS:[BP-4], SS:[BP-6] etc. for as many nesting levels used(minus one))?
It pushes the memory that bp points to [bp-xx]. It's intended to save the contents of the earlier frames.
Yes, the stack will be in an inconsistent state if an exception occurs in the middle. The hardware (at least up to 486) doesn't check the whole thing first.
superfury wrote:That's the CPU_PUSH16(&frametemp); line? […] Show full quote
peterferrie wrote:
It pushes the remembered sp value if required.
That's the CPU_PUSH16(&frametemp); line?
peterferrie wrote:
Then it sets bp to the remembered sp value, and finally adjusts sp according to the stack size.
That's the two last lines of the handling? REG_BP = frametemp; REG_SP -= stacksize; ?
Then it loops and pushes, and it might fail during the loop, but some things will be on the stack at that time.
So if an stack exception or page protection exception occurs it leaves the stack(and the SP/BP registers) in an inconsistent state? Isn't this check supposed to be done before executing the entire instruction to prevent inconsistent states? Or is this a 80286-specific CPU bug? Also does it push the pointers(BP register itself is pushed) as in fake86, or does it push the word value the BP register points to (word at address SS:[BP-2], SS:[BP-4], SS:[BP-6] etc. for as many nesting levels used(minus one))?
It pushes the memory that bp points to [bp-xx]. It's intended to save the contents of the earlier frames.
Yes, the stack will be in an inconsistent state if an exception occurs in the middle. The hardware (at least up to 486) doesn't check the whole thing first.
So the data on the stack is in an inconsistent state(SP and the data on the stack). What about the BP register? Is it already partially decreased in that case? Or is the value added to BP(xx) kept inside some intermediate register for usage, with the BP register being updated afterwards(when all pushes succeed)?
Edit: This is my modified version, based on your comments. Is this correct?
1extern byte ENTER_L; //Level value of the ENTER instruction! 2void CPU186_OPC8() 3{ 4 word temp16; //ENTER Iw,Ib 5 word stacksize = immw; 6 byte nestlev = immb; 7 word bpdata; 8 debugger_setcommand("ENTER %04X,%02X",stacksize,nestlev); 9 nestlev &= 0x1F; //MOD 32! 10 if (EMULATED_CPU>CPU_80486) //We don't check it all before, but during the execution on 486- processors! 11 { 12 if (checkStackAccess(1+nestlev,1,0)) return; //Abort on error! 13 if (checkENTERStackAccess((nestlev>1)?(nestlev-1):0,0)) return; //Abort on error! 14 } 15 ENTER_L = nestlev; //Set the nesting level used! 16 //according to http://www.felixcloutier.com/x86/ENTER.html 17 if (EMULATED_CPU<=CPU_80486) //We don't check it all before, but during the execution on 486- processors! 18 { 19 if (checkStackAccess(1,1,0)) return; //Abort on error! 20 } 21 CPU_PUSH16(®_BP); 22 word frametemp = REG_SP; 23 if (nestlev) 24 { 25 for (temp16=1; temp16<nestlev; ++temp16) 26 { 27 if (EMULATED_CPU<=CPU_80486) //We don't check it all before, but during the execution on 486- processors! 28 { 29 if (checkENTERStackAccess(1,0)) return; //Abort on error! 30 } 31 REG_BP -= 2; //Push BP to the next size of BP! 32 bpdata = MMU_rw(CPU_SEGMENT_SS,REG_SS,REG_BP,0); //Read the value to copy. 33 if (EMULATED_CPU<=CPU_80486) //We don't check it all before, but during the execution on 486- processors! 34 { 35 if (checkStackAccess(1,1,0)) return; //Abort on error! 36 } 37 CPU_PUSH16(&bpdata); 38 } 39 if (EMULATED_CPU<=CPU_80486) //We don't check it all before, but during the execution on 486- processors! 40 { 41 if (checkStackAccess(1,1,0)) return; //Abort on error! 42 } 43 CPU_PUSH16(&frametemp); //Felixcloutier.com says frametemp, fake86 says Sp(incorrect). 44 } 45 46 REG_BP = frametemp; 47 REG_SP -= stacksize; //Substract: the stack size is data after the buffer created, not immediately at the params. 48}