Viewing Issue Advanced Details
ID Category [?] Severity [?] Reproducibility Date Submitted Last Update
01056 Core Typo Have not tried Feb 9, 2008, 04:16 Jul 15, 2010, 16:25
Tester -Misc Reporters- View Status Public Platform
Assigned To Resolution Fixed OS
Status [?] Resolved Driver
Version 0.57 Fixed in Version 0.66 Build
Fixed in Git Commit Github Pull Request #
Summary 01056: V30 core.
Description -Tomasz:
Hey .. maybe I'm wrong (as usual) - when tested Cygne with NEC v30 cpu core found something weird.
Maybe bug, maybe (probably) just a difference between x86 cpus and Nec ones (I have no detailed infos about nec cpus).
Problem is with Neg opcode and Carry flag. Value of Carry after NEG is opposite to value calculated by x86 core.
Inside bandai wonderswan is 80186 clone, probably designed by NEC. But carry in NEG must be calculated like in plain x86.


for example:
prefix 0xf6 , opcode & 0x38 = 0x18 => NEG
              I.CarryVal=(tmp==0);
               should be (at least for x86 and wonderswan )
                I.CarryVal=(tmp!=0);


carry should be set if tmp isn't 0 ( if 0 , then neg (sub 0,tmp) = 0-0 , no carry.. all other values (non-zeros) -> carry is set )
------------------------------------------------------------------------------------------------------------------------------------
-Stephh:
First, I checked the NEG operand with a REAL 80x86 debugger, I mean DEBUG.EXE included in DOS 6.22
(who told that DOS was history ? :p) and it confirms that the carry is set ONLY if value != 0 ...


Then I looked at the MAME CPU cores which have similarities :


  - 80x86 (src/cpu/i86 folder)
  - NEC V30 (src/cpu/nec folder)
  - V60 (src/cpu/v60 folder)




1) 80x86


From the source files, you can see that Peter Trauner (MESS Dev) has worked on the CPU core ...


In src/cpu/i86/instr86.c, we have the NEG instruction :


[BEGIN]
static void PREFIX86(_f6pre)(void)
{
/* Opcode 0xf6 */
unsigned ModRM = FETCH;
unsigned tmp = (unsigned)GetRMByte(ModRM);
unsigned tmp2;


switch (ModRM & 0x38)
{
...
case 0x18: /* NEG Eb */
ICOUNT -= (ModRM >= 0xc0) ? cycles.negnot_r8 : cycles.negnot_m8;
tmp2=0;
SUBB(tmp2,tmp);
PutbackRMByte(ModRM,tmp2);
break;
...
}
}
[END]


And in src/cpu/i86/i86.h, we have the macros (split in multiple lines for easier reading) :


[BEGIN]
#define SUBB(dst,src) \
{ unsigned res=dst-src; \
SetCFB(res); \
SetOFB_Sub(res,src,dst); \
SetAF(res,src,dst); \
SetSZPF_Byte(res); \
dst=(BYTE)res; \
}


#define SetCFB(x) (I.CarryVal = (x) & 0x100)
[END]


If you follow the code, you'll be given this ('tmp' being the value you want to NEG) :


  tmp == 0 => I.CarryVal = 0
  tmp != 0 => I.CarryVal = 1




2) V60


From the source files, you can see that Farfetch'd and R. Belmont have worked on the CPU core ...


In src/cpu/v60/op12.c, we have the NEG instruction :


[BEGIN]
UINT32 opNEGB(void) /* TRUSTED (C too!)*/
{
UINT8 tmpb;
F12DecodeFirstOperand(ReadAM,0);


tmpb = (INT8)(f12Op1&0xFF);
modWriteValB = 0;
SUBB(modWriteValB, (INT8)tmpb);


F12WriteSecondOperand(0);
F12END();
}
[END]


And in src/cpu/v60/v60.c, we have the macros (split in multiple lines for easier reading) :


[BEGIN]
#define SUBB(dst, src) \
{ unsigned res=(dst)-(src); \
SetCFB(res); \
SetOFB_Sub(res,src,dst); \
SetSZPF_Byte(res); \
dst=(UINT8)res; \
}


#define SetCFB(x) {_CY = ((x) & 0x100) ? 1 : 0; }
[END]



If you follow the code, you'll be given this ('tmp' being the value you want to NEG) :


  tmp == 0 => _CY = 0
  tmp != 0 => _CY = 1


You might have noticed that the 'SUBB' macro is 99.99% the same as in the 80x86 core
(only additional parenthesis around 'dst' and 'src') and also for the 'SetCFB' macro
(the carry is stored in other variable) ...




3) Nec V30


From the source files, you can see that Bryan McPhail ("Mish") has worked on the CPU core ...


In src/cpu/nec/nec.c, we have the NEG instruction (split in multiple lines for easier reading) :


[BEGIN]
OP( 0xf6, i_f6pre )
{
UINT32 tmp;
UINT32 uresult,uresult2;
INT32 result,result2;


GetModRM; tmp = GetRMByte(ModRM);


switch (ModRM & 0x38)
{
...
case 0x18: /* NEG */
I.CarryVal=(tmp==0);
tmp=(~tmp)+1; SetSZPF_Byte(tmp);
PutbackRMByte(ModRM,tmp&0xff);
nec_ICount-=(ModRM >=0xc0 )?2:16;
break;
...
   }
}
[END]


And in src/cpu/nec/nec.h, we have the macros (split in multiple lines for easier reading) :


[BEGIN]
#define SUBB \
{ UINT32 res=dst-src; \
SetCFB(res); \
SetOFB_Sub(res,src,dst); \
SetAF(res,src,dst); \
SetSZPF_Byte(res); \
dst=(BYTE)res; \
}


#define SetCFB(x) (I.CarryVal = (x) & 0x100)
[END]


Here the 'SUBB' and 'SetCFB' macros are 100% the same as in the 80x86 core ...


But for an obscure reason, the 'OP( 0xf6, i_f6pre )' does NOT call the 'SUBB' macro !


So, if you follow the code, you'll be given this ('tmp' being the value you want to NEG) :


  tmp == 0 => I.CarryVal = 1
  tmp != 0 => I.CarryVal = 0


And I can't guess that to be true: I know that the NEC V30 core had (has?) some bugs !
Do you remember the bug for 'bbmanw' about the wrong score being given at the end of level?
It was in fact a CPU core bug that was also caused by a BAD carry flag on the 'DAA' instr.
Steps To Reproduce
Additional Information Posted by Tomasz Slanina / stephh
Github Commit
Flags
Regression Version
Affected Sets / Systems
Attached Files
 
Relationships
There are no relationship linked to this issue.
Notes
1
User avatar
No.06377
AWJ
Developer
Jul 15, 2010, 16:25
This bug was fixed by Bryan McPhail in 0.66 (!)

Closing, 7 years late.