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 counts = 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/m8for (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/m8for (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/m8for (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/m8for (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/m8if (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/m8msb = 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 countif (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/m16for (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/m16for (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/m16for (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/m16if (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/m16if (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/m16msb = 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 countif (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/m32for (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/m32for (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/m32for (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/m32if (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/m32if (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/m32msb = 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