Reply 80 of 178, by superfury
This is what I've gotten so far:
16-bit:
byte op_grp2_8(byte cnt, byte varshift) {//word d,INLINEREGISTER word s, shift, tempCF, msb;INLINEREGISTER byte numcnt;//word backup;//if (cnt>0x8) return(oper1b); //NEC V20/V30+ limits shift countnumcnt = cnt; //Save count!s = oper1b;switch (thereg) {case 0: //ROL r/m8if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!else if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!for (shift = 1; shift <= numcnt; shift++) {tempCF = ((s&0x80)>>7); //Save MSB!s = (s << 1)|tempCF;}FLAGW_CF(s&1); //Set carry flag!if (numcnt==1) FLAGW_OF(((s >> 7) & 1)^FLAG_CF);break;case 1: //ROR r/m8if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!else if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!for (shift = 1; shift <= numcnt; shift++) {tempCF = (s&1); //Save LSB!s = (s >> 1) | (tempCF << 7);}FLAGW_CF(((s&0x80)>>7)); //Set carry flag!if (numcnt==1) FLAGW_OF((s >> 7) ^ ((s >> 6) & 1));break;case 2: //RCL r/m8if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!for (shift = 1; shift <= numcnt; shift++) {tempCF = ((s&0x80)>>7); //Save MSB!s = (s << 1)|FLAG_CF; //Shift and set CF!FLAGW_CF(tempCF); //Set CF!}if (numcnt==1) FLAGW_OF(((s >> 7) & 1)^FLAG_CF); //OF=MSB^CFbreak;case 3: //RCR r/m8if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!if (numcnt==1) FLAGW_OF((s >> 7) ^ FLAG_CF);for (shift = 1; shift <= numcnt; shift++) {tempCF = (s&1); //Save LSB!s = (s >> 1) | (FLAG_CF << 7);FLAGW_CF(tempCF);}break;case 4: case 6: //SHL r/m8if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!//FLAGW_AF(0);for (shift = 1; shift <= numcnt; shift++) {if (s & 0x80) FLAGW_CF(1); else FLAGW_CF(0);//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?s = (s << 1) & 0xFF;
}if (numcnt==1) { if (FLAG_CF==(s>>7)) FLAGW_OF(0); else FLAGW_OF(1); }if (numcnt) flag_szp8((uint8_t)(s&0xFF)); break;case 5: //SHR r/m8if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!if (numcnt==1) { if (s&0x80) FLAGW_OF(1); else FLAGW_OF(0); }//FLAGW_AF(0);for (shift = 1; shift <= numcnt; shift++) {FLAGW_CF(s & 1);//backup = s; //Save backup!s = s >> 1;//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?}if (numcnt) flag_szp8((uint8_t)(s & 0xFF)); break;case 7: //SAR r/m8if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!msb = s & 0x80;//FLAGW_AF(0);for (shift = 1; shift <= numcnt; 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 (!numcnt) //Nothing done?{FLAGW_SF(tempSF); //We don't update when nothing's done!}else if (numcnt==1) //Overflow is cleared on all 1-bit shifts!{flag_szp8(s); //Affect sign as well!FLAGW_OF(0); //Cleared!}else if (numcnt) //Anything shifted at all?{flag_szp8(s); //Affect sign as well!if (EMULATED_CPU<=CPU_NECV30) //Valid to update OF?{FLAGW_OF(0); //Cleared with count as well?}}break;}op_grp2_cycles(numcnt, varshift);return(s & 0xFF);}word op_grp2_16(byte cnt, byte varshift) {//word d,INLINEREGISTER uint_32 s, shift, tempCF, msb;INLINEREGISTER byte numcnt;//word backup;//if (cnt>0x8) return(oper1b); //NEC V20/V30+ limits shift countnumcnt = cnt; //Save count!s = oper1;switch (thereg) {case 0: //ROL r/m16if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!else if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!for (shift = 1; shift <= numcnt; shift++) {tempCF = ((s&0x8000)>>15); //Save MSB!s = (s << 1)|tempCF;}FLAGW_CF(s&1); //Set carry flag!if (numcnt==1) FLAGW_OF(((s >> 15) & 1)^FLAG_CF);break;case 1: //ROR r/m16if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!else if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!for (shift = 1; shift <= numcnt; shift++) {tempCF = (s&1); //Save LSB!s = (s >> 1) | (tempCF << 15);}FLAGW_CF(((s&0x8000)>>15)); //Set carry flag!if (numcnt==1) FLAGW_OF((s >> 15) ^ ((s >> 14) & 1));break;case 2: //RCL r/m16if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!for (shift = 1; shift <= numcnt; shift++) {tempCF = ((s&0x8000)>>15); //Save MSB!s = (s << 1)|FLAG_CF; //Shift and set CF!FLAGW_CF(tempCF); //Set CF!}if (numcnt==1) FLAGW_OF(((s >> 15) & 1)^FLAG_CF); //OF=MSB^CFbreak;case 3: //RCR r/m16if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!if (numcnt==1) FLAGW_OF((s >> 15) ^ FLAG_CF);for (shift = 1; shift <= numcnt; shift++) {tempCF = (s&1); //Save LSB!s = (s >> 1) | (FLAG_CF << 15);FLAGW_CF(tempCF);}break;case 4: case 6: //SHL r/m16if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!//FLAGW_AF(0);for (shift = 1; shift <= numcnt; shift++) {if (s & 0x8000) FLAGW_CF(1); else FLAGW_CF(0);//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?s = (s << 1) & 0xFFFF;}if (numcnt==1) { if (FLAG_CF==(s>>15)) FLAGW_OF(0); else FLAGW_OF(1); }if (numcnt) flag_szp16((uint16_t)(s&0xFFFF)); break;case 5: //SHR r/m16if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!if (numcnt==1) { if (s&0x8000) FLAGW_OF(1); else FLAGW_OF(0); }//FLAGW_AF(0);for (shift = 1; shift <= numcnt; shift++) {FLAGW_CF(s & 1);//backup = s; //Save backup!s = s >> 1;//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?}if (numcnt) flag_szp16((uint16_t)(s & 0xFFFF)); break;case 7: //SAR r/m16if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!msb = s & 0x8000;//FLAGW_AF(0);for (shift = 1; shift <= numcnt; 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 (!numcnt) //Nothing done?{FLAGW_SF(tempSF); //We don't update when nothing's done!}else if (numcnt==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!if (EMULATED_CPU<=CPU_NECV30) //Valid to update OF?{FLAGW_OF(0); //Cleared with count as well?}}break;}op_grp2_cycles(numcnt, varshift);return(s & 0xFFFF);}
32-bit:
uint_32 op_grp2_32(byte cnt, byte varshift) {//word d,INLINEREGISTER uint_64 s, shift, tempCF, msb;INLINEREGISTER byte numcnt;//word backup;//if (cnt>0x8) return(oper1b); //NEC V20/V30+ limits shift countnumcnt = cnt; //Save count!s = oper1d;switch (thereg) {case 0: //ROL r/m32if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!else if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!for (shift = 1; shift <= numcnt; shift++) {tempCF = ((s&0x80000000)>>31); //Save MSB!s = (s << 1)|tempCF;}FLAGW_CF(s&1); //Set carry flag!if (numcnt==1) FLAGW_OF(((s >> 31) & 1)^FLAG_CF);break;case 1: //ROR r/m32if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!else if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!for (shift = 1; shift <= numcnt; shift++) {tempCF = (s&1); //Save LSB!s = (s >> 1) | (tempCF << 31);}FLAGW_CF(((s&0x80000000)>>31)); //Set carry flag!if (numcnt==1) FLAGW_OF((s >> 31) ^ ((s >> 30) & 1));break;case 2: //RCL r/m32if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!for (shift = 1; shift <= numcnt; shift++) {tempCF = ((s&0x80000000)>>31); //Save MSB!s = (s << 1)|FLAG_CF; //Shift and set CF!FLAGW_CF(tempCF); //Set CF!}if (numcnt==1) FLAGW_OF(((s >> 31) & 1)^FLAG_CF); //OF=MSB^CFbreak;case 3: //RCR r/m32if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!if (numcnt==1) FLAGW_OF((s >> 31) ^ FLAG_CF);for (shift = 1; shift <= numcnt; shift++) {tempCF = (s&1); //Save LSB!s = (s >> 1) | (FLAG_CF << 31);FLAGW_CF(tempCF);}break;case 4: case 6: //SHL r/m32if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!//FLAGW_AF(0);for (shift = 1; shift <= numcnt; shift++) {if (s & 0x80000000) FLAGW_CF(1); else FLAGW_CF(0);//if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?s = (s << 1) & 0xFFFFFFFF;}if (numcnt==1) { if (FLAG_CF==(s>>31)) FLAGW_OF(0); else FLAGW_OF(1); }
if (numcnt) flag_szp32((uint32_t)(s&0xFFFFFFFF)); break;case 5: //SHR r/m32if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!if (numcnt==1) { if (s&0x80000000) FLAGW_OF(1); else FLAGW_OF(0); }//FLAGW_AF(0);for (shift = 1; shift <= numcnt; shift++) {FLAGW_CF(s & 1);//backup = s; //Save backup!s = s >> 1;//if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?}if (numcnt) flag_szp32((uint32_t)(s & 0xFFFFFFFF)); break;case 7: //SAR r/m32if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!msb = s & 0x80000000;//FLAGW_AF(0);for (shift = 1; shift <= numcnt; 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 (!numcnt) //Nothing done?{FLAGW_SF(tempSF); //We don't update when nothing's done!}else if (numcnt==1) //Overflow is cleared on all 1-bit shifts!{flag_szp32(s); //Affect sign as well!FLAGW_OF(0); //Cleared!}else if (numcnt) //Anything shifted at all?{flag_szp32(s); //Affect sign as well!if (EMULATED_CPU<=CPU_NECV30) //Valid to update OF?{FLAGW_OF(0); //Cleared with count as well?}}break;}op_grp2_cycles32(numcnt, varshift);return(s & 0xFFFFFFFF);}
There are still several things failing now(according to WinMerge, EDX/EAX is correct in all cases):
- ROLi B/W, ROLr, RORr: carry flag incorrectly set(set/not set)?
- RCLi B/W, RCRi B/W: missing Overflow flag set?
- RCRr: missing carry flag set(incorrectly)?
Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io