First post, by superfury
I'm trying to get my 8/16/32-bit shift/rotate(GRP2 opcodes) instructions result in fully correct flags, but for some reason, it doesn't check out in the EPC 80186 testsuite(ran on the UniPCemu 80286 emulation).
GRP2 8-bit
byte op_grp2_8(byte cnt, byte varshift) {
//word d,
INLINEREGISTER word s, shift, oldCF, msb;
word backup;
//if (cnt>0x8) return(oper1b); //NEC V20/V30+ limits shift count
s = oper1b;
oldCF = FLAG_CF;
if (EMULATED_CPU >= CPU_NECV30) cnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
switch (thereg) {
case 0: //ROL r/m8
for (shift = 1; shift <= cnt; shift++) {
if (s & 0x80) FLAGW_CF(1); else FLAGW_CF(0);
s = s << 1;
s = s | FLAG_CF;
}
if (cnt==1) FLAGW_OF(FLAG_CF ^ ((s >> 7) & 1));
break;
case 1: //ROR r/m8
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
s = (s >> 1) | (FLAG_CF << 7);
}
if (cnt==1) FLAGW_OF((s >> 7) ^ ((s >> 6) & 1));
break;
case 2: //RCL r/m8
for (shift = 1; shift <= cnt; shift++) {
oldCF = FLAG_CF;
if (s & 0x80) FLAGW_CF(1); else FLAGW_CF(0);
s = s << 1;
s = s | oldCF;
}
if (cnt==1) FLAGW_OF(FLAG_CF ^ ((s >> 7) & 1));
break;
case 3: //RCR r/m8
for (shift = 1; shift <= cnt; shift++) {
oldCF = FLAG_CF;
FLAGW_CF(s & 1);
s = (s >> 1) | (oldCF << 7);
}
if (cnt==1) FLAGW_OF((s >> 7) ^ ((s >> 6) & 1));
break;
case 4: case 6: //SHL r/m8
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
if (s & 0x80) FLAGW_CF(1); else FLAGW_CF(0);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFF;
}
if (cnt==1) FLAGW_OF((FLAG_CF ^ (s >> 7)));
flag_szp8((uint8_t)(s&0xFF)); break;
case 5: //SHR r/m8
if (cnt == 1) FLAGW_OF((s & 0x80) ? 1 : 0); else FLAGW_OF(0);
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
flag_szp8((uint8_t)(s & 0xFF)); break;
case 7: //SAR r/m8
msb = s & 0x80;
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
byte tempSF;
tempSF = FLAG_SF; //Save the SF!
/*flag_szp8((uint8_t)(s & 0xFF));*/
//http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#SAR says only C and O flags!
if (!cnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (cnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_s8(s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (cnt) //Anything shifted at all?
{
flag_s8(s); //Affect sign as well!
}
if ((EMULATED_CPU>=CPU_NECV30) && cnt) //NECV20+ affected?
{
flag_p8(s); //Affect parity as well!
}
break;
}
op_grp2_cycles(cnt, varshift);
return(s & 0xFF);
}
GRP2 16-bit
word op_grp2_16(byte cnt, byte varshift) {
//uint32_t d,
INLINEREGISTER uint_32 s, shift, oldCF, msb;
//if (cnt>0x10) return(oper1); //NEC V20/V30+ limits shift count
if (EMULATED_CPU >= CPU_NECV30) cnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
word backup;
s = oper1;
oldCF = FLAG_CF;
switch (thereg) {
case 0: //ROL r/m16
for (shift = 1; shift <= cnt; shift++) {
if (s & 0x8000) FLAGW_CF(1); else FLAGW_CF(0);
s = s << 1;
s = s | FLAG_CF;
}
if (cnt==1) FLAGW_OF(FLAG_CF ^ ((s >> 15) & 1));
break;
case 1: //ROR r/m16
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
s = (s >> 1) | (FLAG_CF << 15);
}
if (cnt==1) FLAGW_OF((s >> 15) ^ ((s >> 14) & 1));
break;
case 2: //RCL r/m16
for (shift = 1; shift <= cnt; shift++) {
oldCF = FLAG_CF;
if (s & 0x8000) FLAGW_CF(1); else FLAGW_CF(0);
s = s << 1;
s = s | oldCF;
//oldCF = ((s&0x8000)>>15)&1; //Save FLAG_CF!
//s = (s<<1)+FLAG_CF;
//FLAG_CF = oldCF;
}
if (cnt==1) FLAGW_OF(FLAG_CF ^ ((s >> 15) & 1));
break;
case 3: //RCR r/m16
if (cnt==1) FLAGW_OF(((s >> 15) & 1) ^ FLAG_CF);
for (shift = 1; shift <= cnt; shift++) {
oldCF = FLAG_CF;
FLAGW_CF(s & 1);
s = (s >> 1) | (oldCF << 15);
//oldCF = s&1;
//s = (s<<1)+(FLAG_CF<<16);
//FLAG_CF = oldCF;
}
if (cnt==1) FLAGW_OF((s >> 15) ^ ((s >> 14) & 1));
break;
case 4: case 6: //SHL r/m16
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
if (s & 0x8000) FLAGW_CF(1); else FLAGW_CF(0);
//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
s = (s << 1) & 0xFFFF;
}
if ((cnt) && (FLAG_CF == (s >> 15))) FLAGW_OF(0); else FLAGW_OF(1);
flag_szp16(s); break;
case 5: //SHR r/m16
if (cnt) FLAGW_OF((s & 0x8000) ? 1 : 0);
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
backup = s; //Save backup!
s = s >> 1;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
flag_szp16(s); break;
case 7: //SAR r/m16
msb = s & 0x8000; //Read the MSB!
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
backup = s; //Save backup!
s = (s >> 1) | msb;
//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
}
byte tempSF;
tempSF = FLAG_SF; //Save the SF!
/*flag_szp16(s);*/
//http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#SAR says only C and O flags!
if (!cnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (cnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_s16(s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (cnt) //Anything shifted at all?
{
flag_s16(s); //Affect sign as well!
}
if ((EMULATED_CPU>=CPU_NECV30) && cnt) //NECV20+ affected?
{
flag_p16(s); //Affect parity as well!
flag_s16(s); //Affect sign as well!
}
break;
}
op_grp2_cycles(cnt, varshift|4);
return(s & 0xFFFF);
}
GRP2 32-bit:
uint_32 op_grp2_32(byte cnt, byte varshift) {
//uint32_t d,
INLINEREGISTER uint_32 s, shift, oldCF, msb;
//if (cnt>0x10) return(oper1d); //NEC V20/V30+ limits shift count
if (EMULATED_CPU >= CPU_NECV30) cnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
s = oper1d;
oldCF = FLAG_CF;
switch (thereg) {
case 0: //ROL r/m32
for (shift = 1; shift <= cnt; shift++) {
if (s & 0x80000000) FLAGW_CF(1); else FLAGW_CF(0);
s = s << 1;
s = s | FLAG_CF;
}
if (cnt==1) FLAGW_OF(FLAG_CF ^ ((s >> 31) & 1));
break;
case 1: //ROR r/m32
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
s = (s >> 1) | (FLAG_CF << 31);
}
if (cnt==1) FLAGW_OF((s >> 31) ^ ((s >> 30) & 1));
break;
case 2: //RCL r/m32
for (shift = 1; shift <= cnt; shift++) {
oldCF = FLAG_CF;
if (s & 0x80000000) FLAGW_CF(1); else FLAGW_CF(0);
s = s << 1;
s = s | oldCF;
//oldCF = ((s&0x8000)>>15)&1; //Save FLAG_CF!
//s = (s<<1)+FLAG_CF;
//FLAG_CF = oldCF;
}
if (cnt==1) FLAGW_OF(FLAG_CF ^ ((s >> 31) & 1));
break;
case 3: //RCR r/m32
if (cnt==1) FLAGW_OF(((s >> 31) & 1) ^ FLAG_CF);
for (shift = 1; shift <= cnt; shift++) {
oldCF = FLAG_CF;
FLAGW_CF(s & 1);
s = (s >> 1) | (oldCF << 31);
//oldCF = s&1;
//s = (s<<1)+(FLAG_CF<<32);
//FLAG_CF = oldCF;
}
if (cnt==1) FLAGW_OF((s >> 31) ^ ((s >> 30) & 1));
break;
case 4: case 6: //SHL r/m32
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
if (s & 0x80000000) FLAGW_CF(1); else FLAGW_CF(0);
s = (s << 1) & 0xFFFFFFFF;
//FLAGW_AF(1); //Auxiliary carry?
}
if ((cnt==1) && (FLAG_CF == (s >> 31))) FLAGW_OF(0); else FLAGW_OF(1);
flag_szp32(s); break;
case 5: //SHR r/m32
if (cnt==1) FLAGW_OF((s & 0x80000000) ? 1 : 0);
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
s = s >> 1;
//FLAGW_AF(1); //Auxiliary carry?
}
flag_szp32(s); break;
case 7: //SAR r/m32
msb = s & 0x80000000; //Read the MSB!
//FLAGW_AF(0);
for (shift = 1; shift <= cnt; shift++) {
FLAGW_CF(s & 1);
s = (s >> 1) | msb;
//FLAGW_AF(1); //Auxiliary carry?
}
byte tempSF;
tempSF = FLAG_SF; //Save the SF!
/*flag_szp32(s);*/
//http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#SAR says only C and O flags!
if (!cnt) //Nothing done?
{
FLAGW_SF(tempSF); //We don't update when nothing's done!
}
else if (cnt==1) //Overflow is cleared on all 1-bit shifts!
{
flag_s32(s); //Affect sign as well!
FLAGW_OF(0); //Cleared!
}
else if (cnt) //Anything shifted at all?
{
flag_s32(s); //Affect sign as well!
}
if ((EMULATED_CPU>=CPU_NECV30) && cnt) //NECV20+ affected?
{
flag_p32(s); //Affect parity as well!
flag_s32(s); //Affect sign as well!
}
break;
}
op_grp2_cycles32(cnt, varshift|4);
return(s & 0xFFFFFFFF);
}
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