VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

Anyone can see what's going wrong, when calculating the BCD instruction flags?

//BCD opcodes!
byte CPU8086_internal_DAA()
{
word ALVAL, oldCF;
CPUPROT1
oldCF = FLAG_CF; //Save old Carry!
ALVAL = (word)REG_AL;
if (((ALVAL&0xF)>9) || FLAG_AF)
{
oper1 = ALVAL+6;
ALVAL = (oper1&0xFF);
FLAGW_CF((((oper1&0xFF00)>0)?1:0)|FLAG_CF);
FLAGW_AF(1);
}
else FLAGW_AF(0);
if (((REG_AL)>0x99) || oldCF)
{
ALVAL += 0x60;
FLAGW_CF(1);
}
else
{
FLAGW_CF(0);
}
REG_AL = (byte)(ALVAL&0xFF); //Write the value back to AL!
flag_szp8(REG_AL);
//if (ALVAL&0xFF00) FLAGW_OF(1); else FLAGW_OF(0); //Undocumented: Overflow flag!
CPUPROT2
if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
{
CPU[activeCPU].cycles_OP += 4; //Timings!
}
return 0;
}
byte CPU8086_internal_DAS()
{
INLINEREGISTER byte tempCF, tempAL;
INLINEREGISTER word bigAL;
bigAL = (word)(tempAL = REG_AL);
tempCF = FLAG_CF; //Save old values!
CPUPROT1
if (((bigAL&0xF)>9) || FLAG_AF)
{
oper1 = bigAL = REG_AL-6;
REG_AL = oper1&255;
FLAGW_CF(tempCF|((oper1&0xFF00)>0));
FLAGW_AF(1);
}
else FLAGW_AF(0);

if ((tempAL>0x99) || tempCF)
{
bigAL -= 0x60;
REG_AL = (byte)(bigAL&0xFF);
FLAGW_CF(1);
}
else
{
FLAGW_CF(0);
}
Show last 164 lines
	flag_szp8(REG_AL);
//if (bigAL&0xFF00) FLAGW_OF(1); else FLAGW_OF(0); //Undocumented: Overflow flag!
CPUPROT2
if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
{
CPU[activeCPU].cycles_OP += 4; //Timings!
}
return 0;
}
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;
}
byte CPU8086_internal_AAS()
{
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); //Sign is cleared!
}
//z=s=o=p=?
CPUPROT2
if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
{
CPU[activeCPU].cycles_OP += 4; //Timings!
}
return 0;
}

OPTINLINE byte CPU8086_internal_AAM(byte data)
{
CPUPROT1
if ((!data) && (CPU[activeCPU].instructionstep==0)) //First step?
{
CPU[activeCPU].cycles_OP += 1; //Timings always!
++CPU[activeCPU].instructionstep; //Next step after we're done!
CPU[activeCPU].executed = 0; //Not executed yet!
return 1;
}
word quotient, remainder;
byte error, applycycles;
CPU8086_internal_DIV(REG_AL,data,&quotient,&remainder,&error,8,2,6,&applycycles);
if (error) //Error occurred?
{
CPU_exDIV0(); //Raise error that's requested!
return 1;
}
else //Valid result?
{
REG_AH = (byte)(quotient&0xFF);
REG_AL = (byte)(remainder&0xFF);
//Flags are set on newer CPUs according to the MOD operation: Sign, Zero and Parity are set according to the mod operation(AL) and Overflow, Carry and Auxiliary carry are cleared.
flag_szp8(REG_AL); //Result of MOD instead!
FLAGW_OF(0); FLAGW_CF(0); FLAGW_AF(0); //Clear these!
//C=O=A=?
}
CPUPROT2
return 0;
}
OPTINLINE byte CPU8086_internal_AAD(byte data)
{
CPUPROT1
oper2 = (word)REG_AL; //What to add!
REG_AX = (REG_AH*data); //AAD
oper1 = REG_AX; //Load for addition!
op_add16(); //Add, 16-bit, including flags!
REG_AX = res16; //The result to load!
REG_AH = 0; //AH is cleared!
//C=O=A=?
CPUPROT2
if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
{
CPU[activeCPU].cycles_OP += 60; //Timings!
}
return 0;
}

The 80186 test suite fails on these, expecting the Overflow flag(???) to be set in some of these cases, as well as the auxiliary flag not to be set?

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

Reply 1 of 9, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie

For if (((ALVAL&0xF)>9) || FLAG_AF)
According to my notes, carry should not be altered here, AF should be the only flag that is set when true.

OF is set on exit according to the result in all cases.

Reply 2 of 9, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've tried to apply the AAD instruction, but flags doesn't match, according to the EPC's 80186 testsuite?

	CPUPROT1
oper2b = REG_AL; //What to add!
REG_AL = (REG_AH*data); //AAD
oper1b = REG_AL; //Load for addition!
op_add8(); //Add, 8-bit, including flags!
REG_AL = res8; //The result to load!
REG_AH = 0; //AH is cleared!
//C=O=A=?
CPUPROT2

Bits 7, 4 and 1 of the flags malfunction, according to the testsuite:

void flag_add8(uint8_t v1, uint8_t v2)
{
int16_t dst;
dst = (int16_t)v1 + (int16_t)v2;
flag_szp8((uint8_t)(dst&0xFF));
if (dst & 0xFF00) FLAGW_CF(1);
else FLAGW_CF(0);
if (((dst ^ v1) & (dst ^ v2) & 0x80) == 0x80) FLAGW_OF(1);
else FLAGW_OF(0);
if (((v1 ^ v2 ^ dst) & 0x10) == 0x10) FLAGW_AF(1);
else FLAGW_AF(0);
}

Is this correct? Or is something going wrong here? This is based on: 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 4 of 9, by superfury

User metadata
Rank l33t++
Rank
l33t++

But then. Why does the EPC 80186 invalidate those flags? They don't match up with the dumped results(which I assume are taken from a real 801/286. I'm thinking 80286, because it expects flags bits 12-15 to be zeroed(on 80286+, not on 80186/8 and earlier).

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

Reply 5 of 9, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

But then. Why does the EPC 80186 invalidate those flags? They don't match up with the dumped results(which I assume are taken from a real 801/286. I'm thinking 80286, because it expects flags bits 12-15 to be zeroed(on 80286+, not on 80186/8 and earlier).

That is most certainly the case. They did not have a real 80186 to run this on. I will try to dig up my 286 this weekend maybe and then run the test and see what I get. I should probably just be able to do it via DOS' debug command. Cannot promise though.

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 6 of 9, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie

Can you tell me some specific combinations of values that are failing the test?
I have maps somewhere with every bit value for every possible combination of inputs, so if I can find them I can compare directly.

Reply 7 of 9, by superfury

User metadata
Rank l33t++
Rank
l33t++

It's the MUL.BIN from the EPC 80186 testsuite. From the point it gets to the AAD, the flags pushed on the stack mismatch. The first one has wrong Overflow and Adjust flags. The second one has 0x08 instead of 0x0 on the stack(high byte of pushed flags). The third one, I'll need to run again on my current PC to check those results.

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

Reply 8 of 9, by superfury

User metadata
Rank l33t++
Rank
l33t++

This is the dump of the test that's running, as well as the used binaries for reference, from the EPC 80186 testsuite:

Filename
debugger_UniPCemu_20170630_1619.zip
File size
34.27 KiB
Downloads
35 downloads
File comment
The used ROM binary, result ROM and diagnostic logs of the test running.
File license
Fair use/fair dealing exception

The files:
999.mul.bin: The ROM loaded as a BIOS.
res_999.mul.bin: The results expected to be located at segment 0, at the start of RAM.
debugger.log: The logging containing all instructions executed, register dump(CPU states before executing an instruction), memory accesses during the instruction execution(they're dumped before the executed instruction) and video/interrupt status.
ROM_log.log; a short version of debugger.log, which details the test results. It also shows the errors when compared to the res_999.mul.bin at the start of RAM. The final memory reads at the end of debugger.log are the emulator reading back the results from RAM to compare against the res_999.mul.bin file.

Anyone can see what's going wrong?

So:

00:00:17:13.08760: F000:01E1 (D539)AAD 39
00:00:17:13.08766: Registers:
00:00:17:13.08778: AX: 532D, BX: 0014, CX: 2400, DX: F900
00:00:17:13.08794: CS: F000, DS: 0000, ES: 0000, SS: 0000
00:00:17:13.08806: SP: 008A, BP: 0000, SI: EEEB, DI: 0000
00:00:17:13.08816: IP: 01E1, FLAGS: 0086
00:00:17:13.08820: CR0: FFF0
00:00:17:13.08836: GDTR: 000000000000FFFF, IDTR: 00000000000003FF
00:00:17:13.08850: FLAGSINFO:c1P0a0zStido00n0

This results in being:

00:00:17:13.09698: Registers:
00:00:17:13.09712: AX: 00A8, BX: 0014, CX: 2400, DX: F900
00:00:17:13.09726: CS: F000, DS: 0000, ES: 0000, SS: 0000
00:00:17:13.09740: SP: 008A, BP: 0000, SI: EEEB, DI: 0000
00:00:17:13.09748: IP: 01E3, FLAGS: 0892
00:00:17:13.09754: CR0: FFF0
00:00:17:13.09768: GDTR: 000000000000FFFF, IDTR: 00000000000003FF
00:00:17:13.09782: FLAGSINFO:c1p0A0zStidO00n0

It expects the value in memory to be 0x0082 at the pushed flags right after that, but it finds 0x0892 instead. So Overflow and Adjust aren't supposed to be set? Why?

The other error occuring is:

00:00:17:13.04158: F000:01CF (D512)AAD 12
00:00:17:13.04164: Registers:
00:00:17:13.04176: AX: FFFF, BX: 0014, CX: 2400, DX: F900
00:00:17:13.04190: CS: F000, DS: 0000, ES: 0000, SS: 0000
00:00:17:13.04202: SP: 008E, BP: 0000, SI: EEEB, DI: 0000
00:00:17:13.04212: IP: 01CF, FLAGS: 0086
00:00:17:13.04216: CR0: FFF0
00:00:17:13.04232: GDTR: 000000000000FFFF, IDTR: 00000000000003FF
00:00:17:13.04246: FLAGSINFO:c1P0a0zStido00n0

The register state right after this instruction is:

00:00:17:13.05044: AX: 00ED, BX: 0014, CX: 2400, DX: F900
00:00:17:13.05058: CS: F000, DS: 0000, ES: 0000, SS: 0000
00:00:17:13.05070: SP: 008E, BP: 0000, SI: EEEB, DI: 0000
00:00:17:13.05082: IP: 01D1, FLAGS: 0097
00:00:17:13.05086: CR0: FFF0
00:00:17:13.05102: GDTR: 000000000000FFFF, IDTR: 00000000000003FF
00:00:17:13.05118: FLAGSINFO:C1P0A0zStido00n0

It expects flags to be 0x0086 but gets 0x0097 instead(Carry and Adjust flag aren't supposed to be set for some unknown reason. Why?).

AAD instruction:

OPTINLINE byte CPU8086_internal_AAD(byte data)
{
CPUPROT1
oper2b = REG_AL; //What to add!
REG_AL = (REG_AH*data); //AAD
oper1b = REG_AL; //Load for addition!
op_add8(); //Add, 8-bit, including flags!
REG_AL = res8; //The result to load!
REG_AH = 0; //AH is cleared!
//C=O=A=?
CPUPROT2
if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
{
CPU[activeCPU].cycles_OP += 60; //Timings!
}
return 0;
}
OPTINLINE void op_add8() {
res8 = oper1b + oper2b;
flag_add8 (oper1b, oper2b);
}
void flag_add8(uint8_t v1, uint8_t v2)
{
int16_t dst;
dst = (int16_t)v1 + (int16_t)v2;
flag_szp8((uint8_t)(dst&0xFF));
if (dst & 0xFF00) FLAGW_CF(1);
else FLAGW_CF(0);
if (((dst ^ v1) & (dst ^ v2) & 0x80) == 0x80) FLAGW_OF(1);
else FLAGW_OF(0);
if (((v1 ^ v2 ^ dst) & 0x10) == 0x10) FLAGW_AF(1);
else FLAGW_AF(0);
}

Anyone can 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 9 of 9, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie

It seems that either that had a weird CPU that behaves in an undocumented way, or that their test results are actually wrong.
I am certain that the values that you have are correct.