VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

I'm trying to get the flags properly implemented in UniPCemu, but the 80186(or 80286, since it expects the high 4 bits to be zeroed?) testsuite says the carry and adjust flags are incorrect?

//Addition Carry, Overflow, Adjust logic
//Tables based on http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt
//Index Bit0=sumsign, Bit1=num2sign(add or sub negated value), Bit2=num1sign(v1)
byte addoverflow[8] = {0,1,0,0,0,0,1,0};
byte suboverflow[8] = {0,0,0,1,1,0,0,0};

//Flags(Aux/Carry):
//ADD: ((op1)^(op2))^(((op1)^(result))&~((op1)^(op2)))^result
//SUB: ((op1)^(op2))^(((op1)^(result))&((op1)^(op2)))^result
//Auxiliary flag: ((op1^op2)^((op1^result)&(~(op1^op2))^result
//Auxiliary flag: ((op1)^(op2))^(((op1)^(result))&~((op1)^(op2)))^result
//borrow/carry bits
#define bcbitsa(v1,v2) (((v1)^(v2))^(((v1)^(dst))&~((v1)^(v2)))^dst)
#define bcbitss(v1,v2) (((v1)^(v2))^(((v1)^(dst))&((v1)^(v2)))^dst)

void flag_adcoa8(uint8_t v1, uint16_t add, uint16_t dst)
{
FLAGW_CF((bcbitsa((uint16_t)v1,add)>>7)&1); //Carry?
FLAGW_OF(addoverflow[((dst>>7)&1)|(((add>>6)&2))|((v1>>5)&4)]); //Overflow?
FLAGW_AF((bcbitsa((uint16_t)v1,add)&0x8)>>3); //Adjust?
}

void flag_adcoa16(uint16_t v1, uint32_t add, uint32_t dst)
{
FLAGW_CF((bcbitsa((uint32_t)v1,add)>>15)&1); //Carry?
FLAGW_OF(addoverflow[((dst>>15)&1)|(((add>>14)&2))|((v1>>13)&4)]); //Overflow?
FLAGW_AF((bcbitsa((uint32_t)v1,add)&0x8)>>3); //Adjust?
}

void flag_adcoa32(uint32_t v1, uint64_t add, uint64_t dst)
{
FLAGW_CF((bcbitsa((uint64_t)v1,add)>>31)&1); //Carry?
FLAGW_OF(addoverflow[((dst>>31)&1)|(((add>>30)&2))|((v1>>29)&4)]); //Overflow?
FLAGW_AF((bcbitsa((uint32_t)v1,add)&0x8)>>3); //Adjust?
}

//Substract Carry, Overflow, Adjust logic
void flag_subcoa8(uint8_t v1, uint16_t sub, uint16_t dst)
{
FLAGW_CF((bcbitss((uint16_t)v1,sub)>>7)&1); //Carry?
FLAGW_OF(suboverflow[((dst>>7)&1)|((sub>>6)&2)|((v1>>5)&4)]); //Overflow?
FLAGW_AF((bcbitss((uint16_t)v1,sub)&0x8)>>3); //Adjust?
}

void flag_subcoa16(uint16_t v1, uint32_t sub, uint32_t dst)
{
FLAGW_CF((bcbitss((uint32_t)v1,sub)>>15)&1); //Carry?
FLAGW_OF(suboverflow[((dst>>15)&1)|((sub>>14)&2)|((v1>>13)&4)]); //Overflow?
FLAGW_AF((bcbitss((uint32_t)v1,sub)&0x8)>>3); //Adjust?
}

void flag_subcoa32(uint32_t v1, uint64_t sub, uint64_t dst)
{
FLAGW_CF((bcbitss((uint64_t)v1,sub)>>31)&1); //Carry?
FLAGW_OF(suboverflow[((dst>>31)&1)|((sub>>30)&2)|((v1>>29)&4)]); //Overflow?
FLAGW_AF((bcbitss((uint64_t)v1,sub)&0x8)>>3); //Adjust?
}

Anyone knows what's going wrong? I've based it on http://www.emulators.com/docs/nx11_flags.htm and the code that's talked about(which is mentioned as well, at least the ADD instruction). For some reason, UniPCemu's doesn't match the dumped flags? The overflow flags now uses the tables from http://teaching.idallen.com/dat2343/10f/notes … 40_overflow.txt

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

Reply 1 of 19, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie

For carry, it's not bit 7 that matters in an 8-bit add, it's bit 8 after the adc (consider 0xff+0xff+carry set, or 0xff+0x00+carry clear, depending on the test case).
If the value after the add is less than the value of the left parameter, or if the result equals the left parameter and the right parameter is non-zero, then you have a carry.
There's an overflow if the top bit of the result is different from the top bit of both of the parameters.
There's an aux carry if both parameters had bit 3 set and the result does too, or if only one parameter had it set and the result doesn't.

Reply 2 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

So the carry bit is set on toggling bit 8, while the aux bit does the same for bit 4? So it's quite litterally a half-carry(4-bits carry into bit 4 or borrow from bit 4)?

Edit: I've changed the bits to check from bits 3(auxiliary) and 7/15/31(carry) to bits 4(auxiliary) and 8/16/32. The test suite's SUBB/SUBW/SBBB/SBBW instructions still give errors on bit 4 of the flags(auxiliary carry)? It's bytes at address 0x70, 0x74, 0x84 and 0x90. It expects 0x97, 0x87, 0x87, 0x96 and gets 0x87, 0x97, 0x97, 0x96? So bit 0x10 in the flags is flipped? That's the auxiliary flag.

https://bitbucket.org/superfury/unipcemu/src/ … ags.c?at=master

Edit: maybe a problem with the detection?

#define bcbitsa(v1,v2) (((v1)^(v2))^(((v1)^(dst))&~((v1)^(v2)))^dst)
#define bcbitss(v1,v2) (((v1)^(v2))^(((v1)^(dst))&((v1)^(v2)))^dst)

bcbitsa is for adding, bcbitss is for substracting. Result bits is 1 for carry/borrow bits, 0 otherwise. Both v1 and v2 are the direct inputted values(unmodified, only carry added(+) with SBB/ADC as unsigned values).

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

Reply 3 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've tried making a simple truth table to use for calculating carry/adjust flags, based on the 7/15/31th bit of v1(the value being added/substracted to/from), v2(the value being added/substracted) and the result bit:

ADD:
CARRY(7/15/31)/AUX(3):
V1 V2 RES FLAG
0 0 0 0
0 0 1 0
0 1 0 1
0 1 1 0
1 0 0 1
1 0 1 0
1 1 0 0
1 1 1 1

SUB:
CARRY(7/15/31)/AUX(3):
V1 V2 RES FLAG
0 0 0 0
0 0 1 1
0 1 0 0
0 1 1 1
1 0 0 0
1 0 1 0
1 1 0 0
1 1 1 1

For some reason, this doesn't match an actual CPU? The testsuite still fails.

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

Reply 4 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

After some checking and adjusting, the carry flag now seems to work correctly. But the adjust flag still isn't? It uses the same logic as the normal carry flag, but the effect of substracting 0x100 from 0xFF still doesn't set the Auxiliary carry flag, but does set the carry flag? The carry flag looks at the bit changed being 8/16/32, but the Auxiliary flag checks bit 3 instead? All cases work, except the substracting 0x100(0xFF immediate + Carry flag in SBB instruction) from 0xFF instruction? It's supposed to be cleared? (0xFF-0x100=0xFF, so the first case(both aren't set) doesn't apply, nor the second case(one parameter has bit 3 set(source parameter only) and the result doesn't have it set(being 0x1FF in 9-bit terms)) applies?

But somehow, the testsuite appears to expect the Auxiliary flag to be set with the substraction of 0xFF-0x100=0xFF?

Edit: Adding and modified according to Bochs lazy_flags.h's http://bochs.sourceforge.net/cgi-bin/lxr/sour … pu/lazy_flags.h ADD_COUT_VEC and SUB_COUT_VEC makes the booting process run until loading CD-ROM device drivers, keyboard unresponsive. Test suites failing?

Edit: Restoring the old code makes it able to boot again, but it will still fail the testsuites on the ADC/D, SUB/SBB and CMP instructions?

Edit: Apparently, looking at the Bochs source code and comparing it to the original code of fake86, I notice something odd: all three handle the Carry flag in SBB/ADC instructions differently: Bochs(which seems to be correctly working) doesn't include the carry flag in the second operand flags, while fake86 does include it (incorrectly) in the second operand of the SBB instructions, while UniPCemu included it with sbb only(being based off fake86's flag operations originally). Now, fixing those flags using the Bochs way fixes the testsuite as well(sub and add tests work without problems now). The only part left is the mul ROM and rotate ROM giving errors.

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

Reply 5 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

The rotate ROM is acting odd: it expects the RCLW BX,CL instruction to set Overflow flag while CL=8? Since CL<>1, it shouldn't even change the overflow flag?

Also, there's still a problem with 80286+ AAA instruction?

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

Reply 6 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

This is the AAA instruction:

byte CPU8086_internal_AAA()
{
CPUPROT1
if (EMULATED_CPU<CPU_80286) //Before new CPU?
{
if (((REG_AL&0xF)>9) || FLAG_AF)
{
REG_AL += 6;
++REG_AH;
FLAGW_AF(1);
FLAGW_CF(1);
}
else
{
FLAGW_AF(0);
FLAGW_CF(0);
}
REG_AL &= 0xF;
}
else //Newer CPUs?
{
if (((REG_AL&0xF)>9) || FLAG_AF)
{
REG_AX += 0x0106;
FLAGW_AF(1);
FLAGW_CF(1);
}
else
{
FLAGW_AF(0);
FLAGW_CF(0);
}
REG_AL &= 0xF;
}
//flag_szp8(REG_AL); //Basic flags!
flag_p8(REG_AL); //Parity is affected!
if (EMULATED_CPU<CPU_80286) //Before new CPU?
{
FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
}
else
{
FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
FLAGW_SF(0); //Clear Sign!
}
//z=s=p=o=?
CPUPROT2
if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
{
CPU[activeCPU].cycles_OP += 4; //Timings!
}
return 0;
}

And the rotate instructions:

byte op_grp2_8(byte cnt, byte varshift) {
//word d,
INLINEREGISTER word s, shift, oldCF, msb;
//word backup;
//if (cnt>0x8) return(oper1b); //NEC V20/V30+ limits shift count
s = oper1b;
oldCF = FLAG_CF;
if (EMULATED_CPU >= CPU_NECV30) cnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
switch (thereg) {
case 0: //ROL r/m8
for (shift = 1; shift <= cnt; shift++) {
if (s & 0x80) FLAGW_CF(1); else FLAGW_CF(0);
s = s << 1;
s = s | FLAG_CF;
}
if (cnt==1) FLAGW_OF(((s >> 7) & 1)&FLAG_CF); else FLAGW_OF(0);
break;

case 1: //ROR r/m8
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
s = (s >> 1) | (FLAG_CF << 7);
}
if (cnt==1) FLAGW_OF((s >> 7) ^ ((s >> 6) & 1));
break;

case 2: //RCL r/m8
for (shift = 1; shift <= cnt; shift++) {
oldCF = FLAG_CF;
if (s & 0x80) FLAGW_CF(1); else FLAGW_CF(0);
s = s << 1;
s = s | oldCF;
}
if (cnt==1) FLAGW_OF(FLAG_CF ^ ((s >> 7) & 1));
break;

case 3: //RCR r/m8
for (shift = 1; shift <= cnt; shift++) {
oldCF = FLAG_CF;
FLAGW_CF(s & 1);
s = (s >> 1) | (oldCF << 7);
}
if (cnt==1) FLAGW_OF((s >> 7) ^ ((s >> 6) & 1));
break;

case 4: case 6: //SHL r/m8
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
if (s & 0x80) FLAGW_CF(1); else FLAGW_CF(0);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFF;
}
if (cnt==1) { if (FLAG_CF==(s>>7)) FLAGW_OF(0); else FLAGW_OF(1); }
flag_szp8((uint8_t)(s&0xFF)); break;

case 5: //SHR r/m8
if (cnt == 1) { if (s&0x80) FLAGW_OF(1); else FLAGW_OF(0); }
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
Show last 150 lines
			//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
flag_szp8((uint8_t)(s & 0xFF)); break;

case 7: //SAR r/m8
msb = s & 0x80;
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
byte tempSF;
tempSF = FLAG_SF; //Save the SF!
/*flag_szp8((uint8_t)(s & 0xFF));*/
//http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#SAR says only C and O flags!
if (!cnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (cnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_s8(s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (cnt) //Anything shifted at all?
{
flag_s8(s); //Affect sign as well!
}
if ((EMULATED_CPU>=CPU_NECV30) && cnt) //NECV20+ affected?
{
flag_p8(s); //Affect parity as well!
}
break;
}
op_grp2_cycles(cnt, varshift);
return(s & 0xFF);
}

word op_grp2_16(byte cnt, byte varshift) {
//uint32_t d,
INLINEREGISTER uint_32 s, shift, oldCF, msb;
//if (cnt>0x10) return(oper1); //NEC V20/V30+ limits shift count
if (EMULATED_CPU >= CPU_NECV30) cnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
//word backup;
s = oper1;
oldCF = FLAG_CF;
switch (thereg) {
case 0: //ROL r/m16
for (shift = 1; shift <= cnt; shift++) {
if (s & 0x8000) FLAGW_CF(1); else FLAGW_CF(0);
s = s << 1;
s = s | FLAG_CF;
}
if (cnt==1) FLAGW_OF(FLAG_CF ^ ((s >> 15) & 1));
break;

case 1: //ROR r/m16
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
s = (s >> 1) | (FLAG_CF << 15);
}
if (cnt==1) FLAGW_OF((s >> 15) ^ ((s >> 14) & 1));
break;

case 2: //RCL r/m16
for (shift = 1; shift <= cnt; shift++) {
oldCF = FLAG_CF;
if (s & 0x8000) FLAGW_CF(1); else FLAGW_CF(0);
s = s << 1;
s = s | oldCF;
//oldCF = ((s&0x8000)>>15)&1; //Save FLAG_CF!
//s = (s<<1)+FLAG_CF;
//FLAG_CF = oldCF;
}
if (cnt==1) FLAGW_OF(FLAG_CF ^ ((s >> 15) & 1));
break;

case 3: //RCR r/m16
for (shift = 1; shift <= cnt; shift++) {
oldCF = FLAG_CF;
FLAGW_CF(s & 1);
s = (s >> 1) | (oldCF << 15);
//oldCF = s&1;
//s = (s<<1)+(FLAG_CF<<16);
//FLAG_CF = oldCF;
}
if (cnt==1) FLAGW_OF((s >> 15) ^ ((s >> 14) & 1));
break;

case 4: case 6: //SHL r/m16
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
if (s & 0x8000) FLAGW_CF(1); else FLAGW_CF(0);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFFF;
}
if (cnt==1) { if (FLAG_CF == (s >> 15)) FLAGW_OF(0); else FLAGW_OF(1); }
flag_szp16(s); break;

case 5: //SHR r/m16
if (cnt==1) { if (s&0x8000) FLAGW_OF(1); else FLAGW_OF(0); }
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
flag_szp16(s); break;

case 7: //SAR r/m16
msb = s & 0x8000; //Read the MSB!
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
byte tempSF;
tempSF = FLAG_SF; //Save the SF!
/*flag_szp16(s);*/
//http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#SAR says only C and O flags!
if (!cnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (cnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_s16(s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (cnt) //Anything shifted at all?
{
flag_s16(s); //Affect sign as well!
}
if ((EMULATED_CPU>=CPU_NECV30) && cnt) //NECV20+ affected?
{
flag_p16(s); //Affect parity as well!
flag_s16(s); //Affect sign as well!
}
break;
}
op_grp2_cycles(cnt, varshift|4);
return(s & 0xFFFF);
}

Can anyone see what's going wrong?

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

Reply 7 of 19, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

Where did you get the information that for 286+ AAA touches AX ? According to this MIT page for the 386 AAA instruction it should still touch only AH/AL just like 8086:

http://css.csail.mit.edu/6.858/2014/readings/i386/AAA.htm

Also the AMD 186 instruction set here (http://ece425web.groups.et.byu.net/stable/lab … tructionSet.pdf) describes it the same way.

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 8 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

I found that part of information here: http://www.hugi.scene.org/online/coding/hugi% … 20-%20coaax.htm

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

Reply 9 of 19, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

According to this: https://stackoverflow.com/questions/18945247/ … instruction-set you information is correct. So the MIT website is wrong... 🙁

But then when was the change introduced? It seems not 80186/188 as the AMD official docs still have the 8088/8086 behavior. It must have been 286. If I have some time I see about firing debug.exe on one of my machines and test it. I'll try a 386.

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 10 of 19, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

Ok, to confirm. I ran this code on my actual 386 computer (via debug.exe in DOS):

mov ax, 00f6
add al, 9
aaa

and the result was AX=0205

So your code is correct.

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 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

What about the 80286 and 80186? Do they have this new behaviour as well? Or do the 80186 or both still have the old 8086/88 behaviour?

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

Reply 12 of 19, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

I do not have an 186. Although I do have a 286 so I will try it in that. My guess though is that it will behave like a 386. We'll see.

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 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

With all current changes, I do notice a problem on the CPU emulation: when running Wolfenstein 3D's original program, it now hangs the CPU for some reason(it used to work previously). Also, both on current and the last release version of UniPCemu, for some reason, the cinematics of Megarace seem to hang and produce no sound? It seems to eventually continue on to the next screen(either a still video screen or a menu/gameplay). Gameplay seems to run somewhat, though. Any idea what might caused the cinematics to hang? It used to work previously.

Is there a way (besides the testsuite for 80486+ CPUs that's on another vogons thread(x86 CPU emulation test suite?)) to test the 80386 emulation and find the offending instruction(s)? The smallest i386-nofpu program seems to hang in a little "returnpoint:cmp ax;jne xxx;(jumps to xxx);xxx:jmp returnpoint" neverending loop.

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

Reply 15 of 19, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

The rotate ROM is acting odd: it expects the RCLW BX,CL instruction to set Overflow flag while CL=8? Since CL<>1, it shouldn't even change the overflow flag?

Also, there's still a problem with 80286+ AAA instruction?

RCL would require CL=9 to rotate to the original value, otherwise it will shift the carry to the top bit, and that could well cause an overflow condition.

Reply 16 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

But no flags should be affected when CL<>1, according to documentation? Or just carry flag?

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

Reply 18 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

Managed to fix the code and the testsuite now runs fine again.

There's still a problem with the AAD instruction, it seems?

My current AAD instruction:

OPTINLINE byte CPU8086_internal_AAD(byte data)
{
CPUPROT1
oper2b = REG_AL; //What to add!
oper1b = (REG_AH*data); //AAD base to work on, we're adding to this!
op_add8(); //Add, 8-bit, including flags!
REG_AL = res8; //The result to load!
REG_AH = 0; //AH is cleared!
CPUPROT2
if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
{
CPU[activeCPU].cycles_OP += 60; //Timings!
}
return 0;
}

Can you see what's going wrong? The EPC 80186 testsuite doesn't match the AAD 39h(expecting flags to be 0082h, getting 0892h at address 88h) and AAD 12h(expecting flags to be 0086 and getting 0097 at address 8Ch). Can you see what's going wrong? The new instruction uses the new, improved version of the ADD flags(which is the same as Bochs). This is done, according to the alternative documentation at http://www.hugi.scene.org/online/coding/hugi% … 20-%20coaax.htm . It says the flags are actually the result of the '+' operation, so essentially the (although incorrect in assembler) execution is: ADD (AH*imm),AL with the result being stored back into AL?

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

Reply 19 of 19, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie

Yes, the flags are the result of the add, but according to my documentation, it's a 16-bit add, not an 8-bit one.
i.e. ax = ((ah * imm8) + al) & 0xff
That might explain the difference in flags.