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)?
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
1mov eax,20 2stc 3rcl 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.
1mov al,20 2stc 3rcl 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.
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.
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 😀
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?
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.
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.
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?
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?
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?
1FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected! 2FLAGW_SF(0); //Clear Sign!
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):
1 if ((EMULATED_CPU>=CPU_80386)) 2 { 3 if ((maskcnt==0x10) || (maskcnt==0x18)) 4 { 5 FLAGW_CF(s); 6 FLAGW_OF(FLAG_CF); 7 overflow = FLAG_OF; 8 s = 0; //Make the result zeroed, according to IBMulator? 9 goto skipshift; 10 } 11 if (maskcnt!=8) numcnt &= 7; //Limit count! 12 }
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?
But it's modulo 9, so nothing is rotated and overflow isn't affected? Carry is set to bit 0?
1 case 2: //RCL r/m8 2 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 3 numcnt = maskcnt; 4 if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap! 5 overflow = numcnt?0:FLAG_OF; 6 for (shift = 1; shift <= numcnt; shift++) { 7 tempCF = FLAG_CF; 8 FLAGW_CF(s>>7); //Save MSB! 9 s = (s << 1)|tempCF; //Shift and set CF! 10 overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL? 11 } 12 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 13 if (maskcnt) FLAGW_OF(overflow); 14 break; 15 16 case 3: //RCR r/m8 17 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 18 numcnt = maskcnt; 19 if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap! 20 overflow = numcnt?0:FLAG_OF; 21 for (shift = 1; shift <= numcnt; shift++) { 22 overflow = (((s >> 7)&1)^FLAG_CF); 23 tempCF = FLAG_CF; 24 FLAGW_CF(s); //Save LSB! 25 s = ((s >> 1)&0x7FU) | (tempCF << 7); 26 } 27 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 28 if (maskcnt) FLAGW_OF(overflow); 29 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?
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:
1byte op_grp2_8(byte cnt, byte varshift) { 2 //word d, 3 INLINEREGISTER word s, shift, tempCF, msb; 4 INLINEREGISTER byte numcnt, maskcnt, overflow; 5 //word backup; 6 //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count 7 numcnt = maskcnt = cnt; //Save count! 8 s = oper1b; 9 switch (thereg) { 10 case 0: //ROL r/m8 11 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 12 numcnt = maskcnt; 13 if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap! 14 overflow = numcnt?0:FLAG_OF; 15 for (shift = 1; shift <= numcnt; shift++) { 16 FLAGW_CF(s>>7); //Save MSB! 17 s = (s << 1)|FLAG_CF; 18 overflow = (((s >> 7) & 1)^FLAG_CF); //Only when not using CL? 19 } 20 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 21 if (maskcnt) FLAGW_OF(overflow); 22 break; 23 24 case 1: //ROR r/m8 25 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 26 numcnt = maskcnt; 27 if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap! 28 overflow = numcnt?0:FLAG_OF; 29 for (shift = 1; shift <= numcnt; shift++) { 30 FLAGW_CF(s); //Save LSB! 31 s = ((s >> 1)&0x7FU) | (FLAG_CF << 7); 32 overflow = ((s >> 7) ^ ((s >> 6) & 1)); //Only when not using CL? 33 } 34 if (maskcnt && (numcnt==0)) FLAGW_CF(s>>7); //Always sets CF, according to various sources? 35 if (maskcnt) FLAGW_OF(overflow); 36 break; 37 38 case 2: //RCL r/m8 39 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 40 numcnt = maskcnt; 41 if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap! 42 overflow = numcnt?0:FLAG_OF; 43 for (shift = 1; shift <= numcnt; shift++) { 44 tempCF = FLAG_CF; 45 FLAGW_CF(s>>7); //Save MSB! 46 s = (s << 1)|tempCF; //Shift and set CF! 47 overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL? 48 } 49 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 50 if (maskcnt) FLAGW_OF(overflow); 51 break; 52 53 case 3: //RCR r/m8 54 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 55 numcnt = maskcnt; 56 if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap! 57 overflow = numcnt?0:FLAG_OF; 58 for (shift = 1; shift <= numcnt; shift++) { 59 overflow = (((s >> 7)&1)^FLAG_CF); 60 tempCF = FLAG_CF;
…Show last 95 lines
61 FLAGW_CF(s); //Save LSB! 62 s = ((s >> 1)&0x7FU) | (tempCF << 7); 63 } 64 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 65 if (maskcnt) FLAGW_OF(overflow); 66 break; 67 68 case 4: case 6: //SHL r/m8 69 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 70 numcnt = maskcnt; 71 if ((EMULATED_CPU>=CPU_80386)) 72 { 73 if ((maskcnt==0x10) || (maskcnt==0x18)) 74 { 75 FLAGW_CF(s); 76 FLAGW_OF(FLAG_CF); 77 overflow = FLAG_OF; 78 s = 0; //Make the result zeroed, according to IBMulator? 79 goto skipshift; 80 } 81 if (maskcnt!=8) numcnt &= 7; //Limit count! 82 } 83 //FLAGW_AF(0); 84 overflow = numcnt?0:FLAG_OF; 85 for (shift = 1; shift <= numcnt; shift++) { 86 FLAGW_CF(s>>7); 87 //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry? 88 s = (s << 1) & 0xFFU; 89 overflow = (FLAG_CF^(s>>7)); 90 } 91 skipshift: 92 if (maskcnt) flag_szp8((uint8_t)(s&0xFFU)); 93 if (maskcnt) FLAGW_OF(overflow); 94 if (maskcnt) FLAGW_AF(1); 95 break; 96 97 case 5: //SHR r/m8 98 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 99 numcnt = maskcnt; 100 //FLAGW_AF(0); 101 overflow = numcnt?0:FLAG_OF; 102 if (maskcnt && ((maskcnt&7)==0)) 103 { 104 //Adjusted according to IBMulator! 105 FLAGW_CF(s>>7); //Always sets CF, according to various sources? 106 } 107 for (shift = 1; shift <= numcnt; shift++) { 108 overflow = (s>>7); 109 if (numcnt&7) FLAGW_CF(s); 110 //backup = s; //Save backup! 111 s = s >> 1; 112 //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry? 113 } 114 if (maskcnt) flag_szp8((uint8_t)(s & 0xFFU)); 115 if (maskcnt) FLAGW_OF(overflow); 116 if (maskcnt) FLAGW_AF(1); 117 break; 118 119 case 7: //SAR r/m8 120 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 121 numcnt = maskcnt; 122 //if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Limit count! Not to be limited! 123 msb = s & 0x80U; 124 //FLAGW_AF(0); 125 for (shift = 1; shift <= numcnt; shift++) { 126 FLAGW_CF(s); 127 //backup = s; //Save backup! 128 s = (s >> 1) | msb; 129 //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry? 130 } 131 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 132 if (maskcnt) FLAGW_AF(0); 133 byte tempSF; 134 tempSF = FLAG_SF; //Save the SF! 135 /*flag_szp8((uint8_t)(s & 0xFF));*/ 136 //http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#SAR says only C and O flags! 137 if (!maskcnt) //Nothing done? 138 { 139 FLAGW_SF(tempSF); //We don't update when nothing's done! 140 } 141 else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts! 142 { 143 flag_szp8((uint8_t)s); //Affect sign as well! 144 FLAGW_OF(0); //Cleared! 145 } 146 else if (numcnt) //Anything shifted at all? 147 { 148 flag_szp8((uint8_t)s); //Affect sign as well! 149 FLAGW_OF(0); //Cleared with count as well? 150 } 151 break; 152 } 153 op_grp2_cycles(numcnt, varshift); 154 return (s & 0xFFU); 155}
16-bit GRP2:
1word op_grp2_16(byte cnt, byte varshift) { 2 //word d, 3 INLINEREGISTER uint_32 s, shift, tempCF, msb; 4 INLINEREGISTER byte numcnt, maskcnt, overflow; 5 //word backup; 6 //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count 7 numcnt = maskcnt = cnt; //Save count! 8 s = oper1; 9 switch (thereg) { 10 case 0: //ROL r/m16 11 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 12 numcnt = maskcnt; 13 if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap! 14 overflow = numcnt?0:FLAG_OF; 15 for (shift = 1; shift <= numcnt; shift++) { 16 FLAGW_CF(s>>15); //Save MSB! 17 s = (s << 1)|FLAG_CF; 18 overflow = (((s >> 15) & 1)^FLAG_CF); //Only when not using CL? 19 } 20 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 21 if (maskcnt) FLAGW_OF(overflow); 22 break; 23 24 case 1: //ROR r/m16 25 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 26 numcnt = maskcnt; 27 if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap! 28 overflow = numcnt?0:FLAG_OF; 29 for (shift = 1; shift <= numcnt; shift++) { 30 FLAGW_CF(s); //Save LSB! 31 s = ((s >> 1)&0x7FFFU) | (FLAG_CF << 15); 32 overflow = ((s >> 15) ^ ((s >> 14) & 1)); //Only when not using CL? 33 } 34 if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources? 35 if (maskcnt) FLAGW_OF(overflow); 36 break; 37 38 case 2: //RCL r/m16 39 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 40 numcnt = maskcnt; 41 if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap! 42 overflow = numcnt?0:FLAG_OF; 43 for (shift = 1; shift <= numcnt; shift++) { 44 tempCF = FLAG_CF; 45 FLAGW_CF(s>>15); //Save MSB! 46 s = (s << 1)|tempCF; //Shift and set CF! 47 overflow = (((s >> 15) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL? 48 } 49 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 50 if (maskcnt) FLAGW_OF(overflow); 51 break; 52 53 case 3: //RCR r/m16 54 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 55 numcnt = maskcnt; 56 if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap! 57 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 58 for (shift = 1; shift <= numcnt; shift++) { 59 overflow = ((s >> 15)^FLAG_CF); 60 tempCF = FLAG_CF;
…Show last 78 lines
61 FLAGW_CF(s); //Save LSB! 62 s = ((s >> 1)&0x7FFFU) | (tempCF << 15); 63 } 64 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 65 if (maskcnt) FLAGW_OF(overflow); 66 break; 67 68 case 4: case 6: //SHL r/m16 69 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 70 numcnt = maskcnt; 71 //FLAGW_AF(0); 72 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 73 for (shift = 1; shift <= numcnt; shift++) { 74 FLAGW_CF(s>>15); 75 //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry? 76 s = (s << 1) & 0xFFFFU; 77 overflow = (FLAG_CF^(s>>15)); 78 } 79 if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources? 80 if (maskcnt) flag_szp16((uint16_t)(s&0xFFFFU)); 81 if (maskcnt) FLAGW_OF(overflow); 82 if (maskcnt) FLAGW_AF(1); 83 break; 84 85 case 5: //SHR r/m16 86 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 87 numcnt = maskcnt; 88 //FLAGW_AF(0); 89 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 90 for (shift = 1; shift <= numcnt; shift++) { 91 overflow = (s>>15); 92 FLAGW_CF(s); 93 //backup = s; //Save backup! 94 s = s >> 1; 95 //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry? 96 } 97 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 98 if (maskcnt) flag_szp16((uint16_t)(s & 0xFFFFU)); 99 if (maskcnt) FLAGW_OF(overflow); 100 if (maskcnt) FLAGW_AF(1); 101 break; 102 103 case 7: //SAR r/m16 104 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 105 numcnt = maskcnt; 106 msb = s & 0x8000U; 107 //FLAGW_AF(0); 108 for (shift = 1; shift <= numcnt; shift++) { 109 FLAGW_CF(s); 110 //backup = s; //Save backup! 111 s = (s >> 1) | msb; 112 //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry? 113 } 114 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 115 if (maskcnt) FLAGW_AF(0); 116 byte tempSF; 117 tempSF = FLAG_SF; //Save the SF! 118 /*flag_szp8((uint8_t)(s & 0xFF));*/ 119 //http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#SAR says only C and O flags! 120 if (!maskcnt) //Nothing done? 121 { 122 FLAGW_SF(tempSF); //We don't update when nothing's done! 123 } 124 else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts! 125 { 126 flag_szp16(s); //Affect sign as well! 127 FLAGW_OF(0); //Cleared! 128 } 129 else if (numcnt) //Anything shifted at all? 130 { 131 flag_szp16(s); //Affect sign as well! 132 FLAGW_OF(0); //Cleared with count as well? 133 } 134 break; 135 } 136 op_grp2_cycles(numcnt, varshift); 137 return (s & 0xFFFFU); 138}
32-bit GRP2:
1uint_32 op_grp2_32(byte cnt, byte varshift) { 2 //word d, 3 INLINEREGISTER uint_64 s, shift, tempCF, msb; 4 INLINEREGISTER byte numcnt,maskcnt,overflow; 5 //word backup; 6 //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count 7 numcnt = maskcnt = cnt; //Save count! 8 s = oper1d; 9 switch (thereg) { 10 case 0: //ROL r/m32 11 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 12 numcnt = maskcnt; 13 if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap! 14 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 15 for (shift = 1; shift <= numcnt; shift++) { 16 FLAGW_CF(s>>31); //Save MSB! 17 s = (s << 1)|FLAG_CF; 18 overflow = (((s >> 31) & 1)^FLAG_CF); 19 } 20 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 21 if (maskcnt) FLAGW_OF(overflow); //Overflow? 22 break; 23 24 case 1: //ROR r/m32 25 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 26 numcnt = maskcnt; 27 if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap! 28 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 29 for (shift = 1; shift <= numcnt; shift++) { 30 FLAGW_CF(s); //Save LSB! 31 s = ((s >> 1)&0x7FFFFFFFU) | (FLAG_CF << 31); 32 overflow = ((s >> 31) ^ ((s >> 30) & 1)); 33 } 34 if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources? 35 if (maskcnt) FLAGW_OF(overflow); //Overflow? 36 break; 37 38 case 2: //RCL r/m32 39 if (EMULATED_CPU >= CPU_80386) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 40 numcnt = maskcnt; 41 //if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 42 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 43 for (shift = 1; shift <= numcnt; shift++) { 44 tempCF = FLAG_CF; 45 FLAGW_CF(s>>31); //Save MSB! 46 s = (s << 1)|tempCF; //Shift and set CF! 47 overflow = (((s >> 31) & 1)^FLAG_CF); //OF=MSB^CF 48 } 49 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 50 if (maskcnt) FLAGW_OF(overflow); //Overflow? 51 break; 52 53 case 3: //RCR r/m32 54 if (EMULATED_CPU >= CPU_80386) maskcnt %= 33; //Clear the upper 3 bits to become a NEC V20/V30+! 55 numcnt = maskcnt; 56 //if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 57 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 58 for (shift = 1; shift <= numcnt; shift++) { 59 overflow = (((s >> 31)&1)^FLAG_CF); 60 tempCF = FLAG_CF;
…Show last 78 lines
61 FLAGW_CF(s); //Save LSB! 62 s = ((s >> 1)&0x7FFFFFFFU) | (tempCF << 31); 63 } 64 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 65 if (maskcnt) FLAGW_OF(overflow); //Overflow? 66 break; 67 68 case 4: case 6: //SHL r/m32 69 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 70 numcnt = maskcnt; 71 //FLAGW_AF(0); 72 overflow = numcnt?0:FLAG_OF; 73 for (shift = 1; shift <= numcnt; shift++) { 74 FLAGW_CF(s>>31); 75 //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry? 76 s = (s << 1) & 0xFFFFFFFFU; 77 overflow = (FLAG_CF^(s>>31)); 78 } 79 if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources? 80 if (maskcnt) FLAGW_OF(overflow); 81 if (maskcnt) FLAGW_AF(1); 82 if (maskcnt) flag_szp32((uint32_t)(s&0xFFFFFFFFU)); 83 break; 84 85 case 5: //SHR r/m32 86 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 87 numcnt = maskcnt; 88 //FLAGW_AF(0); 89 overflow = numcnt?0:FLAG_OF; 90 for (shift = 1; shift <= numcnt; shift++) { 91 overflow = (s>>31); 92 FLAGW_CF(s); 93 //backup = s; //Save backup! 94 s = s >> 1; 95 //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry? 96 } 97 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 98 if (maskcnt) FLAGW_OF(overflow); 99 if (maskcnt) FLAGW_AF(1); 100 if (maskcnt) flag_szp32((uint32_t)(s & 0xFFFFFFFFU)); 101 break; 102 103 case 7: //SAR r/m32 104 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 105 numcnt = maskcnt; 106 msb = s & 0x80000000U; 107 //FLAGW_AF(0); 108 for (shift = 1; shift <= numcnt; shift++) { 109 FLAGW_CF(s); 110 //backup = s; //Save backup! 111 s = (s >> 1) | msb; 112 //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry? 113 } 114 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 115 if (maskcnt) FLAGW_AF(0); 116 byte tempSF; 117 tempSF = FLAG_SF; //Save the SF! 118 /*flag_szp8((uint8_t)(s & 0xFF));*/ 119 //http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#SAR says only C and O flags! 120 if (!maskcnt) //Nothing done? 121 { 122 FLAGW_SF(tempSF); //We don't update when nothing's done! 123 } 124 else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts! 125 { 126 flag_szp32((uint32_t)s); //Affect sign as well! 127 FLAGW_OF(0); //Cleared! 128 } 129 else if (numcnt) //Anything shifted at all? 130 { 131 flag_szp32((uint32_t)s); //Affect sign as well! 132 FLAGW_OF(0); //Cleared with count as well? 133 } 134 break; 135 } 136 op_grp2_cycles32(numcnt, varshift); 137 return (s & 0xFFFFFFFFU); 138}
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:
1mov al,0x40 2shl al, 0x10
will still perform the shift, AL will be zero, and OF will be set.
Carry is set as expected, too, so:
1mov al,1 2shl 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.
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
1byte op_grp2_8(byte cnt, byte varshift) { 2 //word d, 3 INLINEREGISTER word s, shift, tempCF, msb; 4 INLINEREGISTER byte numcnt, maskcnt, overflow; 5 //word backup; 6 //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count 7 numcnt = maskcnt = cnt; //Save count! 8 s = oper1b; 9 switch (thereg) { 10 case 0: //ROL r/m8 11 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 12 numcnt = maskcnt; 13 if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap! 14 overflow = numcnt?0:FLAG_OF; 15 for (shift = 1; shift <= numcnt; shift++) { 16 FLAGW_CF(s>>7); //Save MSB! 17 s = (s << 1)|FLAG_CF; 18 overflow = (((s >> 7) & 1)^FLAG_CF); //Only when not using CL? 19 } 20 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 21 if (maskcnt) FLAGW_OF(overflow); 22 break; 23 24 case 1: //ROR r/m8 25 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 26 numcnt = maskcnt; 27 if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap! 28 overflow = numcnt?0:FLAG_OF; 29 for (shift = 1; shift <= numcnt; shift++) { 30 FLAGW_CF(s); //Save LSB! 31 s = ((s >> 1)&0x7FU) | (FLAG_CF << 7); 32 overflow = ((s >> 7) ^ ((s >> 6) & 1)); //Only when not using CL? 33 } 34 if (maskcnt && (numcnt==0)) FLAGW_CF(s>>7); //Always sets CF, according to various sources? 35 if (maskcnt) FLAGW_OF(overflow); 36 break; 37 38 case 2: //RCL r/m8 39 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 40 numcnt = maskcnt; 41 if ((EMULATED_CPU>=CPU_80386) && (maskcnt>9)) numcnt %= 9; //Operand size wrap! 42 overflow = numcnt?0:FLAG_OF; 43 for (shift = 1; shift <= numcnt; shift++) { 44 tempCF = FLAG_CF; 45 FLAGW_CF(s>>7); //Save MSB! 46 s = (s << 1)|tempCF; //Shift and set CF! 47 overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL? 48 } 49 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 50 if (maskcnt) FLAGW_OF(overflow); 51 break; 52 53 case 3: //RCR r/m8 54 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 55 numcnt = maskcnt; 56 if ((EMULATED_CPU>=CPU_80386) && (maskcnt>9)) numcnt %= 9; //Operand size wrap! 57 overflow = numcnt?0:FLAG_OF; 58 for (shift = 1; shift <= numcnt; shift++) { 59 overflow = (((s >> 7)&1)^FLAG_CF); 60 tempCF = FLAG_CF;
…Show last 91 lines
61 FLAGW_CF(s); //Save LSB! 62 s = ((s >> 1)&0x7FU) | (tempCF << 7); 63 } 64 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 65 if (maskcnt) FLAGW_OF(overflow); 66 break; 67 68 case 4: case 6: //SHL r/m8 69 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 70 numcnt = maskcnt; 71 if ((EMULATED_CPU>=CPU_80386)) 72 { 73 if (((maskcnt&0x18)==maskcnt) && maskcnt) //8/16/24 shifts? 74 { 75 numcnt = maskcnt = 8; //Brhave like a 8 bit shift! 76 } 77 else numcnt &= 7; //Limit count! 78 } 79 //FLAGW_AF(0); 80 overflow = numcnt?0:FLAG_OF; 81 for (shift = 1; shift <= numcnt; shift++) { 82 FLAGW_CF(s>>7); 83 //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry? 84 s = (s << 1) & 0xFFU; 85 overflow = (FLAG_CF^(s>>7)); 86 } 87 skipshift: 88 if (maskcnt) flag_szp8((uint8_t)(s&0xFFU)); 89 if (maskcnt) FLAGW_OF(overflow); 90 if (maskcnt) FLAGW_AF(1); 91 break; 92 93 case 5: //SHR r/m8 94 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 95 numcnt = maskcnt; 96 //FLAGW_AF(0); 97 overflow = numcnt?0:FLAG_OF; 98 if (maskcnt && ((maskcnt&7)==0)) 99 { 100 //Adjusted according to IBMulator! 101 FLAGW_CF(s>>7); //Always sets CF, according to various sources? 102 } 103 for (shift = 1; shift <= numcnt; shift++) { 104 overflow = (s>>7); 105 if (numcnt&7) FLAGW_CF(s); 106 //backup = s; //Save backup! 107 s = s >> 1; 108 //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry? 109 } 110 if (maskcnt) flag_szp8((uint8_t)(s & 0xFFU)); 111 if (maskcnt) FLAGW_OF(overflow); 112 if (maskcnt) FLAGW_AF(1); 113 break; 114 115 case 7: //SAR r/m8 116 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 117 numcnt = maskcnt; 118 //if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Limit count! Not to be limited! 119 msb = s & 0x80U; 120 //FLAGW_AF(0); 121 for (shift = 1; shift <= numcnt; shift++) { 122 FLAGW_CF(s); 123 //backup = s; //Save backup! 124 s = (s >> 1) | msb; 125 //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry? 126 } 127 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 128 if (maskcnt) FLAGW_AF(1); 129 byte tempSF; 130 tempSF = FLAG_SF; //Save the SF! 131 /*flag_szp8((uint8_t)(s & 0xFF));*/ 132 //http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#SAR says only C and O flags! 133 if (!maskcnt) //Nothing done? 134 { 135 FLAGW_SF(tempSF); //We don't update when nothing's done! 136 } 137 else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts! 138 { 139 flag_szp8((uint8_t)s); //Affect sign as well! 140 FLAGW_OF(0); //Cleared! 141 } 142 else if (numcnt) //Anything shifted at all? 143 { 144 flag_szp8((uint8_t)s); //Affect sign as well! 145 FLAGW_OF(0); //Cleared with count as well? 146 } 147 break; 148 } 149 op_grp2_cycles(numcnt, varshift); 150 return (s & 0xFFU); 151}
16-bit:
1word op_grp2_16(byte cnt, byte varshift) { 2 //word d, 3 INLINEREGISTER uint_32 s, shift, tempCF, msb; 4 INLINEREGISTER byte numcnt, maskcnt, overflow; 5 //word backup; 6 //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count 7 numcnt = maskcnt = cnt; //Save count! 8 s = oper1; 9 switch (thereg) { 10 case 0: //ROL r/m16 11 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 12 numcnt = maskcnt; 13 if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap! 14 overflow = numcnt?0:FLAG_OF; 15 for (shift = 1; shift <= numcnt; shift++) { 16 FLAGW_CF(s>>15); //Save MSB! 17 s = (s << 1)|FLAG_CF; 18 overflow = (((s >> 15) & 1)^FLAG_CF); //Only when not using CL? 19 } 20 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 21 if (maskcnt) FLAGW_OF(overflow); 22 break; 23 24 case 1: //ROR r/m16 25 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 26 numcnt = maskcnt; 27 if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap! 28 overflow = numcnt?0:FLAG_OF; 29 for (shift = 1; shift <= numcnt; shift++) { 30 FLAGW_CF(s); //Save LSB! 31 s = ((s >> 1)&0x7FFFU) | (FLAG_CF << 15); 32 overflow = ((s >> 15) ^ ((s >> 14) & 1)); //Only when not using CL? 33 } 34 if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources? 35 if (maskcnt) FLAGW_OF(overflow); 36 break; 37 38 case 2: //RCL r/m16 39 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 40 numcnt = maskcnt; 41 if ((EMULATED_CPU>=CPU_80386) && (maskcnt>17)) numcnt %= 17; //Operand size wrap! 42 overflow = numcnt?0:FLAG_OF; 43 for (shift = 1; shift <= numcnt; shift++) { 44 tempCF = FLAG_CF; 45 FLAGW_CF(s>>15); //Save MSB! 46 s = (s << 1)|tempCF; //Shift and set CF! 47 overflow = (((s >> 15) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL? 48 } 49 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 50 if (maskcnt) FLAGW_OF(overflow); 51 break; 52 53 case 3: //RCR r/m16 54 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 55 numcnt = maskcnt; 56 if ((EMULATED_CPU>=CPU_80386) && (maskcnt>17)) numcnt %= 17; //Operand size wrap! 57 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 58 for (shift = 1; shift <= numcnt; shift++) { 59 overflow = ((s >> 15)^FLAG_CF); 60 tempCF = FLAG_CF;
…Show last 78 lines
61 FLAGW_CF(s); //Save LSB! 62 s = ((s >> 1)&0x7FFFU) | (tempCF << 15); 63 } 64 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 65 if (maskcnt) FLAGW_OF(overflow); 66 break; 67 68 case 4: case 6: //SHL r/m16 69 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 70 numcnt = maskcnt; 71 //FLAGW_AF(0); 72 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 73 for (shift = 1; shift <= numcnt; shift++) { 74 FLAGW_CF(s>>15); 75 //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry? 76 s = (s << 1) & 0xFFFFU; 77 overflow = (FLAG_CF^(s>>15)); 78 } 79 if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources? 80 if (maskcnt) flag_szp16((uint16_t)(s&0xFFFFU)); 81 if (maskcnt) FLAGW_OF(overflow); 82 if (maskcnt) FLAGW_AF(1); 83 break; 84 85 case 5: //SHR r/m16 86 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 87 numcnt = maskcnt; 88 //FLAGW_AF(0); 89 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 90 for (shift = 1; shift <= numcnt; shift++) { 91 overflow = (s>>15); 92 FLAGW_CF(s); 93 //backup = s; //Save backup! 94 s = s >> 1; 95 //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry? 96 } 97 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 98 if (maskcnt) flag_szp16((uint16_t)(s & 0xFFFFU)); 99 if (maskcnt) FLAGW_OF(overflow); 100 if (maskcnt) FLAGW_AF(1); 101 break; 102 103 case 7: //SAR r/m16 104 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 105 numcnt = maskcnt; 106 msb = s & 0x8000U; 107 //FLAGW_AF(0); 108 for (shift = 1; shift <= numcnt; shift++) { 109 FLAGW_CF(s); 110 //backup = s; //Save backup! 111 s = (s >> 1) | msb; 112 //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry? 113 } 114 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 115 if (maskcnt) FLAGW_AF(1); 116 byte tempSF; 117 tempSF = FLAG_SF; //Save the SF! 118 /*flag_szp8((uint8_t)(s & 0xFF));*/ 119 //http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#SAR says only C and O flags! 120 if (!maskcnt) //Nothing done? 121 { 122 FLAGW_SF(tempSF); //We don't update when nothing's done! 123 } 124 else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts! 125 { 126 flag_szp16(s); //Affect sign as well! 127 FLAGW_OF(0); //Cleared! 128 } 129 else if (numcnt) //Anything shifted at all? 130 { 131 flag_szp16(s); //Affect sign as well! 132 FLAGW_OF(0); //Cleared with count as well? 133 } 134 break; 135 } 136 op_grp2_cycles(numcnt, varshift); 137 return (s & 0xFFFFU); 138}
32-bit:
1uint_32 op_grp2_32(byte cnt, byte varshift) { 2 //word d, 3 INLINEREGISTER uint_64 s, shift, tempCF, msb; 4 INLINEREGISTER byte numcnt,maskcnt,overflow; 5 //word backup; 6 //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count 7 numcnt = maskcnt = cnt; //Save count! 8 s = oper1d; 9 switch (thereg) { 10 case 0: //ROL r/m32 11 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 12 numcnt = maskcnt; 13 if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap! 14 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 15 for (shift = 1; shift <= numcnt; shift++) { 16 FLAGW_CF(s>>31); //Save MSB! 17 s = (s << 1)|FLAG_CF; 18 overflow = (((s >> 31) & 1)^FLAG_CF); 19 } 20 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 21 if (maskcnt) FLAGW_OF(overflow); //Overflow? 22 break; 23 24 case 1: //ROR r/m32 25 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 26 numcnt = maskcnt; 27 if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap! 28 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 29 for (shift = 1; shift <= numcnt; shift++) { 30 FLAGW_CF(s); //Save LSB! 31 s = ((s >> 1)&0x7FFFFFFFU) | (FLAG_CF << 31); 32 overflow = ((s >> 31) ^ ((s >> 30) & 1)); 33 } 34 if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources? 35 if (maskcnt) FLAGW_OF(overflow); //Overflow? 36 break; 37 38 case 2: //RCL r/m32 39 if (EMULATED_CPU >= CPU_80386) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 40 numcnt = maskcnt; 41 //if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 42 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 43 for (shift = 1; shift <= numcnt; shift++) { 44 tempCF = FLAG_CF; 45 FLAGW_CF(s>>31); //Save MSB! 46 s = (s << 1)|tempCF; //Shift and set CF! 47 overflow = (((s >> 31) & 1)^FLAG_CF); //OF=MSB^CF 48 } 49 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 50 if (maskcnt) FLAGW_OF(overflow); //Overflow? 51 break; 52 53 case 3: //RCR r/m32 54 if (EMULATED_CPU >= CPU_80386) maskcnt %= 33; //Clear the upper 3 bits to become a NEC V20/V30+! 55 numcnt = maskcnt; 56 //if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 57 overflow = numcnt?0:FLAG_OF; //Default: no overflow! 58 for (shift = 1; shift <= numcnt; shift++) { 59 overflow = (((s >> 31)&1)^FLAG_CF); 60 tempCF = FLAG_CF;
…Show last 78 lines
61 FLAGW_CF(s); //Save LSB! 62 s = ((s >> 1)&0x7FFFFFFFU) | (tempCF << 31); 63 } 64 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 65 if (maskcnt) FLAGW_OF(overflow); //Overflow? 66 break; 67 68 case 4: case 6: //SHL r/m32 69 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 70 numcnt = maskcnt; 71 //FLAGW_AF(0); 72 overflow = numcnt?0:FLAG_OF; 73 for (shift = 1; shift <= numcnt; shift++) { 74 FLAGW_CF(s>>31); 75 //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry? 76 s = (s << 1) & 0xFFFFFFFFU; 77 overflow = (FLAG_CF^(s>>31)); 78 } 79 if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources? 80 if (maskcnt) FLAGW_OF(overflow); 81 if (maskcnt) FLAGW_AF(1); 82 if (maskcnt) flag_szp32((uint32_t)(s&0xFFFFFFFFU)); 83 break; 84 85 case 5: //SHR r/m32 86 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 87 numcnt = maskcnt; 88 //FLAGW_AF(0); 89 overflow = numcnt?0:FLAG_OF; 90 for (shift = 1; shift <= numcnt; shift++) { 91 overflow = (s>>31); 92 FLAGW_CF(s); 93 //backup = s; //Save backup! 94 s = s >> 1; 95 //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry? 96 } 97 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 98 if (maskcnt) FLAGW_OF(overflow); 99 if (maskcnt) FLAGW_AF(1); 100 if (maskcnt) flag_szp32((uint32_t)(s & 0xFFFFFFFFU)); 101 break; 102 103 case 7: //SAR r/m32 104 if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+! 105 numcnt = maskcnt; 106 msb = s & 0x80000000U; 107 //FLAGW_AF(0); 108 for (shift = 1; shift <= numcnt; shift++) { 109 FLAGW_CF(s); 110 //backup = s; //Save backup! 111 s = (s >> 1) | msb; 112 //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry? 113 } 114 if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources? 115 if (maskcnt) FLAGW_AF(1); 116 byte tempSF; 117 tempSF = FLAG_SF; //Save the SF! 118 /*flag_szp8((uint8_t)(s & 0xFF));*/ 119 //http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#SAR says only C and O flags! 120 if (!maskcnt) //Nothing done? 121 { 122 FLAGW_SF(tempSF); //We don't update when nothing's done! 123 } 124 else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts! 125 { 126 flag_szp32((uint32_t)s); //Affect sign as well! 127 FLAGW_OF(0); //Cleared! 128 } 129 else if (numcnt) //Anything shifted at all? 130 { 131 flag_szp32((uint32_t)s); //Affect sign as well! 132 FLAGW_OF(0); //Cleared with count as well? 133 } 134 break; 135 } 136 op_grp2_cycles32(numcnt, varshift); 137 return (s & 0xFFFFFFFFU); 138}
Is that behaviour for all those opcodes 100% correct, peterferrie?
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?