VOGONS


test386.asm CPU tester

Topic actions

Reply 120 of 178, by superfury

User metadata
Rank l33t++
Rank
l33t++

So if I understand correctly, the mask only applies to 8/16/32-bit shift/rotates, while 32-bit RCR doesn't mask and instead does modulo 33(according to test results)? And the modulo 8/16/32 mentioned in pretty much all 80386+ documentation isn't applied in the actual 80386(only top 3 bits masked off, nothing more)?

With modulo I mean the following parts of the manual:
http://x86.renejeschke.de/html/file_module_x86_id_273.html

So with:

switch(OperandSize) {
case 8:
TemporaryCount = (Count & 0x1F) % 9;
break;
case 16:
TemporaryCount = (Count & 0x1F) % 17;
break;
case 32:
TemporaryCount = Count & 0x1F;

The %9 and %17 isn't used in actual processors?

Also:

switch(OperandSize) {
case 8:
TemporaryCount = Count % 8;
break;
case 16:
TemporaryCount = Count % 16;
break;
case 32:
TemporaryCount = Count % 32;
break;
}

%8, %16 and %32 isn't applied? Only %32 for all cases(except 32-bit RCR)?

The only exception to the %32/&0x1F rule is %33 with 32-bit RCR? All others ONLY use modulo 32(&0x1F, masking off the top 3 bits)?

Is that correct? (Although that would make many documentations on the 80386+ or 32-bit x86 CPUs invalid)

ROL AL,9 will become ROL AL,1 and ROL AL,8 will become ROL AL,8?

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

Reply 121 of 178, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

So if I understand correctly, the mask only applies to 8/16/32-bit shift/rotates, while 32-bit RCR doesn't mask and instead does modulo 33(according to test results)?

Both of them mask with 0x1F, so

mov eax,20
stc
rcl eax,20

will do nothing - no change in value or flags. Same behaviour for RCR, but rotate of 0x21 looks just like rotate of 1.
However, the 8- and 16-bit are indeed modulo bitness+1.

mov al,20
stc
rcl al,8

will yield AL=90 and carry and overflow cleared.
A rotate of 9, on the other hand, will do nothing. OF won't be affected like it would be if you did a rotate of 8 and then a rotate of 1.

Reply 122 of 178, by superfury

User metadata
Rank l33t++
Rank
l33t++

So 32-bit RCR doesn't do modulo 33? But I tried that(&0x1F instead of %33) and the testsuite fails it's results when I do(errors completely, not shifting when supposed to). All others are already as you've described.

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

Reply 123 of 178, by Harekiet

User metadata
Rank DOSBox Author
Rank
DOSBox Author

Nice test suite, most stuff seems to pass except for the typical looping rotates, although I doubt that would cause any problems with programs.
Nobody is bored enough to make task switching, security and vm86 tests I guess 😀

Reply 124 of 178, by superfury

User metadata
Rank l33t++
Rank
l33t++
Harekiet wrote:

Nice test suite, most stuff seems to pass except for the typical looping rotates, although I doubt that would cause any problems with programs.
Nobody is bored enough to make task switching, security and vm86 tests I guess 😀

I still agree with that those are still missing from the testsuite(since my emulator might have some unknown bugs regarding some or all of them, seeing some stuff like Windows 3.0 in protected mode crash and EMM386 crashing as well). The only thing acually there is one simple readonly segment test? Can you add those who Harekiet mentioned(TSS, security and VM86 mode tests), hottobar?

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

Reply 125 of 178, by hottobar

User metadata
Rank Newbie
Rank
Newbie
Harekiet wrote:

Nobody is bored enough to make task switching, security and vm86 tests I guess 😀

It's not so much about boredom, it's more like being able to define a meaningful test and to find the time to implement it, while having a very good understanding of the matter, ofc. 😀

Anyway, I've finally found the time to implement every test suggested by peterferrie here.

Last edited by hottobar on 2017-11-19, 18:33. Edited 1 time in total.

Reply 127 of 178, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've also just implemented the RCR variant for the Bit Test instructions. The only thing with possible problems that might have been left are the undocumented adjust instruction results.

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

Reply 128 of 178, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just recompiled the latest test386.asm, with all tests enabled. It now seems to crash on the AAA undefined flags test? I've taken a look at IBMulator and copied some of it's logic that should make my 8086 and 80186+ flags equal(although some little processor differences still apply, like += 0x106 vs ++ and &0xF), but it still fails the test?

8086+ BCD:

//BCD opcodes!
byte CPU8086_internal_DAA()
{
word ALVAL, oldCF, oldAL;
CPUPROT1
oldAL = (word)REG_AL; //Save original!
oldCF = FLAG_CF; //Save old Carry!
ALVAL = (word)REG_AL;
if (((ALVAL&0xF)>9) || FLAG_AF)
{
oper1 = ALVAL+6;
ALVAL = (oper1&0xFF);
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);
FLAGW_OF(((((oldAL&0x80)==0) && (REG_AL&0x80)))?1:0); //Overflow flag, according to IBMulator!
//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 old_CF, old_AL;
INLINEREGISTER word carryAL;
old_AL = (word)(REG_AL);
old_CF = FLAG_CF; //Save old values!
FLAGW_CF(0);
CPUPROT1
if (((old_AL&0xF)>9) || FLAG_AF)
{
carryAL = REG_AL-6;
REG_AL = (carryAL&0xFF); //Store the result!
FLAGW_CF(old_CF|((carryAL&0xFF00)>0)); //Old CF or borrow that occurs when substracting!
FLAGW_AF(1);
}
else FLAGW_AF(0);

if ((old_AL>0x99) || old_CF)
{
REG_AL -= 0x60;
FLAGW_CF(1);
}
flag_szp8(REG_AL);
FLAGW_OF(((old_AL&0x80)) && ((REG_AL&0x80)==0)); //According to IBMulator!
//if (bigAL&0xFF00) FLAGW_OF(1); else FLAGW_OF(0); //Undocumented: Overflow flag!
Show last 137 lines
	CPUPROT2
if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
{
CPU[activeCPU].cycles_OP += 4; //Timings!
}
return 0;
}
byte CPU8086_internal_AAA()
{
CPUPROT1
if (((REG_AL&0xF)>9))
{
if ((REG_AL&0xF)>9)
{
FLAGW_OF(((REG_AL&0xF0)==0x70)?1:0); //According to IBMulator
}
REG_AL += 6;
REG_AL &= 0xF;
++REG_AH;
FLAGW_AF(1);
FLAGW_CF(1);
FLAGW_ZF((REG_AL==0)?1:0);
}
else if (FLAG_AF)
{
REG_AL += 6;
REG_AL &= 0xF;
++REG_AH;
FLAGW_AF(1);
FLAGW_CF(1);
FLAGW_ZF(0); //According to IBMulator!
FLAGW_OF(0); //According to IBMulator!
}
else
{
FLAGW_AF(0);
FLAGW_CF(0);
FLAGW_OF(0); //According to IBMulator!
FLAGW_ZF(0); //According to IBMulator!
}
//flag_szp8(REG_AL); //Basic flags!
flag_p8(REG_AL); //Parity is affected!
FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
//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 (((REG_AL&0xF)>9) || FLAG_AF)
{
FLAGW_SF((REG_AL>0x85)?1:0); //According to IBMulator!
REG_AL -= 6;
REG_AL &= 0xF;
--REG_AH;
FLAGW_AF(1);
FLAGW_CF(1);
FLAGW_OF(0); //According to IBMulator!
}
else if (FLAG_AF)
{
FLAGW_OF(((REG_AL>=0x80) && (REG_AL<=0x85))?1:0); //According to IBMulator!
FLAGW_SF(((REG_AL < 0x06) || (REG_AL > 0x85))?1:0); //According to IBMulator!
REG_AL -= 6;
REG_AL &= 0xF;
--REG_AH;
FLAGW_AF(1);
FLAGW_CF(1);
}
else
{
FLAGW_SF((REG_AL>=0x80)?1:0); //According to IBMulator!
FLAGW_AF(0);
FLAGW_CF(0);
FLAGW_OF(0); //According to IBMulator!
}
//flag_szp8(REG_AL); //Basic flags!
flag_p8(REG_AL); //Parity is affected!
FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
//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,0,0,0);
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
oper2b = (word)REG_AL; //What to add!
oper1b = ((word)REG_AH*(word)data); //AAD base to work on, we're adding to this!
op_add8(); //Add, 8-bit, including flags!
REG_AX = (res8&0xFF); //The result to load!
CPUPROT2
if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
{
CPU[activeCPU].cycles_OP += 60; //Timings!
}
return 0;
}

80186+ adjustments for newer CPUs:

//BCD opcodes!
OPTINLINE void CPU186_internal_AAA()
{
CPUPROT1
FLAGW_SF((REG_AL>=0x7A)&&(REG_AL<=0xF9)); //According to IBMulator
if ((REG_AL&0xF)>9)
{
FLAGW_OF(((REG_AL&0xF0)==0x70)?1:0); //According to IBMulator
REG_AX += 0x0106;
FLAGW_AF(1);
FLAGW_CF(1);
FLAGW_ZF((REG_AL==0)?1:0);
}
else if (FLAG_AF) //Special case according to IBMulator?
{
REG_AX += 0x0106;
FLAGW_AF(1);
FLAGW_CF(1);
FLAGW_ZF(0); //According to IBMulator!
FLAGW_OF(0); //According to IBMulator!
}
else
{
FLAGW_AF(0);
FLAGW_CF(0);
FLAGW_OF(0); //According to IBMulator!
FLAGW_ZF((REG_AL==0)?1:0); //According to IBMulator!
}
flag_p8(REG_AL); //Parity is affected!
REG_AL &= 0xF;
//flag_szp8(REG_AL); //Basic flags!
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!
}
}
OPTINLINE void CPU186_internal_AAS()
{
CPUPROT1
if (((REG_AL&0xF)>9))
{
FLAGW_SF((REG_AL>0x85)?1:0); //According to IBMulator!
REG_AX -= 0x0106;
FLAGW_AF(1);
FLAGW_CF(1);
FLAGW_OF(0); //According to IBMulator!
}
else if (FLAG_AF)
{
FLAGW_OF(((REG_AL>=0x80) && (REG_AL<=0x85))?1:0); //According to IBMulator!
FLAGW_SF(((REG_AL < 0x06) || (REG_AL > 0x85))?1:0); //According to IBMulator!
REG_AX -= 0x0106;
FLAGW_AF(1);
FLAGW_CF(1);
}
else
Show last 18 lines
	{
FLAGW_SF((REG_AL>=0x80)?1:0); //According to IBMulator!
FLAGW_AF(0);
FLAGW_CF(0);
FLAGW_OF(0); //According to IBMulator!
}
REG_AL &= 0xF;
//flag_szp8(REG_AL); //Basic flags!
flag_p8(REG_AL); //Parity is affected!
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!
}
}

Can you see what's going wrong, hottobar? Why is AAA failing?

The strangest thing is, that it actually fails on the Auxiliary flag??? That shouldn't even happen, since the surrounding logic for setting/clearing it is exactly the same and unchanged?

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

Reply 129 of 178, by hottobar

User metadata
Rank Newbie
Rank
Newbie
superfury wrote:
[…]
Show full quote
//According to IBMulator

more like "According to DOSBox"... I've unashamedly copied AAA and AAS code straight from DOSBox, which is correct regarding the undefined flags for pre-pentium hw (for those opcodes anyway).

EDIT: why do you modify ZF and SF at the end of the AAA procedure?

FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
FLAGW_SF(0); //Clear Sign!

Reply 130 of 178, by superfury

User metadata
Rank l33t++
Rank
l33t++

You're right. This is my new code(after some more fixes, now it gets to DAS it seems, before crashing(also some shr before the HLT)):

8086+:

//BCD opcodes!
byte CPU8086_internal_DAA()
{
word ALVAL, oldCF, oldAL;
CPUPROT1
oldAL = (word)REG_AL; //Save original!
oldCF = FLAG_CF; //Save old Carry!
ALVAL = (word)REG_AL;
if (((ALVAL&0xF)>9) || FLAG_AF)
{
oper1 = ALVAL+6;
ALVAL = (oper1&0xFF);
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);
FLAGW_OF(((((oldAL&0x80)==0) && (REG_AL&0x80)))?1:0); //Overflow flag, according to IBMulator!
//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 old_CF, old_AL;
INLINEREGISTER word carryAL;
old_AL = (word)(REG_AL);
old_CF = FLAG_CF; //Save old values!
FLAGW_CF(0);
CPUPROT1
if (((old_AL&0xF)>9) || FLAG_AF)
{
carryAL = REG_AL-6;
REG_AL = (carryAL&0xFF); //Store the result!
FLAGW_CF(old_CF|((carryAL&0xFF00)>0)); //Old CF or borrow that occurs when substracting!
FLAGW_AF(1);
}
else FLAGW_AF(0);

if ((old_AL>0x99) || old_CF)
{
REG_AL -= 0x60;
FLAGW_CF(1);
}
flag_szp8(REG_AL);
FLAGW_OF(((old_AL&0x80)) && ((REG_AL&0x80)==0)); //According to IBMulator!
//if (bigAL&0xFF00) FLAGW_OF(1); else FLAGW_OF(0); //Undocumented: Overflow flag!
Show last 133 lines
	CPUPROT2
if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
{
CPU[activeCPU].cycles_OP += 4; //Timings!
}
return 0;
}
byte CPU8086_internal_AAA()
{
CPUPROT1
if (((REG_AL&0xF)>9))
{
FLAGW_OF(((REG_AL&0xF0)==0x70)?1:0); //According to IBMulator
REG_AL += 6;
REG_AL &= 0xF;
++REG_AH;
FLAGW_AF(1);
FLAGW_CF(1);
FLAGW_ZF((REG_AL==0)?1:0);
}
else if (FLAG_AF)
{
REG_AL += 6;
REG_AL &= 0xF;
++REG_AH;
FLAGW_AF(1);
FLAGW_CF(1);
FLAGW_ZF(0); //According to IBMulator!
FLAGW_OF(0); //According to IBMulator!
}
else
{
FLAGW_AF(0);
FLAGW_CF(0);
FLAGW_OF(0); //According to IBMulator!
FLAGW_ZF((REG_AL==0)?1:0); //According to IBMulator!
}
//flag_szp8(REG_AL); //Basic flags!
flag_p8(REG_AL); //Parity is affected!
//FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
//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 (((REG_AL&0xF)>9) || FLAG_AF)
{
FLAGW_SF((REG_AL>0x85)?1:0); //According to IBMulator!
REG_AL -= 6;
--REG_AH;
FLAGW_AF(1);
FLAGW_CF(1);
FLAGW_OF(0); //According to IBMulator!
}
else if (FLAG_AF)
{
FLAGW_OF(((REG_AL>=0x80) && (REG_AL<=0x85))?1:0); //According to IBMulator!
FLAGW_SF(((REG_AL < 0x06) || (REG_AL > 0x85))?1:0); //According to IBMulator!
REG_AL -= 6;
--REG_AH;
FLAGW_AF(1);
FLAGW_CF(1);
}
else
{
FLAGW_SF((REG_AL>=0x80)?1:0); //According to IBMulator!
FLAGW_AF(0);
FLAGW_CF(0);
FLAGW_OF(0); //According to IBMulator!
}
//flag_szp8(REG_AL); //Basic flags!
flag_p8(REG_AL); //Parity is affected!
FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
REG_AL &= 0xF;
//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,0,0,0);
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
oper2b = (word)REG_AL; //What to add!
oper1b = ((word)REG_AH*(word)data); //AAD base to work on, we're adding to this!
op_add8(); //Add, 8-bit, including flags!
REG_AX = (res8&0xFF); //The result to load!
CPUPROT2
if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
{
CPU[activeCPU].cycles_OP += 60; //Timings!
}
return 0;
}

80186+:

//BCD opcodes!
OPTINLINE void CPU186_internal_AAA()
{
CPUPROT1
FLAGW_SF((REG_AL>=0x7A)&&(REG_AL<=0xF9)); //According to IBMulator
if ((REG_AL&0xF)>9)
{
FLAGW_OF(((REG_AL&0xF0)==0x70)?1:0); //According to IBMulator
REG_AX += 0x0106;
FLAGW_AF(1);
FLAGW_CF(1);
FLAGW_ZF((REG_AL==0)?1:0);
}
else if (FLAG_AF) //Special case according to IBMulator?
{
REG_AX += 0x0106;
FLAGW_AF(1);
FLAGW_CF(1);
FLAGW_ZF(0); //According to IBMulator!
FLAGW_OF(0); //According to IBMulator!
}
else
{
FLAGW_AF(0);
FLAGW_CF(0);
FLAGW_OF(0); //According to IBMulator!
FLAGW_ZF((REG_AL==0)?1:0); //According to IBMulator!
}
flag_p8(REG_AL); //Parity is affected!
REG_AL &= 0xF;
//flag_szp8(REG_AL); //Basic flags!
//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!
}
}
OPTINLINE void CPU186_internal_AAS()
{
CPUPROT1
if (((REG_AL&0xF)>9))
{
FLAGW_SF((REG_AL>0x85)?1:0); //According to IBMulator!
REG_AX -= 0x0106;
FLAGW_AF(1);
FLAGW_CF(1);
FLAGW_OF(0); //According to IBMulator!
}
else if (FLAG_AF)
{
FLAGW_OF(((REG_AL>=0x80) && (REG_AL<=0x85))?1:0); //According to IBMulator!
FLAGW_SF(((REG_AL < 0x06) || (REG_AL > 0x85))?1:0); //According to IBMulator!
REG_AX -= 0x0106;
FLAGW_AF(1);
FLAGW_CF(1);
}
else
Show last 18 lines
	{
FLAGW_SF((REG_AL>=0x80)?1:0); //According to IBMulator!
FLAGW_AF(0);
FLAGW_CF(0);
FLAGW_OF(0); //According to IBMulator!
}
//flag_szp8(REG_AL); //Basic flags!
flag_p8(REG_AL); //Parity is affected!
FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
REG_AL &= 0xF;
//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!
}
}
Filename
debugger_UniPCemu_test386.asm_20171120_2030.zip
File size
446.07 KiB
Downloads
96 downloads
File comment
test386.asm executing POST E0.
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 132 of 178, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just fixed the auxiliary flag to set(shl/shr) or clear(sar) on maskcnt!=0. Now shr crashes because of an invalid carry flag?

16-bit:

byte op_grp2_8(byte cnt, byte varshift) {
//word d,
INLINEREGISTER word s, shift, tempCF, msb;
INLINEREGISTER byte numcnt, maskcnt, overflow;
//word backup;
//if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
numcnt = maskcnt = cnt; //Save count!
s = oper1b;
switch (thereg) {
case 0: //ROL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>7); //Save MSB!
s = (s << 1)|FLAG_CF;
overflow = (((s >> 7) & 1)^FLAG_CF); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 1: //ROR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FU) | (FLAG_CF << 7);
overflow = ((s >> 7) ^ ((s >> 6) & 1)); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>7); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 2: //RCL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>7); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 3: //RCR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
overflow = (((s >> 7)&1)^FLAG_CF);
tempCF = FLAG_CF;
Show last 217 lines
			FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FU) | (tempCF << 7);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 4: case 6: //SHL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>7);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFU;
overflow = (FLAG_CF^(s>>7));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>7); //Always sets CF, according to various sources?
if (numcnt) flag_szp8((uint8_t)(s&0xFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 5: //SHR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
overflow = (s>>7);
FLAGW_CF(s);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (numcnt) flag_szp8((uint8_t)(s & 0xFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 7: //SAR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
msb = s & 0x80U;
//FLAGW_AF(0);
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_AF(0);
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 (!maskcnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_szp8((uint8_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (numcnt) //Anything shifted at all?
{
flag_szp8((uint8_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared with count as well?
}
break;
}
op_grp2_cycles(numcnt, varshift);
return (s & 0xFFU);
}

word op_grp2_16(byte cnt, byte varshift) {
//word d,
INLINEREGISTER uint_32 s, shift, tempCF, msb;
INLINEREGISTER byte numcnt, maskcnt, overflow;
//word backup;
//if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
numcnt = maskcnt = cnt; //Save count!
s = oper1;
switch (thereg) {
case 0: //ROL r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>15); //Save MSB!
s = (s << 1)|FLAG_CF;
overflow = (((s >> 15) & 1)^FLAG_CF); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 1: //ROR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFU) | (FLAG_CF << 15);
overflow = ((s >> 15) ^ ((s >> 14) & 1)); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 2: //RCL r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>15); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 15) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 3: //RCR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
overflow = ((s >> 15)^FLAG_CF);
tempCF = FLAG_CF;
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFU) | (tempCF << 15);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 4: case 6: //SHL r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>15);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFFFU;
overflow = (FLAG_CF^(s>>15));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
if (numcnt) flag_szp16((uint16_t)(s&0xFFFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 5: //SHR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
overflow = (s>>15);
FLAGW_CF(s);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (numcnt) flag_szp16((uint16_t)(s & 0xFFFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 7: //SAR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
msb = s & 0x8000U;
//FLAGW_AF(0);
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_AF(0);
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 (!maskcnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_szp16(s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (numcnt) //Anything shifted at all?
{
flag_szp16(s); //Affect sign as well!
FLAGW_OF(0); //Cleared with count as well?
}
break;
}
op_grp2_cycles(numcnt, varshift);
return (s & 0xFFFFU);
}

32-bit:

uint_32 op_grp2_32(byte cnt, byte varshift) {
//word d,
INLINEREGISTER uint_64 s, shift, tempCF, msb;
INLINEREGISTER byte numcnt,maskcnt,overflow;
//word backup;
//if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
numcnt = maskcnt = cnt; //Save count!
s = oper1d;
switch (thereg) {
case 0: //ROL r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>31); //Save MSB!
s = (s << 1)|FLAG_CF;
overflow = (((s >> 31) & 1)^FLAG_CF);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 1: //ROR r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFFFFFU) | (FLAG_CF << 31);
overflow = ((s >> 31) ^ ((s >> 30) & 1));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 2: //RCL r/m32
if (EMULATED_CPU >= CPU_80386) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>31); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 31) & 1)^FLAG_CF); //OF=MSB^CF
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 3: //RCR r/m32
if (EMULATED_CPU >= CPU_80386) maskcnt %= 33; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
overflow = (((s >> 31)&1)^FLAG_CF);
tempCF = FLAG_CF;
Show last 78 lines
			FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFFFFFU) | (tempCF << 31);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 4: case 6: //SHL r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>31);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFFFFFFFU;
overflow = (FLAG_CF^(s>>31));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
if (numcnt) flag_szp32((uint32_t)(s&0xFFFFFFFFU));
break;

case 5: //SHR r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
overflow = (s>>31);
FLAGW_CF(s);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
if (numcnt) flag_szp32((uint32_t)(s & 0xFFFFFFFFU));
break;

case 7: //SAR r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
msb = s & 0x80000000U;
//FLAGW_AF(0);
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_AF(0);
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 (!maskcnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_szp32((uint32_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (numcnt) //Anything shifted at all?
{
flag_szp32((uint32_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared with count as well?
}
break;
}
op_grp2_cycles32(numcnt, varshift);
return (s & 0xFFFFFFFFU);
}
Filename
debugger_UniPCemu_test386.asm_20171121_0735.zip
File size
1.16 MiB
Downloads
85 downloads
File comment
test386.asm crashing on test E0.
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 133 of 178, by superfury

User metadata
Rank l33t++
Rank
l33t++

Eventually managed to fix those shift bugs, by doing the same as IBMulator:
- SHL r/m8 has a bit of extra logic(clearing the result with shifts of 16 and 24):

		if ((EMULATED_CPU>=CPU_80386))
{
if ((maskcnt==0x10) || (maskcnt==0x18))
{
FLAGW_CF(s);
FLAGW_OF(FLAG_CF);
overflow = FLAG_OF;
s = 0; //Make the result zeroed, according to IBMulator?
goto skipshift;
}
if (maskcnt!=8) numcnt &= 7; //Limit count!
}

SHR r/m8 has a special carry flag setting on the MSB for masked counts 16 and 24.

That makes it continue to the BT instruction tests, which fail.

Edit: Just adjusted the BT* instructions with improved results. Now they pass.

Now it crashes on the very first RCR instruction after that?

Edit: It seems to crash on the following part:

0010:00003386 B0 00 mov al,00	Physical(r):000F3394=83(ƒ); Paged(r):000F3394=83(ƒ); Physical(r):000F3395=F8(ø); Paged(r):000F3395=F8(ø); Physical(r):000F3396=01(); Paged(r):000F3396=01(); Physical(r):000F3397=0F(); Paged(r):000F3397=0F()
Registers:
EAX: 0000ff01 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010002 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 00003386 EFLAGS: 00000803
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00Oditsz0a0p1C
0010:00003388 B1 09 mov cl,09
Registers:
EAX: 0000ff00 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010002 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 00003388 EFLAGS: 00000803
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00Oditsz0a0p1C
0010:0000338a D2 D8 rcr al,cl Physical(r):000F3398=85(…); Paged(r):000F3398=85(…); Physical(r):000F3399=63(c); Paged(r):000F3399=63(c); Physical(r):000F339A=8C(Œ); Paged(r):000F339A=8C(Œ); Physical(r):000F339B=00( ); Paged(r):000F339B=00( )
Registers:
EAX: 0000ff00 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010002 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000338a EFLAGS: 00000803
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00Oditsz0a0p1C
Paged(w):0001FFFE=02(); Paged(w):0001FFFF=08(); Paged(w):00020000=00( ); Paged(w):00020001=00( ); Physical(w):0001FFFE=02(); RAM(w):0001FFFE=02(); Physical(w):0001FFFF=08(); RAM(w):0001FFFF=08(); Physical(w):00020000=00( ); RAM(w):00020000=00( ); Physical(w):00020001=00( ); RAM(w):00020001=00( )
0010:0000338c 9C pushfd
Registers:
EAX: 0000ff00 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010002 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000338c EFLAGS: 00000802
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00Oditsz0a0p1c
RAM(r):0001FFFE=02(); Physical(r):0001FFFE=02(); Paged(r):0001FFFE=02(); RAM(r):0001FFFF=08(); Physical(r):0001FFFF=08(); Paged(r):0001FFFF=08()
0010:0000338d 66 58 pop ax
Registers:
EAX: 0000ff00 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 0000fffe EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000338d EFLAGS: 00000802
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00Oditsz0a0p1c
0010:0000338f 66 25 D5 08 and ax,08d5 Physical(r):000F339C=00( ); Paged(r):000F339C=00( ); Physical(r):000F339D=66(f); Paged(r):000F339D=66(f); Physical(r):000F339E=B8(¸); Paged(r):000F339E=B8(¸); Physical(r):000F339F=00( ); Paged(r):000F339F=00( )
Registers:
EAX: 00000802 EBX: 00010100 ECX: 00000009 EDX: ffff0084
Show last 68 lines
ESP: 00010000 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000338f EFLAGS: 00000802
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00Oditsz0a0p1c
0010:00003393 66 83 F8 01 cmp ax,0001 Physical(r):000F33A0=00( ); Paged(r):000F33A0=00( ); Physical(r):000F33A1=66(f); Paged(r):000F33A1=66(f); Physical(r):000F33A2=50(P); Paged(r):000F33A2=50(P); Physical(r):000F33A3=9D(); Paged(r):000F33A3=9D()
Registers:
EAX: 00000800 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010000 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 00003393 EFLAGS: 00000006
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00oditsz0a0P1c
0010:00003397 0F 85 63 8C 00 00 jne 0000c000
Registers:
EAX: 00000800 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010000 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 00003397 EFLAGS: 00000016
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00oditsz0A0P1c
RAM(r):00001003=00( ); Physical(r):00001003=00( ); Paged(r):00001003=00( ); RAM(r):00001002=00( ); Physical(r):00001002=00( ); Paged(r):00001002=00( ); RAM(r):00001001=20( ); Physical(r):00001001=20( ); Paged(r):00001001=20( ); RAM(r):00001000=27('); Physical(r):00001000=27('); Paged(r):00001000=27('); RAM(r):000023F3=00( ); Physical(r):000023F3=00( ); Paged(r):000023F3=00( ); RAM(r):000023F2=0F(); Physical(r):000023F2=0F(); Paged(r):000023F2=0F(); RAM(r):000023F1=C0(À); Physical(r):000023F1=C0(À); Paged(r):000023F1=C0(À); RAM(r):000023F0=27('); Physical(r):000023F0=27('); Paged(r):000023F0=27('); Physical(r):000FC000=FA(ú); Paged(r):000FC000=FA(ú); Physical(r):000FC001=F4(ô); Paged(r):000FC001=F4(ô); Physical(r):000FC002=EB(ë); Paged(r):000FC002=EB(ë); Physical(r):000FC003=FC(ü); Paged(r):000FC003=FC(ü)
0010:0000c000 FA cli
Registers:
EAX: 00000800 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010000 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000c000 EFLAGS: 00000016
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00oditsz0A0P1c
Physical(r):000FC004=90(); Paged(r):000FC004=90(); Physical(r):000FC005=90(); Paged(r):000FC005=90(); Physical(r):000FC006=90(); Paged(r):000FC006=90(); Physical(r):000FC007=90(); Paged(r):000FC007=90()
Physical(r):000FC008=90(); Paged(r):000FC008=90(); Physical(r):000FC009=90(); Paged(r):000FC009=90(); Physical(r):000FC00A=90(); Paged(r):000FC00A=90(); Physical(r):000FC00B=90(); Paged(r):000FC00B=90()
Physical(r):000FC00C=90(); Paged(r):000FC00C=90(); Physical(r):000FC00D=90(); Paged(r):000FC00D=90(); Physical(r):000FC00E=90(); Paged(r):000FC00E=90(); Physical(r):000FC00F=90(); Paged(r):000FC00F=90()
0010:0000c001 F4 hlt
Registers:
EAX: 00000800 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010000 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000c001 EFLAGS: 00000016
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00oditsz0A0P1c
0010:0000c002 F4 <hlt>
Registers:
EAX: 00000800 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010000 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000c002 EFLAGS: 00000016
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00oditsz0A0P1cH

But it's modulo 9, so nothing is rotated and overflow isn't affected? Carry is set to bit 0?

	case 2: //RCL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>7); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 3: //RCR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
overflow = (((s >> 7)&1)^FLAG_CF);
tempCF = FLAG_CF;
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FU) | (tempCF << 7);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

Edit: The normal POST EE "SARr B" test is giving output and flags errors now, too:S
Edit: Removing the
if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Limit count! Not to be limited!
line from the byte SAR instruction fixed those bugs.

The normal SHL/SHR instructions seem to still cause problem, though?

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

Reply 134 of 178, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

Just fixed the auxiliary flag to set(shl/shr) or clear(sar) on maskcnt!=0. Now shr crashes because of an invalid carry flag?

For SAR, auxilliary carry flag is always set for CPUs prior to Pentium 2 if count &0x1F != 0.

Reply 135 of 178, by superfury

User metadata
Rank l33t++
Rank
l33t++

UniPCemu clears AF when using SAR without count(maskcnt!=0). SHL/SHR set it when maskcnt!=0. So their behaviour is OK. The carry/overflow flags and sign/zero/parity flags are giving errors(at least on 8-bit shl)?
8-bit GRP2:

byte op_grp2_8(byte cnt, byte varshift) {
//word d,
INLINEREGISTER word s, shift, tempCF, msb;
INLINEREGISTER byte numcnt, maskcnt, overflow;
//word backup;
//if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
numcnt = maskcnt = cnt; //Save count!
s = oper1b;
switch (thereg) {
case 0: //ROL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>7); //Save MSB!
s = (s << 1)|FLAG_CF;
overflow = (((s >> 7) & 1)^FLAG_CF); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 1: //ROR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FU) | (FLAG_CF << 7);
overflow = ((s >> 7) ^ ((s >> 6) & 1)); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>7); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 2: //RCL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>7); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 3: //RCR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
overflow = (((s >> 7)&1)^FLAG_CF);
tempCF = FLAG_CF;
Show last 95 lines
			FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FU) | (tempCF << 7);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 4: case 6: //SHL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if ((EMULATED_CPU>=CPU_80386))
{
if ((maskcnt==0x10) || (maskcnt==0x18))
{
FLAGW_CF(s);
FLAGW_OF(FLAG_CF);
overflow = FLAG_OF;
s = 0; //Make the result zeroed, according to IBMulator?
goto skipshift;
}
if (maskcnt!=8) numcnt &= 7; //Limit count!
}
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>7);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFU;
overflow = (FLAG_CF^(s>>7));
}
skipshift:
if (maskcnt) flag_szp8((uint8_t)(s&0xFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 5: //SHR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
if (maskcnt && ((maskcnt&7)==0))
{
//Adjusted according to IBMulator!
FLAGW_CF(s>>7); //Always sets CF, according to various sources?
}
for (shift = 1; shift <= numcnt; shift++) {
overflow = (s>>7);
if (numcnt&7) FLAGW_CF(s);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt) flag_szp8((uint8_t)(s & 0xFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 7: //SAR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Limit count! Not to be limited!
msb = s & 0x80U;
//FLAGW_AF(0);
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_AF(0);
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 (!maskcnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_szp8((uint8_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (numcnt) //Anything shifted at all?
{
flag_szp8((uint8_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared with count as well?
}
break;
}
op_grp2_cycles(numcnt, varshift);
return (s & 0xFFU);
}

16-bit GRP2:

word op_grp2_16(byte cnt, byte varshift) {
//word d,
INLINEREGISTER uint_32 s, shift, tempCF, msb;
INLINEREGISTER byte numcnt, maskcnt, overflow;
//word backup;
//if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
numcnt = maskcnt = cnt; //Save count!
s = oper1;
switch (thereg) {
case 0: //ROL r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>15); //Save MSB!
s = (s << 1)|FLAG_CF;
overflow = (((s >> 15) & 1)^FLAG_CF); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 1: //ROR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFU) | (FLAG_CF << 15);
overflow = ((s >> 15) ^ ((s >> 14) & 1)); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 2: //RCL r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>15); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 15) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 3: //RCR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
overflow = ((s >> 15)^FLAG_CF);
tempCF = FLAG_CF;
Show last 78 lines
			FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFU) | (tempCF << 15);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 4: case 6: //SHL r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>15);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFFFU;
overflow = (FLAG_CF^(s>>15));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
if (maskcnt) flag_szp16((uint16_t)(s&0xFFFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 5: //SHR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
overflow = (s>>15);
FLAGW_CF(s);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) flag_szp16((uint16_t)(s & 0xFFFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 7: //SAR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
msb = s & 0x8000U;
//FLAGW_AF(0);
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_AF(0);
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 (!maskcnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_szp16(s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (numcnt) //Anything shifted at all?
{
flag_szp16(s); //Affect sign as well!
FLAGW_OF(0); //Cleared with count as well?
}
break;
}
op_grp2_cycles(numcnt, varshift);
return (s & 0xFFFFU);
}

32-bit GRP2:

uint_32 op_grp2_32(byte cnt, byte varshift) {
//word d,
INLINEREGISTER uint_64 s, shift, tempCF, msb;
INLINEREGISTER byte numcnt,maskcnt,overflow;
//word backup;
//if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
numcnt = maskcnt = cnt; //Save count!
s = oper1d;
switch (thereg) {
case 0: //ROL r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>31); //Save MSB!
s = (s << 1)|FLAG_CF;
overflow = (((s >> 31) & 1)^FLAG_CF);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 1: //ROR r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFFFFFU) | (FLAG_CF << 31);
overflow = ((s >> 31) ^ ((s >> 30) & 1));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 2: //RCL r/m32
if (EMULATED_CPU >= CPU_80386) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>31); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 31) & 1)^FLAG_CF); //OF=MSB^CF
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 3: //RCR r/m32
if (EMULATED_CPU >= CPU_80386) maskcnt %= 33; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
overflow = (((s >> 31)&1)^FLAG_CF);
tempCF = FLAG_CF;
Show last 78 lines
			FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFFFFFU) | (tempCF << 31);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 4: case 6: //SHL r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>31);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFFFFFFFU;
overflow = (FLAG_CF^(s>>31));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
if (maskcnt) flag_szp32((uint32_t)(s&0xFFFFFFFFU));
break;

case 5: //SHR r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
overflow = (s>>31);
FLAGW_CF(s);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
if (maskcnt) flag_szp32((uint32_t)(s & 0xFFFFFFFFU));
break;

case 7: //SAR r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
msb = s & 0x80000000U;
//FLAGW_AF(0);
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_AF(0);
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 (!maskcnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_szp32((uint32_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (numcnt) //Anything shifted at all?
{
flag_szp32((uint32_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared with count as well?
}
break;
}
op_grp2_cycles32(numcnt, varshift);
return (s & 0xFFFFFFFFU);
}

Can you see what's wrong, peterferrie?

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

Reply 136 of 178, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie

SAR should set AF not clear it when count != 0.
Looking at 8-bit SHL, you don't need the special-casing for count=0x10 and 0x18. They should both behave like count=8.
OF will be set as expected, regardless of the count, so:

mov al,0x40
shl al, 0x10

will still perform the shift, AL will be zero, and OF will be set.
Carry is set as expected, too, so:

mov al,1
shl al,8

will still perform the shift, AL will be zero, and CF will be set.
Sign and parity are set according to the result (i.e. SF is s&0x80, PF=parity of the result).

I suggest that you remove the special-casing and let the "for" loop do the work.

Reply 137 of 178, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've adjusted the 8-bit functionality, but it still crashes(with results 0x800 in resulting flags instead of 0x1 after 8-bit rcr)?

Filename
debugger_UniPCemu_20171122_2219.zip
File size
339.38 KiB
Downloads
82 downloads
File comment
Log result of the new UniPCemu adjustments POST E0 test results.
File license
Fair use/fair dealing exception

8-bit:

byte op_grp2_8(byte cnt, byte varshift) {
//word d,
INLINEREGISTER word s, shift, tempCF, msb;
INLINEREGISTER byte numcnt, maskcnt, overflow;
//word backup;
//if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
numcnt = maskcnt = cnt; //Save count!
s = oper1b;
switch (thereg) {
case 0: //ROL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>7); //Save MSB!
s = (s << 1)|FLAG_CF;
overflow = (((s >> 7) & 1)^FLAG_CF); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 1: //ROR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FU) | (FLAG_CF << 7);
overflow = ((s >> 7) ^ ((s >> 6) & 1)); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>7); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 2: //RCL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>7); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 3: //RCR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
overflow = (((s >> 7)&1)^FLAG_CF);
tempCF = FLAG_CF;
Show last 90 lines
			FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FU) | (tempCF << 7);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 4: case 6: //SHL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if ((EMULATED_CPU>=CPU_80386))
{
if (((maskcnt&0x18)==maskcnt) && maskcnt) //8/16/24 shifts?
{
numcnt = maskcnt = 8; //Brhave like a 8 bit shift!
}
else numcnt &= 7; //Limit count!
}
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>7);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFU;
overflow = (FLAG_CF^(s>>7));
}
skipshift:
if (maskcnt) flag_szp8((uint8_t)(s&0xFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;
case 5: //SHR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
if (maskcnt && ((maskcnt&7)==0))
{
//Adjusted according to IBMulator!
FLAGW_CF(s>>7); //Always sets CF, according to various sources?
}
for (shift = 1; shift <= numcnt; shift++) {
overflow = (s>>7);
if (numcnt&7) FLAGW_CF(s);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt) flag_szp8((uint8_t)(s & 0xFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 7: //SAR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Limit count! Not to be limited!
msb = s & 0x80U;
//FLAGW_AF(0);
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_AF(1);
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 (!maskcnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_szp8((uint8_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (numcnt) //Anything shifted at all?
{
flag_szp8((uint8_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared with count as well?
}
break;
}
op_grp2_cycles(numcnt, varshift);
return (s & 0xFFU);
}

16-bit:

word op_grp2_16(byte cnt, byte varshift) {
//word d,
INLINEREGISTER uint_32 s, shift, tempCF, msb;
INLINEREGISTER byte numcnt, maskcnt, overflow;
//word backup;
//if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
numcnt = maskcnt = cnt; //Save count!
s = oper1;
switch (thereg) {
case 0: //ROL r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>15); //Save MSB!
s = (s << 1)|FLAG_CF;
overflow = (((s >> 15) & 1)^FLAG_CF); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 1: //ROR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFU) | (FLAG_CF << 15);
overflow = ((s >> 15) ^ ((s >> 14) & 1)); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 2: //RCL r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>15); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 15) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 3: //RCR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
overflow = ((s >> 15)^FLAG_CF);
tempCF = FLAG_CF;
Show last 78 lines
			FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFU) | (tempCF << 15);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 4: case 6: //SHL r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>15);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFFFU;
overflow = (FLAG_CF^(s>>15));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
if (maskcnt) flag_szp16((uint16_t)(s&0xFFFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 5: //SHR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
overflow = (s>>15);
FLAGW_CF(s);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) flag_szp16((uint16_t)(s & 0xFFFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 7: //SAR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
msb = s & 0x8000U;
//FLAGW_AF(0);
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_AF(1);
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 (!maskcnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_szp16(s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (numcnt) //Anything shifted at all?
{
flag_szp16(s); //Affect sign as well!
FLAGW_OF(0); //Cleared with count as well?
}
break;
}
op_grp2_cycles(numcnt, varshift);
return (s & 0xFFFFU);
}

32-bit:

uint_32 op_grp2_32(byte cnt, byte varshift) {
//word d,
INLINEREGISTER uint_64 s, shift, tempCF, msb;
INLINEREGISTER byte numcnt,maskcnt,overflow;
//word backup;
//if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
numcnt = maskcnt = cnt; //Save count!
s = oper1d;
switch (thereg) {
case 0: //ROL r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>31); //Save MSB!
s = (s << 1)|FLAG_CF;
overflow = (((s >> 31) & 1)^FLAG_CF);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 1: //ROR r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFFFFFU) | (FLAG_CF << 31);
overflow = ((s >> 31) ^ ((s >> 30) & 1));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 2: //RCL r/m32
if (EMULATED_CPU >= CPU_80386) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>31); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 31) & 1)^FLAG_CF); //OF=MSB^CF
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 3: //RCR r/m32
if (EMULATED_CPU >= CPU_80386) maskcnt %= 33; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
overflow = (((s >> 31)&1)^FLAG_CF);
tempCF = FLAG_CF;
Show last 78 lines
			FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFFFFFU) | (tempCF << 31);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 4: case 6: //SHL r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>31);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFFFFFFFU;
overflow = (FLAG_CF^(s>>31));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
if (maskcnt) flag_szp32((uint32_t)(s&0xFFFFFFFFU));
break;

case 5: //SHR r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
overflow = (s>>31);
FLAGW_CF(s);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
if (maskcnt) flag_szp32((uint32_t)(s & 0xFFFFFFFFU));
break;

case 7: //SAR r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
msb = s & 0x80000000U;
//FLAGW_AF(0);
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_AF(1);
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 (!maskcnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_szp32((uint32_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (numcnt) //Anything shifted at all?
{
flag_szp32((uint32_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared with count as well?
}
break;
}
op_grp2_cycles32(numcnt, varshift);
return (s & 0xFFFFFFFFU);
}

Can you 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 138 of 178, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've just modified the instructions to match peterferrie's first comment at https://github.com/barotto/test386.asm/issues/1 . Now the entire testsuite(including undefined flags part) succeeds 100% without errors 😁 It's running the current testsuite(The test386.asm commit of Sunday, 11/19/2017 18:45)

Current GRP2 opcodes:

8-bit

byte op_grp2_8(byte cnt, byte varshift) {
//word d,
INLINEREGISTER word s, shift, tempCF, msb;
INLINEREGISTER byte numcnt, maskcnt, overflow;
//word backup;
//if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
numcnt = maskcnt = cnt; //Save count!
s = oper1b;
switch (thereg) {
case 0: //ROL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>7); //Save MSB!
s = (s << 1)|FLAG_CF;
overflow = (((s >> 7) & 1)^FLAG_CF); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 1: //ROR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FU) | (FLAG_CF << 7);
overflow = ((s >> 7) ^ ((s >> 6) & 1)); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>7); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 2: //RCL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if ((EMULATED_CPU>=CPU_80386) && (maskcnt>9)) numcnt %= 9; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>7); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 3: //RCR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if ((EMULATED_CPU>=CPU_80386) && (maskcnt>9)) numcnt %= 9; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
overflow = (((s >> 7)&1)^FLAG_CF);
tempCF = FLAG_CF;
Show last 91 lines
			FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FU) | (tempCF << 7);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 4: case 6: //SHL r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if ((EMULATED_CPU>=CPU_80386))
{
if (((maskcnt&0x18)==maskcnt) && maskcnt) //8/16/24 shifts?
{
numcnt = maskcnt = 8; //Brhave like a 8 bit shift!
}
else numcnt &= 7; //Limit count!
}
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>7);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFU;
overflow = (FLAG_CF^(s>>7));
}
skipshift:
if (maskcnt) flag_szp8((uint8_t)(s&0xFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 5: //SHR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
if (maskcnt && ((maskcnt&7)==0))
{
//Adjusted according to IBMulator!
FLAGW_CF(s>>7); //Always sets CF, according to various sources?
}
for (shift = 1; shift <= numcnt; shift++) {
overflow = (s>>7);
if (numcnt&7) FLAGW_CF(s);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt) flag_szp8((uint8_t)(s & 0xFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 7: //SAR r/m8
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Limit count! Not to be limited!
msb = s & 0x80U;
//FLAGW_AF(0);
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_AF(1);
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 (!maskcnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_szp8((uint8_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (numcnt) //Anything shifted at all?
{
flag_szp8((uint8_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared with count as well?
}
break;
}
op_grp2_cycles(numcnt, varshift);
return (s & 0xFFU);
}

16-bit:

word op_grp2_16(byte cnt, byte varshift) {
//word d,
INLINEREGISTER uint_32 s, shift, tempCF, msb;
INLINEREGISTER byte numcnt, maskcnt, overflow;
//word backup;
//if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
numcnt = maskcnt = cnt; //Save count!
s = oper1;
switch (thereg) {
case 0: //ROL r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>15); //Save MSB!
s = (s << 1)|FLAG_CF;
overflow = (((s >> 15) & 1)^FLAG_CF); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 1: //ROR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFU) | (FLAG_CF << 15);
overflow = ((s >> 15) ^ ((s >> 14) & 1)); //Only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 2: //RCL r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if ((EMULATED_CPU>=CPU_80386) && (maskcnt>17)) numcnt %= 17; //Operand size wrap!
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>15); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 15) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 3: //RCR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if ((EMULATED_CPU>=CPU_80386) && (maskcnt>17)) numcnt %= 17; //Operand size wrap!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
overflow = ((s >> 15)^FLAG_CF);
tempCF = FLAG_CF;
Show last 78 lines
			FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFU) | (tempCF << 15);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
break;

case 4: case 6: //SHL r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>15);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFFFU;
overflow = (FLAG_CF^(s>>15));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
if (maskcnt) flag_szp16((uint16_t)(s&0xFFFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 5: //SHR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
overflow = (s>>15);
FLAGW_CF(s);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) flag_szp16((uint16_t)(s & 0xFFFFU));
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
break;

case 7: //SAR r/m16
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
msb = s & 0x8000U;
//FLAGW_AF(0);
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_AF(1);
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 (!maskcnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_szp16(s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (numcnt) //Anything shifted at all?
{
flag_szp16(s); //Affect sign as well!
FLAGW_OF(0); //Cleared with count as well?
}
break;
}
op_grp2_cycles(numcnt, varshift);
return (s & 0xFFFFU);
}

32-bit:

uint_32 op_grp2_32(byte cnt, byte varshift) {
//word d,
INLINEREGISTER uint_64 s, shift, tempCF, msb;
INLINEREGISTER byte numcnt,maskcnt,overflow;
//word backup;
//if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
numcnt = maskcnt = cnt; //Save count!
s = oper1d;
switch (thereg) {
case 0: //ROL r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>31); //Save MSB!
s = (s << 1)|FLAG_CF;
overflow = (((s >> 31) & 1)^FLAG_CF);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 1: //ROR r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFFFFFU) | (FLAG_CF << 31);
overflow = ((s >> 31) ^ ((s >> 30) & 1));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 2: //RCL r/m32
if (EMULATED_CPU >= CPU_80386) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
tempCF = FLAG_CF;
FLAGW_CF(s>>31); //Save MSB!
s = (s << 1)|tempCF; //Shift and set CF!
overflow = (((s >> 31) & 1)^FLAG_CF); //OF=MSB^CF
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 3: //RCR r/m32
if (EMULATED_CPU >= CPU_80386) maskcnt %= 33; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
overflow = numcnt?0:FLAG_OF; //Default: no overflow!
for (shift = 1; shift <= numcnt; shift++) {
overflow = (((s >> 31)&1)^FLAG_CF);
tempCF = FLAG_CF;
Show last 78 lines
			FLAGW_CF(s); //Save LSB!
s = ((s >> 1)&0x7FFFFFFFU) | (tempCF << 31);
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow); //Overflow?
break;

case 4: case 6: //SHL r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s>>31);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFFFFFFFU;
overflow = (FLAG_CF^(s>>31));
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
if (maskcnt) flag_szp32((uint32_t)(s&0xFFFFFFFFU));
break;

case 5: //SHR r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
//FLAGW_AF(0);
overflow = numcnt?0:FLAG_OF;
for (shift = 1; shift <= numcnt; shift++) {
overflow = (s>>31);
FLAGW_CF(s);
//backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_OF(overflow);
if (maskcnt) FLAGW_AF(1);
if (maskcnt) flag_szp32((uint32_t)(s & 0xFFFFFFFFU));
break;

case 7: //SAR r/m32
if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
numcnt = maskcnt;
msb = s & 0x80000000U;
//FLAGW_AF(0);
for (shift = 1; shift <= numcnt; shift++) {
FLAGW_CF(s);
//backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
if (maskcnt) FLAGW_AF(1);
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 (!maskcnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_szp32((uint32_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (numcnt) //Anything shifted at all?
{
flag_szp32((uint32_t)s); //Affect sign as well!
FLAGW_OF(0); //Cleared with count as well?
}
break;
}
op_grp2_cycles32(numcnt, varshift);
return (s & 0xFFFFFFFFU);
}

Is that behaviour for all those opcodes 100% correct, peterferrie?

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

Reply 139 of 178, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just found out two little things(checks out without errors on the test386.asm testsuite, errors out on the 80186 testsuite):
- BCD instructions(various tests(bcd,mul)) flags.
- SHL auxilliary carry flag

Although it might just be because of the change in logic between 286+ and older CPUs(186-) for the BCD instructions, SHL erroring out on the auxilliary carry flag is odd(passes the extended tests in test386.asm). I think the 80186 testsuite result files might have been created on a 286+, since the logic of the high 4 bits of the flags aren't set in the result files?

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