VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've noticed, when running the test386.asm testsuite, that the BCD instructions have some very odd behaviour, comparing to 86box (808x: https://github.com/86Box/86Box/blob/master/src/cpu/808x.c , 286: https://github.com/86Box/86Box/blob/master/sr … u/x86_ops_bcd.h ).

It seems like various oddly mismatched things occur in the real BCD handling (according to getting the testsuite not to fail):
DAA/DAS: Only check for AL>99, never 9F. Carry cleared before and or-ed during the first correction case(borrow or carry during the add/substract). High correction case (>99h) doesn't clear carry flag.
AAA/AAS: really substracting/adding 0x106 on 286, just 6 on 808x (simulated on 286+). 808x adds 1 to AH after this operation. sign/zero/carry/overflow is from 8-bit addition/substraction operation. The resulting AX register is like it's performed the 0x106 addition/substraction instead of what the flags indicate (which seem to report what the AL+/-6 operation did).

Is this odd behaviour somehow correct on 286+ machines? Doesn't that mean that since on 808x no carry from the low byte substracting 6 into the high byte occurs, the result in AX is different on a 808x?

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

Reply 1 of 10, by GloriousCow

User metadata
Rank Oldbie
Rank
Oldbie

I have hardware-generated, per-opcode CPU tests for the 8088, 80286 and 80386 that can answer these sort of questions.

https://github.com/SingleStepTests/8088
https://github.com/SingleStepTests/80286
https://github.com/SingleStepTests/80386

The 8088/8086 does indeed have different BCD logic than the 286+.
You have been reluctant to attempt to use them so far to date, but I can only reiterate that I made them precisely for purpose of emulator validation.

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 2 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++

Still, that only tests the results, just like test386.asm does, while not explaining what the behaviour is (how the flags are updated in the ALU). In my current emulation of the 286+:
- Sign, zero, parity flag according to logic 8-bit result in AL.
- Overflow according to 8086-style result if it was 808x-style, using 8-bit addition/substraction.
- AX result like it is in 286+ style, using 16-bit addition/substraction, discarding the flags.

That's all I figured out so far.

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

Reply 3 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++

So like I actually asked, what is the real behaviour of the 286+ AAA/AAS instructions? And I don't mean what the results of certain operations are, I mean what actually happens during the flag calculations.
Especially the overflow flag, which seems to be the main thing that has to do some weird behaviour on 286, since the 16-bit addition/substraction generates different overflow flag results from 8-bit math (which isn't compatible with the 808x flags if used, test386.asm causes errors if that is done).

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

Reply 4 of 10, by GloriousCow

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote on 2026-01-08, 21:24:

So like I actually asked

Mr. Fury, nobody is obligated to answer you. If having a data set that would answer your question but requires a modicum of effort dissatisfies you, you can wait patiently for someone else to come along.

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 5 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++
GloriousCow wrote on Today, 04:41:
superfury wrote on 2026-01-08, 21:24:

So like I actually asked

Mr. Fury, nobody is obligated to answer you. If having a data set that would answer your question but requires a modicum of effort dissatisfies you, you can wait patiently for someone else to come along.

I know, just was telling that there's a difference between outputs and actual input processing to obtain said outputs. Lots of ways to calculate '5' for example, but without knowing what's actually happening you will be grasping at straws.

Anyone managed to obtain microcode yet of the 286 or newer that might explain what's happening with AAA/AAS?

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

Reply 6 of 10, by GloriousCow

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote on Today, 18:13:

Anyone managed to obtain microcode yet of the 286 or newer that might explain what's happening with AAA/AAS?

Working on that - I just sent off about 10 or so PLCC 80C286s to a lab to get stained.
We do have the 386 microcode. It's a bit difficult to decipher due to the introduction of delay slots.

Granite is a PC emulator that has passed my 80286 test suite, including all BCD flag behavior, so this is probably the best reference, currently.
https://github.com/a-mcego/granite/blob/58a1c … e/80286.h#L3061

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 7 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++

Thanks, that's exactly what I needed!

My emulator's BCD instructions are now properly passing the test386.asm tests, so it should be working correctly now, at least on the x86 instruction behaviour.
There's still x86 protected mode issues I've createn since my last app's release (of UniPCemu), but there's not much of a testsuite for that behaviour yet. I did add some extra tests for that in the test386.asm pull request I made recently. Maybe I'll add some more tests to it if I actually need it (and it should help other emulator devs too). Maybe adding some interrupt handling tests to the protected mode user-mode execution (non-V86 mode).

I'm pretty sure that the V86 mode itself is running properly in my emulator, just some protected mode issues left to work out (that were createn by my latest changes to the protected mode of course, the last release of my emulator didn't have those issues). Of course it could also be a BIU issue (since I added some things to it, like simple caches that weren't there previously to speed up emulation, as memory accesses are relatively slow in my emulator due to mapping).

Edit: Also took a look at the .moo format. It's probably reasonably easy to implement. It reminds me a lot of the RIFF chunks I've already implemented (for Soundfont parsing). Perhaps it's inspired by it?
Assuming I skip the cycle stuff, I might implement it one day in my own emulator. Of course only working with the uncompressed .moo files. I don't want to deal with compression if possible, as that will complicate my app even more.
So pretty much, load initial state (memory and 32-bit/16-bit registers), execute an instruction, compare state in the final block. Fail if the final block state isn't matched (for memory and registers). And of course EXCP for interrupts and exceptions caused.

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

Reply 8 of 10, by GloriousCow

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote on Today, 20:37:

Edit: Also took a look at the .moo format. It's probably reasonably easy to implement. It reminds me a lot of the RIFF chunks I've already implemented (for Soundfont parsing). Perhaps it's inspired by it?

Yes, I've always appreciated chunked formats, they make parsing and extending the format super easy.

There's an example C++ single-header parser here, btw:
https://github.com/dbalsom/moo/tree/main/cpp

superfury wrote on Today, 20:37:

Assuming I skip the cycle stuff, I might implement it one day in my own emulator. Of course only working with the uncompressed .moo files. I don't want to deal with compression if possible, as that will complicate my app even more.

Entirely up to you of course, but if you link with zlib then you can define MOO_USE_ZLIB and mooreader.h will handle decompressing them for you.

You may also find this a good reference, as this is a C++ emulator that uses mooreader.h to run the 8088 test suite:
https://github.com/dbalsom/XTCE-Blue/blob/055 … tRunner.cpp#L95

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 10 of 10, by GloriousCow

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote on 32 minutes ago:

What about other memory? For example, if a test specifies initial and final memory addresses 0-3, what to do with addresses 4+?

It may be useful to zero out memory between each test, if you want to check that you have several 0's after the last byte address in the final state. That way you can catch over-writing bugs.
But for the most part, bytes not specified in either initial or final states were not accessed by the CPU so aren't relevant to validation.

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc