test386.asm CPU tester

Emulation of old PCs, PC hardware, or PC peripherals.

Re: test386.asm CPU tester

Postby superfury » 2017-11-16 @ 20:21

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)?

With modulo I mean the following parts of the manual:
http://x86.renejeschke.de/html/file_mod ... d_273.html

So with:
Code: Select all
switch(OperandSize) {
         case 8:
            TemporaryCount = (Count & 0x1F) % 9;
            break;
         case 16:
            TemporaryCount = (Count & 0x1F) % 17;
            break;
         case 32:
            TemporaryCount = Count & 0x1F;
         


The %9 and %17 isn't used in actual processors?

Also:
Code: Select all
switch(OperandSize) {
         case 8:
            TemporaryCount = Count % 8;
            break;
         case 16:
            TemporaryCount = Count % 16;
            break;
         case 32:
            TemporaryCount = Count % 32;
            break;
      }


%8, %16 and %32 isn't applied? Only %32 for all cases(except 32-bit RCR)?

The only exception to the %32/&0x1F rule is %33 with 32-bit RCR? All others ONLY use modulo 32(&0x1F, masking off the top 3 bits)?

Is that correct? (Although that would make many documentations on the 80386+ or 32-bit x86 CPUs invalid)

ROL AL,9 will become ROL AL,1 and ROL AL,8 will become ROL AL,8?
superfury
l33t
 
Posts: 2061
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: test386.asm CPU tester

Postby peterferrie » 2017-11-17 @ 23:14

superfury wrote: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

Code: Select all
mov eax,20
stc
rcl 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.

Code: Select all
mov al,20
stc
rcl 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.
peterferrie
Oldbie
 
Posts: 603
Joined: 2008-5-08 @ 21:54

Re: test386.asm CPU tester

Postby superfury » 2017-11-18 @ 10:49

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.
superfury
l33t
 
Posts: 2061
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: test386.asm CPU tester

Postby Harekiet » 2017-11-19 @ 08:42

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 :)
User avatar
Harekiet
DOSBox Author
 
Posts: 1048
Joined: 2002-7-01 @ 07:14
Location: Fryslan

Re: test386.asm CPU tester

Postby superfury » 2017-11-19 @ 10:41

Harekiet wrote: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?
superfury
l33t
 
Posts: 2061
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: test386.asm CPU tester

Postby hottobar » 2017-11-19 @ 17:59

Harekiet wrote: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.
User avatar
hottobar
Newbie
 
Posts: 44
Joined: 2014-4-21 @ 17:00

Re: test386.asm CPU tester

Postby hottobar » 2017-11-19 @ 18:05

superfury wrote:Does IBMulator's output match real hardware(which means incorrect manuals)?


Now it does :)
User avatar
hottobar
Newbie
 
Posts: 44
Joined: 2014-4-21 @ 17:00

Re: test386.asm CPU tester

Postby superfury » 2017-11-20 @ 11:15

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.
superfury
l33t
 
Posts: 2061
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: test386.asm CPU tester

Postby superfury » 2017-11-20 @ 14:51

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?

8086+ BCD:
Code: Select all
//BCD opcodes!
byte CPU8086_internal_DAA()
{
   word ALVAL, oldCF, oldAL;
   CPUPROT1
   oldAL = (word)REG_AL; //Save original!
   oldCF = FLAG_CF; //Save old Carry!
   ALVAL = (word)REG_AL;
   if (((ALVAL&0xF)>9) || FLAG_AF)
   {
      oper1 = ALVAL+6;
      ALVAL = (oper1&0xFF);
      FLAGW_AF(1);
   }
   else FLAGW_AF(0);
   if (((REG_AL)>0x99) || oldCF)
   {
      ALVAL += 0x60;
      FLAGW_CF(1);
   }
   else
   {
      FLAGW_CF(0);
   }
   REG_AL = (byte)(ALVAL&0xFF); //Write the value back to AL!
   flag_szp8(REG_AL);
   FLAGW_OF(((((oldAL&0x80)==0) && (REG_AL&0x80)))?1:0); //Overflow flag, according to IBMulator!
   //if (ALVAL&0xFF00) FLAGW_OF(1); else FLAGW_OF(0); //Undocumented: Overflow flag!
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 4; //Timings!
   }
   return 0;
}
byte CPU8086_internal_DAS()
{
   INLINEREGISTER byte old_CF, old_AL;
   INLINEREGISTER word carryAL;
   old_AL = (word)(REG_AL);
   old_CF = FLAG_CF; //Save old values!
   FLAGW_CF(0);
   CPUPROT1
   if (((old_AL&0xF)>9) || FLAG_AF)
   {
      carryAL = REG_AL-6;
      REG_AL = (carryAL&0xFF); //Store the result!
      FLAGW_CF(old_CF|((carryAL&0xFF00)>0)); //Old CF or borrow that occurs when substracting!
      FLAGW_AF(1);
   }
   else FLAGW_AF(0);

   if ((old_AL>0x99) || old_CF)
   {
      REG_AL -= 0x60;
      FLAGW_CF(1);
   }
   flag_szp8(REG_AL);
   FLAGW_OF(((old_AL&0x80)) && ((REG_AL&0x80)==0)); //According to IBMulator!
   //if (bigAL&0xFF00) FLAGW_OF(1); else FLAGW_OF(0); //Undocumented: Overflow flag!
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 4; //Timings!
   }
   return 0;
}
byte CPU8086_internal_AAA()
{
   CPUPROT1
   if (((REG_AL&0xF)>9))
   {
      if ((REG_AL&0xF)>9)
      {
         FLAGW_OF(((REG_AL&0xF0)==0x70)?1:0); //According to IBMulator
      }
      REG_AL += 6;
      REG_AL &= 0xF;
      ++REG_AH;
      FLAGW_AF(1);
      FLAGW_CF(1);
      FLAGW_ZF((REG_AL==0)?1:0);
   }
   else if (FLAG_AF)
   {
      REG_AL += 6;
      REG_AL &= 0xF;
      ++REG_AH;
      FLAGW_AF(1);
      FLAGW_CF(1);
      FLAGW_ZF(0); //According to IBMulator!
      FLAGW_OF(0); //According to IBMulator!
   }
   else
   {
      FLAGW_AF(0);
      FLAGW_CF(0);
      FLAGW_OF(0); //According to IBMulator!
      FLAGW_ZF(0); //According to IBMulator!
   }
   //flag_szp8(REG_AL); //Basic flags!
   flag_p8(REG_AL); //Parity is affected!
   FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
   //z=s=p=o=?
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 4; //Timings!
   }
   return 0;
}
byte CPU8086_internal_AAS()
{
   CPUPROT1
   if (((REG_AL&0xF)>9) || FLAG_AF)
   {
      FLAGW_SF((REG_AL>0x85)?1:0); //According to IBMulator!
      REG_AL -= 6;
      REG_AL &= 0xF;
      --REG_AH;
      FLAGW_AF(1);
      FLAGW_CF(1);
      FLAGW_OF(0); //According to IBMulator!
   }
   else if (FLAG_AF)
   {
      FLAGW_OF(((REG_AL>=0x80) && (REG_AL<=0x85))?1:0); //According to IBMulator!
      FLAGW_SF(((REG_AL < 0x06) || (REG_AL > 0x85))?1:0); //According to IBMulator!
      REG_AL -= 6;
      REG_AL &= 0xF;
      --REG_AH;
      FLAGW_AF(1);
      FLAGW_CF(1);
   }
   else
   {
      FLAGW_SF((REG_AL>=0x80)?1:0); //According to IBMulator!
      FLAGW_AF(0);
      FLAGW_CF(0);
      FLAGW_OF(0); //According to IBMulator!
   }
   //flag_szp8(REG_AL); //Basic flags!
   flag_p8(REG_AL); //Parity is affected!
   FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
   //z=s=o=p=?
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 4; //Timings!
   }
   return 0;
}

OPTINLINE byte CPU8086_internal_AAM(byte data)
{
   CPUPROT1
   if ((!data) && (CPU[activeCPU].instructionstep==0)) //First step?
   {
      CPU[activeCPU].cycles_OP += 1; //Timings always!
      ++CPU[activeCPU].instructionstep; //Next step after we're done!
      CPU[activeCPU].executed = 0; //Not executed yet!
      return 1;
   }
   word quotient, remainder;
   byte error, applycycles;
   CPU8086_internal_DIV(REG_AL,data,&quotient,&remainder,&error,8,2,6,&applycycles,0,0,0);
   if (error) //Error occurred?
   {
      CPU_exDIV0(); //Raise error that's requested!
      return 1;
   }
   else //Valid result?
   {
      REG_AH = (byte)(quotient&0xFF);
      REG_AL = (byte)(remainder&0xFF);
      //Flags are set on newer CPUs according to the MOD operation: Sign, Zero and Parity are set according to the mod operation(AL) and Overflow, Carry and Auxiliary carry are cleared.
      flag_szp8(REG_AL); //Result of MOD instead!
      FLAGW_OF(0); FLAGW_CF(0); FLAGW_AF(0); //Clear these!
      //C=O=A=?
   }
   CPUPROT2
   return 0;
}
OPTINLINE byte CPU8086_internal_AAD(byte data)
{
   CPUPROT1
   oper2b = (word)REG_AL; //What to add!
   oper1b = ((word)REG_AH*(word)data); //AAD base to work on, we're adding to this!
   op_add8(); //Add, 8-bit, including flags!
   REG_AX = (res8&0xFF); //The result to load!
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 60; //Timings!
   }
   return 0;
}


80186+ adjustments for newer CPUs:
Code: Select all
//BCD opcodes!
OPTINLINE void CPU186_internal_AAA()
{
   CPUPROT1
   FLAGW_SF((REG_AL>=0x7A)&&(REG_AL<=0xF9)); //According to IBMulator
   if ((REG_AL&0xF)>9)
   {
      FLAGW_OF(((REG_AL&0xF0)==0x70)?1:0); //According to IBMulator
      REG_AX += 0x0106;
      FLAGW_AF(1);
      FLAGW_CF(1);
      FLAGW_ZF((REG_AL==0)?1:0);
   }
   else if (FLAG_AF) //Special case according to IBMulator?
   {
      REG_AX += 0x0106;
      FLAGW_AF(1);
      FLAGW_CF(1);
      FLAGW_ZF(0); //According to IBMulator!
      FLAGW_OF(0); //According to IBMulator!
   }
   else
   {
      FLAGW_AF(0);
      FLAGW_CF(0);
      FLAGW_OF(0); //According to IBMulator!
      FLAGW_ZF((REG_AL==0)?1:0); //According to IBMulator!
   }
   flag_p8(REG_AL); //Parity is affected!
   REG_AL &= 0xF;
   //flag_szp8(REG_AL); //Basic flags!
   FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
   FLAGW_SF(0); //Clear Sign!
   //z=s=p=o=?
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 4; //Timings!
   }
}
OPTINLINE void CPU186_internal_AAS()
{
   CPUPROT1
   if (((REG_AL&0xF)>9))
   {
      FLAGW_SF((REG_AL>0x85)?1:0); //According to IBMulator!
      REG_AX -= 0x0106;
      FLAGW_AF(1);
      FLAGW_CF(1);
      FLAGW_OF(0); //According to IBMulator!
   }
   else if (FLAG_AF)
   {
      FLAGW_OF(((REG_AL>=0x80) && (REG_AL<=0x85))?1:0); //According to IBMulator!
      FLAGW_SF(((REG_AL < 0x06) || (REG_AL > 0x85))?1:0); //According to IBMulator!
      REG_AX -= 0x0106;
      FLAGW_AF(1);
      FLAGW_CF(1);
   }
   else
   {
      FLAGW_SF((REG_AL>=0x80)?1:0); //According to IBMulator!
      FLAGW_AF(0);
      FLAGW_CF(0);
      FLAGW_OF(0); //According to IBMulator!
   }
   REG_AL &= 0xF;
   //flag_szp8(REG_AL); //Basic flags!
   flag_p8(REG_AL); //Parity is affected!
   FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
   //FLAGW_SF(0); //Sign is cleared!
   //z=s=o=p=?
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 4; //Timings!
   }
}


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?
superfury
l33t
 
Posts: 2061
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: test386.asm CPU tester

Postby hottobar » 2017-11-20 @ 18:00

superfury wrote:
Code: Select all
//According to IBMulator



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?
Code: Select all
FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
FLAGW_SF(0); //Clear Sign!
User avatar
hottobar
Newbie
 
Posts: 44
Joined: 2014-4-21 @ 17:00

Re: test386.asm CPU tester

Postby superfury » 2017-11-20 @ 19:29

You're right. This is my new code(after some more fixes, now it gets to DAS it seems, before crashing(also some shr before the HLT)):

8086+:
Code: Select all
//BCD opcodes!
byte CPU8086_internal_DAA()
{
   word ALVAL, oldCF, oldAL;
   CPUPROT1
   oldAL = (word)REG_AL; //Save original!
   oldCF = FLAG_CF; //Save old Carry!
   ALVAL = (word)REG_AL;
   if (((ALVAL&0xF)>9) || FLAG_AF)
   {
      oper1 = ALVAL+6;
      ALVAL = (oper1&0xFF);
      FLAGW_AF(1);
   }
   else FLAGW_AF(0);
   if (((REG_AL)>0x99) || oldCF)
   {
      ALVAL += 0x60;
      FLAGW_CF(1);
   }
   else
   {
      FLAGW_CF(0);
   }
   REG_AL = (byte)(ALVAL&0xFF); //Write the value back to AL!
   flag_szp8(REG_AL);
   FLAGW_OF(((((oldAL&0x80)==0) && (REG_AL&0x80)))?1:0); //Overflow flag, according to IBMulator!
   //if (ALVAL&0xFF00) FLAGW_OF(1); else FLAGW_OF(0); //Undocumented: Overflow flag!
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 4; //Timings!
   }
   return 0;
}
byte CPU8086_internal_DAS()
{
   INLINEREGISTER byte old_CF, old_AL;
   INLINEREGISTER word carryAL;
   old_AL = (word)(REG_AL);
   old_CF = FLAG_CF; //Save old values!
   FLAGW_CF(0);
   CPUPROT1
   if (((old_AL&0xF)>9) || FLAG_AF)
   {
      carryAL = REG_AL-6;
      REG_AL = (carryAL&0xFF); //Store the result!
      FLAGW_CF(old_CF|((carryAL&0xFF00)>0)); //Old CF or borrow that occurs when substracting!
      FLAGW_AF(1);
   }
   else FLAGW_AF(0);

   if ((old_AL>0x99) || old_CF)
   {
      REG_AL -= 0x60;
      FLAGW_CF(1);
   }
   flag_szp8(REG_AL);
   FLAGW_OF(((old_AL&0x80)) && ((REG_AL&0x80)==0)); //According to IBMulator!
   //if (bigAL&0xFF00) FLAGW_OF(1); else FLAGW_OF(0); //Undocumented: Overflow flag!
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 4; //Timings!
   }
   return 0;
}
byte CPU8086_internal_AAA()
{
   CPUPROT1
   if (((REG_AL&0xF)>9))
   {
      FLAGW_OF(((REG_AL&0xF0)==0x70)?1:0); //According to IBMulator
      REG_AL += 6;
      REG_AL &= 0xF;
      ++REG_AH;
      FLAGW_AF(1);
      FLAGW_CF(1);
      FLAGW_ZF((REG_AL==0)?1:0);
   }
   else if (FLAG_AF)
   {
      REG_AL += 6;
      REG_AL &= 0xF;
      ++REG_AH;
      FLAGW_AF(1);
      FLAGW_CF(1);
      FLAGW_ZF(0); //According to IBMulator!
      FLAGW_OF(0); //According to IBMulator!
   }
   else
   {
      FLAGW_AF(0);
      FLAGW_CF(0);
      FLAGW_OF(0); //According to IBMulator!
      FLAGW_ZF((REG_AL==0)?1:0); //According to IBMulator!
   }
   //flag_szp8(REG_AL); //Basic flags!
   flag_p8(REG_AL); //Parity is affected!
   //FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
   //z=s=p=o=?
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 4; //Timings!
   }
   return 0;
}
byte CPU8086_internal_AAS()
{
   CPUPROT1
   if (((REG_AL&0xF)>9) || FLAG_AF)
   {
      FLAGW_SF((REG_AL>0x85)?1:0); //According to IBMulator!
      REG_AL -= 6;
      --REG_AH;
      FLAGW_AF(1);
      FLAGW_CF(1);
      FLAGW_OF(0); //According to IBMulator!
   }
   else if (FLAG_AF)
   {
      FLAGW_OF(((REG_AL>=0x80) && (REG_AL<=0x85))?1:0); //According to IBMulator!
      FLAGW_SF(((REG_AL < 0x06) || (REG_AL > 0x85))?1:0); //According to IBMulator!
      REG_AL -= 6;
      --REG_AH;
      FLAGW_AF(1);
      FLAGW_CF(1);
   }
   else
   {
      FLAGW_SF((REG_AL>=0x80)?1:0); //According to IBMulator!
      FLAGW_AF(0);
      FLAGW_CF(0);
      FLAGW_OF(0); //According to IBMulator!
   }
   //flag_szp8(REG_AL); //Basic flags!
   flag_p8(REG_AL); //Parity is affected!
   FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
   REG_AL &= 0xF;
   //z=s=o=p=?
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 4; //Timings!
   }
   return 0;
}

OPTINLINE byte CPU8086_internal_AAM(byte data)
{
   CPUPROT1
   if ((!data) && (CPU[activeCPU].instructionstep==0)) //First step?
   {
      CPU[activeCPU].cycles_OP += 1; //Timings always!
      ++CPU[activeCPU].instructionstep; //Next step after we're done!
      CPU[activeCPU].executed = 0; //Not executed yet!
      return 1;
   }
   word quotient, remainder;
   byte error, applycycles;
   CPU8086_internal_DIV(REG_AL,data,&quotient,&remainder,&error,8,2,6,&applycycles,0,0,0);
   if (error) //Error occurred?
   {
      CPU_exDIV0(); //Raise error that's requested!
      return 1;
   }
   else //Valid result?
   {
      REG_AH = (byte)(quotient&0xFF);
      REG_AL = (byte)(remainder&0xFF);
      //Flags are set on newer CPUs according to the MOD operation: Sign, Zero and Parity are set according to the mod operation(AL) and Overflow, Carry and Auxiliary carry are cleared.
      flag_szp8(REG_AL); //Result of MOD instead!
      FLAGW_OF(0); FLAGW_CF(0); FLAGW_AF(0); //Clear these!
      //C=O=A=?
   }
   CPUPROT2
   return 0;
}
OPTINLINE byte CPU8086_internal_AAD(byte data)
{
   CPUPROT1
   oper2b = (word)REG_AL; //What to add!
   oper1b = ((word)REG_AH*(word)data); //AAD base to work on, we're adding to this!
   op_add8(); //Add, 8-bit, including flags!
   REG_AX = (res8&0xFF); //The result to load!
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 60; //Timings!
   }
   return 0;
}


80186+:
Code: Select all
//BCD opcodes!
OPTINLINE void CPU186_internal_AAA()
{
   CPUPROT1
   FLAGW_SF((REG_AL>=0x7A)&&(REG_AL<=0xF9)); //According to IBMulator
   if ((REG_AL&0xF)>9)
   {
      FLAGW_OF(((REG_AL&0xF0)==0x70)?1:0); //According to IBMulator
      REG_AX += 0x0106;
      FLAGW_AF(1);
      FLAGW_CF(1);
      FLAGW_ZF((REG_AL==0)?1:0);
   }
   else if (FLAG_AF) //Special case according to IBMulator?
   {
      REG_AX += 0x0106;
      FLAGW_AF(1);
      FLAGW_CF(1);
      FLAGW_ZF(0); //According to IBMulator!
      FLAGW_OF(0); //According to IBMulator!
   }
   else
   {
      FLAGW_AF(0);
      FLAGW_CF(0);
      FLAGW_OF(0); //According to IBMulator!
      FLAGW_ZF((REG_AL==0)?1:0); //According to IBMulator!
   }
   flag_p8(REG_AL); //Parity is affected!
   REG_AL &= 0xF;
   //flag_szp8(REG_AL); //Basic flags!
   //FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
   //FLAGW_SF(0); //Clear Sign!
   //z=s=p=o=?
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 4; //Timings!
   }
}
OPTINLINE void CPU186_internal_AAS()
{
   CPUPROT1
   if (((REG_AL&0xF)>9))
   {
      FLAGW_SF((REG_AL>0x85)?1:0); //According to IBMulator!
      REG_AX -= 0x0106;
      FLAGW_AF(1);
      FLAGW_CF(1);
      FLAGW_OF(0); //According to IBMulator!
   }
   else if (FLAG_AF)
   {
      FLAGW_OF(((REG_AL>=0x80) && (REG_AL<=0x85))?1:0); //According to IBMulator!
      FLAGW_SF(((REG_AL < 0x06) || (REG_AL > 0x85))?1:0); //According to IBMulator!
      REG_AX -= 0x0106;
      FLAGW_AF(1);
      FLAGW_CF(1);
   }
   else
   {
      FLAGW_SF((REG_AL>=0x80)?1:0); //According to IBMulator!
      FLAGW_AF(0);
      FLAGW_CF(0);
      FLAGW_OF(0); //According to IBMulator!
   }
   //flag_szp8(REG_AL); //Basic flags!
   flag_p8(REG_AL); //Parity is affected!
   FLAGW_ZF((REG_AL==0)?1:0); //Zero is affected!
   REG_AL &= 0xF;
   //FLAGW_SF(0); //Sign is cleared!
   //z=s=o=p=?
   CPUPROT2
   if (CPU_apply286cycles()==0) //No 80286+ cycles instead?
   {
      CPU[activeCPU].cycles_OP += 4; //Timings!
   }
}


debugger_UniPCemu_test386.asm_20171120_2030.zip
test386.asm executing POST E0.
(446.07 KiB) Downloaded 4 times
superfury
l33t
 
Posts: 2061
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: test386.asm CPU tester

Postby peterferrie » 2017-11-20 @ 23:44

That log shows SHR AL,CL failing because AF is not set.
AF is always set for SHR (and SHL) for CPUs prior to Pentium II.
peterferrie
Oldbie
 
Posts: 603
Joined: 2008-5-08 @ 21:54

Re: test386.asm CPU tester

Postby superfury » 2017-11-21 @ 06:15

Just fixed the auxiliary flag to set(shl/shr) or clear(sar) on maskcnt!=0. Now shr crashes because of an invalid carry flag?

16-bit:
Code: Select all
byte op_grp2_8(byte cnt, byte varshift) {
   //word d,
   INLINEREGISTER word s, shift, tempCF, msb;
   INLINEREGISTER byte numcnt, maskcnt, overflow;
   //word backup;
   //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
   numcnt = maskcnt = cnt; //Save count!
   s = oper1b;
   switch (thereg) {
   case 0: //ROL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>7); //Save MSB!
         s = (s << 1)|FLAG_CF;
         overflow = (((s >> 7) & 1)^FLAG_CF); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 1: //ROR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FU) | (FLAG_CF << 7);
         overflow = ((s >> 7) ^ ((s >> 6) & 1)); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>7); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 2: //RCL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>7); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 3: //RCR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (((s >> 7)&1)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FU) | (tempCF << 7);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 4: case 6: //SHL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>7);
         //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
         s = (s << 1) & 0xFFU;
         overflow = (FLAG_CF^(s>>7));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>7); //Always sets CF, according to various sources?
      if (numcnt) flag_szp8((uint8_t)(s&0xFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 5: //SHR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (s>>7);
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = s >> 1;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (numcnt) flag_szp8((uint8_t)(s & 0xFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 7: //SAR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      msb = s & 0x80U;
      //FLAGW_AF(0);
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = (s >> 1) | msb;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_AF(0);
      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 (!maskcnt) //Nothing done?
      {
         FLAGW_SF(tempSF); //We don't update when nothing's done!
      }
      else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
      {
         flag_szp8((uint8_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared!
      }
      else if (numcnt) //Anything shifted at all?
      {
         flag_szp8((uint8_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared with count as well?
      }
      break;
   }
   op_grp2_cycles(numcnt, varshift);
   return (s & 0xFFU);
}

word op_grp2_16(byte cnt, byte varshift) {
   //word d,
   INLINEREGISTER uint_32 s, shift, tempCF, msb;
   INLINEREGISTER byte numcnt, maskcnt, overflow;
   //word backup;
   //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
   numcnt = maskcnt = cnt; //Save count!
   s = oper1;
   switch (thereg) {
   case 0: //ROL r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>15); //Save MSB!
         s = (s << 1)|FLAG_CF;
         overflow = (((s >> 15) & 1)^FLAG_CF); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 1: //ROR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFU) | (FLAG_CF << 15);
         overflow = ((s >> 15) ^ ((s >> 14) & 1)); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 2: //RCL r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>15); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 15) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 3: //RCR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = ((s >> 15)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFU) | (tempCF << 15);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 4: case 6: //SHL r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>15);
         //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
         s = (s << 1) & 0xFFFFU;
         overflow = (FLAG_CF^(s>>15));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
      if (numcnt) flag_szp16((uint16_t)(s&0xFFFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 5: //SHR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (s>>15);
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = s >> 1;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (numcnt) flag_szp16((uint16_t)(s & 0xFFFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 7: //SAR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      msb = s & 0x8000U;
      //FLAGW_AF(0);
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = (s >> 1) | msb;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_AF(0);
      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 (!maskcnt) //Nothing done?
      {
         FLAGW_SF(tempSF); //We don't update when nothing's done!
      }
      else if (maskcnt==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!
         FLAGW_OF(0); //Cleared with count as well?
      }
      break;
   }
   op_grp2_cycles(numcnt, varshift);
   return (s & 0xFFFFU);
}


32-bit:
Code: Select all
uint_32 op_grp2_32(byte cnt, byte varshift) {
   //word d,
   INLINEREGISTER uint_64 s, shift, tempCF, msb;
   INLINEREGISTER byte numcnt,maskcnt,overflow;
   //word backup;
   //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
   numcnt = maskcnt = cnt; //Save count!
   s = oper1d;
   switch (thereg) {
   case 0: //ROL r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>31); //Save MSB!
         s = (s << 1)|FLAG_CF;
         overflow = (((s >> 31) & 1)^FLAG_CF);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 1: //ROR r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFFFFFU) | (FLAG_CF << 31);
         overflow = ((s >> 31) ^ ((s >> 30) & 1));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 2: //RCL r/m32
      if (EMULATED_CPU >= CPU_80386) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>31); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 31) & 1)^FLAG_CF); //OF=MSB^CF
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 3: //RCR r/m32
      if (EMULATED_CPU >= CPU_80386) maskcnt %= 33; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (((s >> 31)&1)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFFFFFU) | (tempCF << 31);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 4: case 6: //SHL r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>31);
         //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
         s = (s << 1) & 0xFFFFFFFFU;
         overflow = (FLAG_CF^(s>>31));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      if (numcnt) flag_szp32((uint32_t)(s&0xFFFFFFFFU));
      break;

   case 5: //SHR r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (s>>31);
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = s >> 1;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      if (numcnt) flag_szp32((uint32_t)(s & 0xFFFFFFFFU));
      break;

   case 7: //SAR r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      msb = s & 0x80000000U;
      //FLAGW_AF(0);
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = (s >> 1) | msb;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_AF(0);
      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 (!maskcnt) //Nothing done?
      {
         FLAGW_SF(tempSF); //We don't update when nothing's done!
      }
      else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
      {
         flag_szp32((uint32_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared!
      }
      else if (numcnt) //Anything shifted at all?
      {
         flag_szp32((uint32_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared with count as well?
      }
      break;
   }
   op_grp2_cycles32(numcnt, varshift);
   return (s & 0xFFFFFFFFU);
}


debugger_UniPCemu_test386.asm_20171121_0735.zip
test386.asm crashing on test E0.
(1.16 MiB) Downloaded 3 times
superfury
l33t
 
Posts: 2061
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: test386.asm CPU tester

Postby superfury » 2017-11-21 @ 10:21

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):
Code: Select all
      if ((EMULATED_CPU>=CPU_80386))
      {
         if ((maskcnt==0x10) || (maskcnt==0x18))
         {
            FLAGW_CF(s);
            FLAGW_OF(FLAG_CF);
            overflow = FLAG_OF;
            s = 0; //Make the result zeroed, according to IBMulator?
            goto skipshift;
         }
         if (maskcnt!=8) numcnt &= 7; //Limit count!
      }


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?

Edit: It seems to crash on the following part:
Code: Select all
0010:00003386 B0 00 mov al,00   Physical(r):000F3394=83(ƒ); Paged(r):000F3394=83(ƒ); Physical(r):000F3395=F8(ø); Paged(r):000F3395=F8(ø); Physical(r):000F3396=01(); Paged(r):000F3396=01(); Physical(r):000F3397=0F(); Paged(r):000F3397=0F()
Registers:
EAX: 0000ff01 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010002 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 00003386 EFLAGS: 00000803
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00Oditsz0a0p1C
0010:00003388 B1 09 mov cl,09
Registers:
EAX: 0000ff00 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010002 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 00003388 EFLAGS: 00000803
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00Oditsz0a0p1C
0010:0000338a D2 D8 rcr al,cl   Physical(r):000F3398=85(…); Paged(r):000F3398=85(…); Physical(r):000F3399=63(c); Paged(r):000F3399=63(c); Physical(r):000F339A=8C(Œ); Paged(r):000F339A=8C(Œ); Physical(r):000F339B=00( ); Paged(r):000F339B=00( )
Registers:
EAX: 0000ff00 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010002 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000338a EFLAGS: 00000803
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00Oditsz0a0p1C
   Paged(w):0001FFFE=02(); Paged(w):0001FFFF=08(); Paged(w):00020000=00( ); Paged(w):00020001=00( ); Physical(w):0001FFFE=02(); RAM(w):0001FFFE=02(); Physical(w):0001FFFF=08(); RAM(w):0001FFFF=08(); Physical(w):00020000=00( ); RAM(w):00020000=00( ); Physical(w):00020001=00( ); RAM(w):00020001=00( )
0010:0000338c 9C pushfd
Registers:
EAX: 0000ff00 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010002 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000338c EFLAGS: 00000802
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00Oditsz0a0p1c
   RAM(r):0001FFFE=02(); Physical(r):0001FFFE=02(); Paged(r):0001FFFE=02(); RAM(r):0001FFFF=08(); Physical(r):0001FFFF=08(); Paged(r):0001FFFF=08()
0010:0000338d 66 58 pop ax
Registers:
EAX: 0000ff00 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 0000fffe EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000338d EFLAGS: 00000802
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00Oditsz0a0p1c
0010:0000338f 66 25 D5 08 and ax,08d5   Physical(r):000F339C=00( ); Paged(r):000F339C=00( ); Physical(r):000F339D=66(f); Paged(r):000F339D=66(f); Physical(r):000F339E=B8(¸); Paged(r):000F339E=B8(¸); Physical(r):000F339F=00( ); Paged(r):000F339F=00( )
Registers:
EAX: 00000802 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010000 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000338f EFLAGS: 00000802
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00Oditsz0a0p1c
0010:00003393 66 83 F8 01 cmp ax,0001   Physical(r):000F33A0=00( ); Paged(r):000F33A0=00( ); Physical(r):000F33A1=66(f); Paged(r):000F33A1=66(f); Physical(r):000F33A2=50(P); Paged(r):000F33A2=50(P); Physical(r):000F33A3=9D(); Paged(r):000F33A3=9D()
Registers:
EAX: 00000800 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010000 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 00003393 EFLAGS: 00000006
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00oditsz0a0P1c
0010:00003397 0F 85 63 8C 00 00 jne 0000c000
Registers:
EAX: 00000800 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010000 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 00003397 EFLAGS: 00000016
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00oditsz0A0P1c
   RAM(r):00001003=00( ); Physical(r):00001003=00( ); Paged(r):00001003=00( ); RAM(r):00001002=00( ); Physical(r):00001002=00( ); Paged(r):00001002=00( ); RAM(r):00001001=20( ); Physical(r):00001001=20( ); Paged(r):00001001=20( ); RAM(r):00001000=27('); Physical(r):00001000=27('); Paged(r):00001000=27('); RAM(r):000023F3=00( ); Physical(r):000023F3=00( ); Paged(r):000023F3=00( ); RAM(r):000023F2=0F(); Physical(r):000023F2=0F(); Paged(r):000023F2=0F(); RAM(r):000023F1=C0(À); Physical(r):000023F1=C0(À); Paged(r):000023F1=C0(À); RAM(r):000023F0=27('); Physical(r):000023F0=27('); Paged(r):000023F0=27('); Physical(r):000FC000=FA(ú); Paged(r):000FC000=FA(ú); Physical(r):000FC001=F4(ô); Paged(r):000FC001=F4(ô); Physical(r):000FC002=EB(ë); Paged(r):000FC002=EB(ë); Physical(r):000FC003=FC(ü); Paged(r):000FC003=FC(ü)
0010:0000c000 FA cli
Registers:
EAX: 00000800 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010000 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000c000 EFLAGS: 00000016
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00oditsz0A0P1c
   Physical(r):000FC004=90(); Paged(r):000FC004=90(); Physical(r):000FC005=90(); Paged(r):000FC005=90(); Physical(r):000FC006=90(); Paged(r):000FC006=90(); Physical(r):000FC007=90(); Paged(r):000FC007=90()
   Physical(r):000FC008=90(); Paged(r):000FC008=90(); Physical(r):000FC009=90(); Paged(r):000FC009=90(); Physical(r):000FC00A=90(); Paged(r):000FC00A=90(); Physical(r):000FC00B=90(); Paged(r):000FC00B=90()
   Physical(r):000FC00C=90(); Paged(r):000FC00C=90(); Physical(r):000FC00D=90(); Paged(r):000FC00D=90(); Physical(r):000FC00E=90(); Paged(r):000FC00E=90(); Physical(r):000FC00F=90(); Paged(r):000FC00F=90()
0010:0000c001 F4 hlt
Registers:
EAX: 00000800 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010000 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000c001 EFLAGS: 00000016
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00oditsz0A0P1c
0010:0000c002 F4 <hlt>
Registers:
EAX: 00000800 EBX: 00010100 ECX: 00000009 EDX: ffff0084
ESP: 00010000 EBP: 00010000 ESI: 0000f000 EDI: 00000020
CS: 0010 DS: 0018 ES: 0018 FS: 5555 GS: 5555 SS: 0028 TR: 0000 LDTR: 0000
EIP: 0000c002 EFLAGS: 00000016
CR0: 80000001 CR1: 00000000 CR2: 00012000 CR3: 00001000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000f092f0037 IDTR: 0000000f096d0087
FLAGSINFO: 00000000000000vr0n00oditsz0A0P1cH


But it's modulo 9, so nothing is rotated and overflow isn't affected? Carry is set to bit 0?

Code: Select all
   case 2: //RCL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>7); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 3: //RCR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (((s >> 7)&1)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FU) | (tempCF << 7);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      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?
superfury
l33t
 
Posts: 2061
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: test386.asm CPU tester

Postby peterferrie » 2017-11-21 @ 19:39

superfury wrote:Just fixed the auxiliary flag to set(shl/shr) or clear(sar) on maskcnt!=0. Now shr crashes because of an invalid carry flag?


For SAR, auxilliary carry flag is always set for CPUs prior to Pentium 2 if count &0x1F != 0.
peterferrie
Oldbie
 
Posts: 603
Joined: 2008-5-08 @ 21:54

Re: test386.asm CPU tester

Postby superfury » 2017-11-21 @ 21:30

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:
Code: Select all
byte op_grp2_8(byte cnt, byte varshift) {
   //word d,
   INLINEREGISTER word s, shift, tempCF, msb;
   INLINEREGISTER byte numcnt, maskcnt, overflow;
   //word backup;
   //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
   numcnt = maskcnt = cnt; //Save count!
   s = oper1b;
   switch (thereg) {
   case 0: //ROL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>7); //Save MSB!
         s = (s << 1)|FLAG_CF;
         overflow = (((s >> 7) & 1)^FLAG_CF); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 1: //ROR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FU) | (FLAG_CF << 7);
         overflow = ((s >> 7) ^ ((s >> 6) & 1)); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>7); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 2: //RCL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>7); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 3: //RCR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (((s >> 7)&1)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FU) | (tempCF << 7);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 4: case 6: //SHL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if ((EMULATED_CPU>=CPU_80386))
      {
         if ((maskcnt==0x10) || (maskcnt==0x18))
         {
            FLAGW_CF(s);
            FLAGW_OF(FLAG_CF);
            overflow = FLAG_OF;
            s = 0; //Make the result zeroed, according to IBMulator?
            goto skipshift;
         }
         if (maskcnt!=8) numcnt &= 7; //Limit count!
      }
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>7);
         //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
         s = (s << 1) & 0xFFU;
         overflow = (FLAG_CF^(s>>7));
      }
      skipshift:
      if (maskcnt) flag_szp8((uint8_t)(s&0xFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 5: //SHR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      if (maskcnt && ((maskcnt&7)==0))
      {
         //Adjusted according to IBMulator!
         FLAGW_CF(s>>7); //Always sets CF, according to various sources?
      }
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (s>>7);
         if (numcnt&7) FLAGW_CF(s);
         //backup = s; //Save backup!
         s = s >> 1;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt) flag_szp8((uint8_t)(s & 0xFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 7: //SAR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Limit count! Not to be limited!
      msb = s & 0x80U;
      //FLAGW_AF(0);
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = (s >> 1) | msb;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_AF(0);
      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 (!maskcnt) //Nothing done?
      {
         FLAGW_SF(tempSF); //We don't update when nothing's done!
      }
      else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
      {
         flag_szp8((uint8_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared!
      }
      else if (numcnt) //Anything shifted at all?
      {
         flag_szp8((uint8_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared with count as well?
      }
      break;
   }
   op_grp2_cycles(numcnt, varshift);
   return (s & 0xFFU);
}


16-bit GRP2:
Code: Select all
word op_grp2_16(byte cnt, byte varshift) {
   //word d,
   INLINEREGISTER uint_32 s, shift, tempCF, msb;
   INLINEREGISTER byte numcnt, maskcnt, overflow;
   //word backup;
   //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
   numcnt = maskcnt = cnt; //Save count!
   s = oper1;
   switch (thereg) {
   case 0: //ROL r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>15); //Save MSB!
         s = (s << 1)|FLAG_CF;
         overflow = (((s >> 15) & 1)^FLAG_CF); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 1: //ROR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFU) | (FLAG_CF << 15);
         overflow = ((s >> 15) ^ ((s >> 14) & 1)); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 2: //RCL r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>15); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 15) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 3: //RCR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = ((s >> 15)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFU) | (tempCF << 15);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 4: case 6: //SHL r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>15);
         //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
         s = (s << 1) & 0xFFFFU;
         overflow = (FLAG_CF^(s>>15));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
      if (maskcnt) flag_szp16((uint16_t)(s&0xFFFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 5: //SHR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (s>>15);
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = s >> 1;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) flag_szp16((uint16_t)(s & 0xFFFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 7: //SAR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      msb = s & 0x8000U;
      //FLAGW_AF(0);
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = (s >> 1) | msb;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_AF(0);
      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 (!maskcnt) //Nothing done?
      {
         FLAGW_SF(tempSF); //We don't update when nothing's done!
      }
      else if (maskcnt==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!
         FLAGW_OF(0); //Cleared with count as well?
      }
      break;
   }
   op_grp2_cycles(numcnt, varshift);
   return (s & 0xFFFFU);
}


32-bit GRP2:
Code: Select all
uint_32 op_grp2_32(byte cnt, byte varshift) {
   //word d,
   INLINEREGISTER uint_64 s, shift, tempCF, msb;
   INLINEREGISTER byte numcnt,maskcnt,overflow;
   //word backup;
   //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
   numcnt = maskcnt = cnt; //Save count!
   s = oper1d;
   switch (thereg) {
   case 0: //ROL r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>31); //Save MSB!
         s = (s << 1)|FLAG_CF;
         overflow = (((s >> 31) & 1)^FLAG_CF);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 1: //ROR r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFFFFFU) | (FLAG_CF << 31);
         overflow = ((s >> 31) ^ ((s >> 30) & 1));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 2: //RCL r/m32
      if (EMULATED_CPU >= CPU_80386) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>31); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 31) & 1)^FLAG_CF); //OF=MSB^CF
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 3: //RCR r/m32
      if (EMULATED_CPU >= CPU_80386) maskcnt %= 33; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (((s >> 31)&1)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFFFFFU) | (tempCF << 31);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 4: case 6: //SHL r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>31);
         //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
         s = (s << 1) & 0xFFFFFFFFU;
         overflow = (FLAG_CF^(s>>31));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      if (maskcnt) flag_szp32((uint32_t)(s&0xFFFFFFFFU));
      break;

   case 5: //SHR r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (s>>31);
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = s >> 1;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      if (maskcnt) flag_szp32((uint32_t)(s & 0xFFFFFFFFU));
      break;

   case 7: //SAR r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      msb = s & 0x80000000U;
      //FLAGW_AF(0);
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = (s >> 1) | msb;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_AF(0);
      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 (!maskcnt) //Nothing done?
      {
         FLAGW_SF(tempSF); //We don't update when nothing's done!
      }
      else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
      {
         flag_szp32((uint32_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared!
      }
      else if (numcnt) //Anything shifted at all?
      {
         flag_szp32((uint32_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared with count as well?
      }
      break;
   }
   op_grp2_cycles32(numcnt, varshift);
   return (s & 0xFFFFFFFFU);
}


Can you see what's wrong, peterferrie?
superfury
l33t
 
Posts: 2061
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: test386.asm CPU tester

Postby peterferrie » 2017-11-22 @ 17:47

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:

Code: Select all
mov al,0x40
shl al, 0x10


will still perform the shift, AL will be zero, and OF will be set.
Carry is set as expected, too, so:

Code: Select all
mov al,1
shl 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.
peterferrie
Oldbie
 
Posts: 603
Joined: 2008-5-08 @ 21:54

Re: test386.asm CPU tester

Postby superfury » 2017-11-22 @ 20:17

I've adjusted the 8-bit functionality, but it still crashes(with results 0x800 in resulting flags instead of 0x1 after 8-bit rcr)?

debugger_UniPCemu_20171122_2219.zip
Log result of the new UniPCemu adjustments POST E0 test results.
(339.38 KiB) Downloaded 3 times


8-bit:
Code: Select all
byte op_grp2_8(byte cnt, byte varshift) {
   //word d,
   INLINEREGISTER word s, shift, tempCF, msb;
   INLINEREGISTER byte numcnt, maskcnt, overflow;
   //word backup;
   //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
   numcnt = maskcnt = cnt; //Save count!
   s = oper1b;
   switch (thereg) {
   case 0: //ROL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>7); //Save MSB!
         s = (s << 1)|FLAG_CF;
         overflow = (((s >> 7) & 1)^FLAG_CF); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 1: //ROR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FU) | (FLAG_CF << 7);
         overflow = ((s >> 7) ^ ((s >> 6) & 1)); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>7); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 2: //RCL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>7); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 3: //RCR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 9; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (((s >> 7)&1)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FU) | (tempCF << 7);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

case 4: case 6: //SHL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if ((EMULATED_CPU>=CPU_80386))
      {
         if (((maskcnt&0x18)==maskcnt) && maskcnt) //8/16/24 shifts?
         {
            numcnt = maskcnt = 8; //Brhave like a 8 bit shift!
         }
         else numcnt &= 7; //Limit count!
      }
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>7);
         //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
         s = (s << 1) & 0xFFU;
         overflow = (FLAG_CF^(s>>7));
      }
      skipshift:
      if (maskcnt) flag_szp8((uint8_t)(s&0xFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;
   case 5: //SHR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      if (maskcnt && ((maskcnt&7)==0))
      {
         //Adjusted according to IBMulator!
         FLAGW_CF(s>>7); //Always sets CF, according to various sources?
      }
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (s>>7);
         if (numcnt&7) FLAGW_CF(s);
         //backup = s; //Save backup!
         s = s >> 1;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt) flag_szp8((uint8_t)(s & 0xFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 7: //SAR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Limit count! Not to be limited!
      msb = s & 0x80U;
      //FLAGW_AF(0);
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = (s >> 1) | msb;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_AF(1);
      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 (!maskcnt) //Nothing done?
      {
         FLAGW_SF(tempSF); //We don't update when nothing's done!
      }
      else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
      {
         flag_szp8((uint8_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared!
      }
      else if (numcnt) //Anything shifted at all?
      {
         flag_szp8((uint8_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared with count as well?
      }
      break;
   }
   op_grp2_cycles(numcnt, varshift);
   return (s & 0xFFU);
}


16-bit:
Code: Select all
word op_grp2_16(byte cnt, byte varshift) {
   //word d,
   INLINEREGISTER uint_32 s, shift, tempCF, msb;
   INLINEREGISTER byte numcnt, maskcnt, overflow;
   //word backup;
   //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
   numcnt = maskcnt = cnt; //Save count!
   s = oper1;
   switch (thereg) {
   case 0: //ROL r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>15); //Save MSB!
         s = (s << 1)|FLAG_CF;
         overflow = (((s >> 15) & 1)^FLAG_CF); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 1: //ROR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFU) | (FLAG_CF << 15);
         overflow = ((s >> 15) ^ ((s >> 14) & 1)); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 2: //RCL r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>15); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 15) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 3: //RCR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt %= 17; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = ((s >> 15)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFU) | (tempCF << 15);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 4: case 6: //SHL r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>15);
         //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
         s = (s << 1) & 0xFFFFU;
         overflow = (FLAG_CF^(s>>15));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
      if (maskcnt) flag_szp16((uint16_t)(s&0xFFFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 5: //SHR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (s>>15);
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = s >> 1;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) flag_szp16((uint16_t)(s & 0xFFFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 7: //SAR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      msb = s & 0x8000U;
      //FLAGW_AF(0);
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = (s >> 1) | msb;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_AF(1);
      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 (!maskcnt) //Nothing done?
      {
         FLAGW_SF(tempSF); //We don't update when nothing's done!
      }
      else if (maskcnt==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!
         FLAGW_OF(0); //Cleared with count as well?
      }
      break;
   }
   op_grp2_cycles(numcnt, varshift);
   return (s & 0xFFFFU);
}


32-bit:
Code: Select all
uint_32 op_grp2_32(byte cnt, byte varshift) {
   //word d,
   INLINEREGISTER uint_64 s, shift, tempCF, msb;
   INLINEREGISTER byte numcnt,maskcnt,overflow;
   //word backup;
   //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
   numcnt = maskcnt = cnt; //Save count!
   s = oper1d;
   switch (thereg) {
   case 0: //ROL r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>31); //Save MSB!
         s = (s << 1)|FLAG_CF;
         overflow = (((s >> 31) & 1)^FLAG_CF);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 1: //ROR r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFFFFFU) | (FLAG_CF << 31);
         overflow = ((s >> 31) ^ ((s >> 30) & 1));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 2: //RCL r/m32
      if (EMULATED_CPU >= CPU_80386) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>31); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 31) & 1)^FLAG_CF); //OF=MSB^CF
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 3: //RCR r/m32
      if (EMULATED_CPU >= CPU_80386) maskcnt %= 33; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (((s >> 31)&1)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFFFFFU) | (tempCF << 31);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 4: case 6: //SHL r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>31);
         //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
         s = (s << 1) & 0xFFFFFFFFU;
         overflow = (FLAG_CF^(s>>31));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      if (maskcnt) flag_szp32((uint32_t)(s&0xFFFFFFFFU));
      break;

   case 5: //SHR r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (s>>31);
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = s >> 1;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      if (maskcnt) flag_szp32((uint32_t)(s & 0xFFFFFFFFU));
      break;

   case 7: //SAR r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      msb = s & 0x80000000U;
      //FLAGW_AF(0);
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = (s >> 1) | msb;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_AF(1);
      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 (!maskcnt) //Nothing done?
      {
         FLAGW_SF(tempSF); //We don't update when nothing's done!
      }
      else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
      {
         flag_szp32((uint32_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared!
      }
      else if (numcnt) //Anything shifted at all?
      {
         flag_szp32((uint32_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared with count as well?
      }
      break;
   }
   op_grp2_cycles32(numcnt, varshift);
   return (s & 0xFFFFFFFFU);
}


Can you see what's going wrong?
superfury
l33t
 
Posts: 2061
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: test386.asm CPU tester

Postby superfury » 2017-11-23 @ 10:33

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 :D It's running the current testsuite(The test386.asm commit of Sunday, 11/19/2017 18:45)

Current GRP2 opcodes:

8-bit
Code: Select all
byte op_grp2_8(byte cnt, byte varshift) {
   //word d,
   INLINEREGISTER word s, shift, tempCF, msb;
   INLINEREGISTER byte numcnt, maskcnt, overflow;
   //word backup;
   //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
   numcnt = maskcnt = cnt; //Save count!
   s = oper1b;
   switch (thereg) {
   case 0: //ROL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>7); //Save MSB!
         s = (s << 1)|FLAG_CF;
         overflow = (((s >> 7) & 1)^FLAG_CF); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 1: //ROR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FU) | (FLAG_CF << 7);
         overflow = ((s >> 7) ^ ((s >> 6) & 1)); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>7); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 2: //RCL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if ((EMULATED_CPU>=CPU_80386) && (maskcnt>9)) numcnt %= 9; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>7); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 7) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 3: //RCR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if ((EMULATED_CPU>=CPU_80386) && (maskcnt>9)) numcnt %= 9; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (((s >> 7)&1)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FU) | (tempCF << 7);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 4: case 6: //SHL r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if ((EMULATED_CPU>=CPU_80386))
      {
         if (((maskcnt&0x18)==maskcnt) && maskcnt) //8/16/24 shifts?
         {
            numcnt = maskcnt = 8; //Brhave like a 8 bit shift!
         }
         else numcnt &= 7; //Limit count!
      }
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>7);
         //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
         s = (s << 1) & 0xFFU;
         overflow = (FLAG_CF^(s>>7));
      }
      skipshift:
      if (maskcnt) flag_szp8((uint8_t)(s&0xFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 5: //SHR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      if (maskcnt && ((maskcnt&7)==0))
      {
         //Adjusted according to IBMulator!
         FLAGW_CF(s>>7); //Always sets CF, according to various sources?
      }
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (s>>7);
         if (numcnt&7) FLAGW_CF(s);
         //backup = s; //Save backup!
         s = s >> 1;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt) flag_szp8((uint8_t)(s & 0xFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 7: //SAR r/m8
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //if (EMULATED_CPU>=CPU_80386) numcnt &= 7; //Limit count! Not to be limited!
      msb = s & 0x80U;
      //FLAGW_AF(0);
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = (s >> 1) | msb;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_AF(1);
      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 (!maskcnt) //Nothing done?
      {
         FLAGW_SF(tempSF); //We don't update when nothing's done!
      }
      else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
      {
         flag_szp8((uint8_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared!
      }
      else if (numcnt) //Anything shifted at all?
      {
         flag_szp8((uint8_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared with count as well?
      }
      break;
   }
   op_grp2_cycles(numcnt, varshift);
   return (s & 0xFFU);
}


16-bit:
Code: Select all
word op_grp2_16(byte cnt, byte varshift) {
   //word d,
   INLINEREGISTER uint_32 s, shift, tempCF, msb;
   INLINEREGISTER byte numcnt, maskcnt, overflow;
   //word backup;
   //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
   numcnt = maskcnt = cnt; //Save count!
   s = oper1;
   switch (thereg) {
   case 0: //ROL r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>15); //Save MSB!
         s = (s << 1)|FLAG_CF;
         overflow = (((s >> 15) & 1)^FLAG_CF); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 1: //ROR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0xF; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFU) | (FLAG_CF << 15);
         overflow = ((s >> 15) ^ ((s >> 14) & 1)); //Only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 2: //RCL r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if ((EMULATED_CPU>=CPU_80386) && (maskcnt>17)) numcnt %= 17; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>15); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 15) & 1)^FLAG_CF); //OF=MSB^CF, only when not using CL?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 3: //RCR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if ((EMULATED_CPU>=CPU_80386) && (maskcnt>17)) numcnt %= 17; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = ((s >> 15)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFU) | (tempCF << 15);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      break;

   case 4: case 6: //SHL r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>15);
         //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
         s = (s << 1) & 0xFFFFU;
         overflow = (FLAG_CF^(s>>15));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>15); //Always sets CF, according to various sources?
      if (maskcnt) flag_szp16((uint16_t)(s&0xFFFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 5: //SHR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (s>>15);
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = s >> 1;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) flag_szp16((uint16_t)(s & 0xFFFFU));
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      break;

   case 7: //SAR r/m16
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      msb = s & 0x8000U;
      //FLAGW_AF(0);
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = (s >> 1) | msb;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_AF(1);
      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 (!maskcnt) //Nothing done?
      {
         FLAGW_SF(tempSF); //We don't update when nothing's done!
      }
      else if (maskcnt==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!
         FLAGW_OF(0); //Cleared with count as well?
      }
      break;
   }
   op_grp2_cycles(numcnt, varshift);
   return (s & 0xFFFFU);
}


32-bit:
Code: Select all
uint_32 op_grp2_32(byte cnt, byte varshift) {
   //word d,
   INLINEREGISTER uint_64 s, shift, tempCF, msb;
   INLINEREGISTER byte numcnt,maskcnt,overflow;
   //word backup;
   //if (cnt>0x8) return (oper1b); //NEC V20/V30+ limits shift count
   numcnt = maskcnt = cnt; //Save count!
   s = oper1d;
   switch (thereg) {
   case 0: //ROL r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>31); //Save MSB!
         s = (s << 1)|FLAG_CF;
         overflow = (((s >> 31) & 1)^FLAG_CF);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 1: //ROR r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      if (EMULATED_CPU>=CPU_80386) numcnt &= 0x1F; //Operand size wrap!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFFFFFU) | (FLAG_CF << 31);
         overflow = ((s >> 31) ^ ((s >> 30) & 1));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 2: //RCL r/m32
      if (EMULATED_CPU >= CPU_80386) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         tempCF = FLAG_CF;
         FLAGW_CF(s>>31); //Save MSB!
         s = (s << 1)|tempCF; //Shift and set CF!
         overflow = (((s >> 31) & 1)^FLAG_CF); //OF=MSB^CF
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 3: //RCR r/m32
      if (EMULATED_CPU >= CPU_80386) maskcnt %= 33; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //if (EMULATED_CPU >= CPU_NECV30) numcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      overflow = numcnt?0:FLAG_OF; //Default: no overflow!
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (((s >> 31)&1)^FLAG_CF);
         tempCF = FLAG_CF;
         FLAGW_CF(s); //Save LSB!
         s = ((s >> 1)&0x7FFFFFFFU) | (tempCF << 31);
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow); //Overflow?
      break;

   case 4: case 6: //SHL r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s>>31);
         //if (s & 0x8) FLAGW_AF(1); //Auxiliary carry?
         s = (s << 1) & 0xFFFFFFFFU;
         overflow = (FLAG_CF^(s>>31));
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s>>31); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      if (maskcnt) flag_szp32((uint32_t)(s&0xFFFFFFFFU));
      break;

   case 5: //SHR r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      //FLAGW_AF(0);
      overflow = numcnt?0:FLAG_OF;
      for (shift = 1; shift <= numcnt; shift++) {
         overflow = (s>>31);
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = s >> 1;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_OF(overflow);
      if (maskcnt) FLAGW_AF(1);
      if (maskcnt) flag_szp32((uint32_t)(s & 0xFFFFFFFFU));
      break;

   case 7: //SAR r/m32
      if (EMULATED_CPU >= CPU_NECV30) maskcnt &= 0x1F; //Clear the upper 3 bits to become a NEC V20/V30+!
      numcnt = maskcnt;
      msb = s & 0x80000000U;
      //FLAGW_AF(0);
      for (shift = 1; shift <= numcnt; shift++) {
         FLAGW_CF(s);
         //backup = s; //Save backup!
         s = (s >> 1) | msb;
         //if (((backup^s)&0x10)) FLAGW_AF(1); //Auxiliary carry?
      }
      if (maskcnt && (numcnt==0)) FLAGW_CF(s); //Always sets CF, according to various sources?
      if (maskcnt) FLAGW_AF(1);
      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 (!maskcnt) //Nothing done?
      {
         FLAGW_SF(tempSF); //We don't update when nothing's done!
      }
      else if (maskcnt==1) //Overflow is cleared on all 1-bit shifts!
      {
         flag_szp32((uint32_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared!
      }
      else if (numcnt) //Anything shifted at all?
      {
         flag_szp32((uint32_t)s); //Affect sign as well!
         FLAGW_OF(0); //Cleared with count as well?
      }
      break;
   }
   op_grp2_cycles32(numcnt, varshift);
   return (s & 0xFFFFFFFFU);
}


Is that behaviour for all those opcodes 100% correct, peterferrie?
superfury
l33t
 
Posts: 2061
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Previous

Return to PC Emulation

Who is online

Users browsing this forum: No registered users and 1 guest