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 count
numcnt = cnt; //Save count!
s = oper1b;
switch (thereg) {
case 0: //ROL r/m8
if (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/m8
if (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/m8
if (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^CF
break;
case 3: //RCR r/m8
if (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/m8
if (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/m8
if (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/m8
if (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 count
numcnt = cnt; //Save count!
s = oper1;
switch (thereg) {
case 0: //ROL r/m16
if (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/m16
if (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/m16
if (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^CF
break;
case 3: //RCR r/m16
if (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/m16
if (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/m16
if (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/m16
if (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 count
numcnt = cnt; //Save count!
s = oper1d;
switch (thereg) {
case 0: //ROL r/m32
if (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/m32
if (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/m32
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)|FLAG_CF; //Shift and set CF!
FLAGW_CF(tempCF); //Set CF!
}
if (numcnt==1) FLAGW_OF(((s >> 31) & 1)^FLAG_CF); //OF=MSB^CF
break;
case 3: //RCR r/m32
if (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/m32
if (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/m32
if (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/m32
if (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