VOGONS


UniPCemu's 80286 emulation bug help?

Topic actions

First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

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?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 1 of 69, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

Few questions:

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)

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 2 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

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).

323-XT_80186_crash.jpg
Filename
323-XT_80186_crash.jpg
File size
97.79 KiB
Views
1002 views
File comment
Windows 3.0 on UniPCemu's 80186 XT emulation.
File license
Fair use/fair dealing exception

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:

324-XT_8086_checkit.jpg
Filename
324-XT_8086_checkit.jpg
File size
145.95 KiB
Views
1002 views
File comment
CheckIt Diagnostics XT 8086
File license
Fair use/fair dealing exception
325-XT_8088_checkit.jpg
Filename
325-XT_8088_checkit.jpg
File size
145.95 KiB
Views
1002 views
File comment
CheckIt Diagnostics XT 8088
File license
Fair use/fair dealing exception
326-XT_80186_checkit.jpg
Filename
326-XT_80186_checkit.jpg
File size
145.7 KiB
Views
1002 views
File comment
CheckIt Diagnostics XT 80186
File license
Fair use/fair dealing exception
327-XT_80188_checkit.jpg
Filename
327-XT_80188_checkit.jpg
File size
145.7 KiB
Views
1002 views
File comment
CheckIt Diagnostics XT 80188
File license
Fair use/fair dealing exception

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 3 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++
328-XT_80286_checkit.jpg
Filename
328-XT_80286_checkit.jpg
File size
146.08 KiB
Views
1002 views
File comment
CheckIt Diagnostics XT 80286
File license
Fair use/fair dealing exception

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:

Filename
debugger_checkit_diagnostics_protectedmodetest.zip
File size
66.65 KiB
Downloads
81 downloads
File comment
80286 CheckIt! Diagnostics protected mode test hanging.
File license
Fair use/fair dealing exception

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 4 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

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:

extern byte ENTER_L; //Level value of the ENTER instruction!
void CPU186_OPC8()
{
word temp16; //ENTER Iw,Ib
word stacksize = immw;
byte nestlev = immb;
debugger_setcommand("ENTER %04X,%02X",stacksize,nestlev);
if (checkStackAccess(1+(nestlev?(nestlev&0x1F):0),1,0)) return; //Abort on error!
ENTER_L = nestlev; //Set the nesting level used!
CPU_PUSH16(&REG_BP);
word frametemp = REG_SP;
if (nestlev)
{
nestlev &= 0x1F; //MOD 32!
for (temp16=1; temp16<nestlev; temp16++)
{
REG_BP -= 2; //Push BP to the next size of BP!
CPU_PUSH16(&REG_BP);
}
CPU_PUSH16(&REG_SP);
}
REG_BP = frametemp;

if (CPU_StackAddress_size[activeCPU]) //32-bit size?
{
REG_ESP -= stacksize; //Zero extend!
}
else //--?
{
REG_SP -= stacksize;
}
}
void CPU186_OPC9()
{
debugger_setcommand("LEAVE");
if (checkStackAccess(1,0,0)) return; //Abort on fault!
REG_SP = REG_BP; //LEAVE
REG_BP = CPU_POP16();
}

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:

IR0: PIT0
IR1: PS/2(AT+) or IBM compatible keyboard
IR2 (S)VGA vretrace(when enabled in vertical retrace register)
IR4 UART port 1(XT&AT serial mouse)
IR6 FDC(Floppy)
IR7 LPT1(Connected Sound Source, base port 378)
IR8 RTC(AT+)
IR14 ATA(AT+)
IR15 ATA(AT+)

Tried edit.com, says disk not ready. When terminating the application(file - exit), it tells me:

Invalid COMMAND.COM

Cannot 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:

0 PIT0
1 IBM compatible keyboard
2 (S)VGA vretrace(when enabled in vertical retrace register), MPU-401*(XT only)
3 UART port 2&4(Unused)
4 UART port 1(XT&AT serial mouse)&3(Unused)
5 ATA**(XT only), LPT3(Unused, base port 3BC), Sound Blaster*
6 FDC(Floppy), LPT2(Unused, base port 278)
7 LPT1(Connected Sound Source, base port 378)

AT configuration:

0 PIT0
1 PS/2(AT+) keyboard
2 (S)VGA vretrace(when enabled in vertical retrace register)
3 UART port 2&4(Unused)
4 UART port 1(XT&AT serial mouse)&3(Unused)
5 LPT3(Unused, base port 3BC), Sound Blaster*
6 FDC(Floppy), LPT2(Unused, base port 278)
7 LPT1(Connected Sound Source, base port 378)
8 RTC(AT+)
9 MPU-401*(AT+)
10
11
12 PS/2 mouse(PS/2+)
13
14 Primary ATA**(AT+)
15 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.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 5 of 69, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie

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).

Reply 6 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

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.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 7 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

Is there any way to test ALL x86-16(80286 instruction set) opcodes? Are there any testsuites or test programs available?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 8 of 69, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

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.

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 9 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've just updated the ENTER instruction behaviour to create a (hopefully) better stack:

 void CPU186_OPC8()
{
word temp16; //ENTER Iw,Ib
word stacksize = immw;
byte nestlev = immb;
debugger_setcommand("ENTER %04X,%02X",stacksize,nestlev);
if (checkStackAccess(1+(nestlev?(nestlev&0x1F):0),1,0)) return; //Abort on error!
ENTER_L = nestlev; //Set the nesting level used!
//according to http://www.felixcloutier.com/x86/ENTER.html
CPU_PUSH16(&REG_BP);
word frametemp = REG_SP;
nestlev &= 0x1F; //MOD 32!
if (nestlev)

{
if (nestlev>1)
{
for (temp16=1; temp16<nestlev; temp16++)
{
REG_BP -= 2; //Push BP to the next size of BP!
CPU_PUSH16(&REG_BP);
}
}
CPU_PUSH16(&frametemp); //Felixcloutier.com says frametemp, fake86 says Sp?
}

REG_BP = frametemp;
REG_SP -= stacksize; //Substract: the stack size is data after the buffer created, not immediately at the params.
}

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(&REG_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.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 10 of 69, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

According to official AMD documentation your implementation is correct (so therefore one can assume that fake86 has a bug there).

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 11 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

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

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 12 of 69, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

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 😀

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 13 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've just tried running Day of the Tentacle on the AT 286 again. Now it crashes with a R6000 stack overflow error?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 14 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

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?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 15 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've modified the ENTER BP behaviour a bit:

extern byte ENTER_L; //Level value of the ENTER instruction!
void CPU186_OPC8()
{
word temp16; //ENTER Iw,Ib
word stacksize = immw;
byte nestlev = immb;
word bpdata;
debugger_setcommand("ENTER %04X,%02X",stacksize,nestlev);
nestlev &= 0x1F; //MOD 32!
if (checkStackAccess(1+nestlev,1,0)) return; //Abort on error!
if (checkENTERStackAccess((nestlev>1)?(nestlev-1):0,0)) return; //Abort on error!
ENTER_L = nestlev; //Set the nesting level used!
//according to http://www.felixcloutier.com/x86/ENTER.html
CPU_PUSH16(&REG_BP);
word frametemp = REG_SP;
if (nestlev)
{
for (temp16=1; temp16<nestlev; ++temp16)
{
REG_BP -= 2; //Push BP to the next size of BP!
bpdata = MMU_rw(CPU_SEGMENT_SS,REG_SS,REG_BP,0); //Read the value to copy.
CPU_PUSH16(&bpdata);
}
CPU_PUSH16(&frametemp); //Felixcloutier.com says frametemp, fake86 says Sp(incorrect).
}

REG_BP = frametemp;
REG_SP -= stacksize; //Substract: the stack size is data after the buffer created, not immediately at the params.
}

Is this more correct? It copies the pointer(s) from the source stack to the destination window.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 16 of 69, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie

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 mod check is correct.

Reply 17 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++
peterferrie wrote:

The CPU tries to push just bp first, regardless of the nesting level, and aborts on failure.

That's done at the CPU_PUSH16(&REG_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; ?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 18 of 69, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:
peterferrie wrote:

The CPU tries to push just bp first, regardless of the nesting level, and aborts on failure.

That's done at the CPU_PUSH16(&REG_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; ?

Yes, the rest is correct.

Reply 19 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++
peterferrie wrote:
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.

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?

extern byte ENTER_L; //Level value of the ENTER instruction!
void CPU186_OPC8()
{
word temp16; //ENTER Iw,Ib
word stacksize = immw;
byte nestlev = immb;
word bpdata;
debugger_setcommand("ENTER %04X,%02X",stacksize,nestlev);
nestlev &= 0x1F; //MOD 32!
if (EMULATED_CPU>CPU_80486) //We don't check it all before, but during the execution on 486- processors!
{
if (checkStackAccess(1+nestlev,1,0)) return; //Abort on error!
if (checkENTERStackAccess((nestlev>1)?(nestlev-1):0,0)) return; //Abort on error!
}
ENTER_L = nestlev; //Set the nesting level used!
//according to http://www.felixcloutier.com/x86/ENTER.html
if (EMULATED_CPU<=CPU_80486) //We don't check it all before, but during the execution on 486- processors!
{
if (checkStackAccess(1,1,0)) return; //Abort on error!
}
CPU_PUSH16(&REG_BP);
word frametemp = REG_SP;
if (nestlev)
{
for (temp16=1; temp16<nestlev; ++temp16)
{
if (EMULATED_CPU<=CPU_80486) //We don't check it all before, but during the execution on 486- processors!
{
if (checkENTERStackAccess(1,0)) return; //Abort on error!
}
REG_BP -= 2; //Push BP to the next size of BP!
bpdata = MMU_rw(CPU_SEGMENT_SS,REG_SS,REG_BP,0); //Read the value to copy.
if (EMULATED_CPU<=CPU_80486) //We don't check it all before, but during the execution on 486- processors!
{
if (checkStackAccess(1,1,0)) return; //Abort on error!
}
CPU_PUSH16(&bpdata);
}
if (EMULATED_CPU<=CPU_80486) //We don't check it all before, but during the execution on 486- processors!
{
if (checkStackAccess(1,1,0)) return; //Abort on error!
}
CPU_PUSH16(&frametemp); //Felixcloutier.com says frametemp, fake86 says Sp(incorrect).
}

REG_BP = frametemp;
REG_SP -= stacksize; //Substract: the stack size is data after the buffer created, not immediately at the params.
}

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io