[ オリジナルレポート ]

BugID: #01056

カテゴリ 重要度 ステータス 解決状況 登録日時 最終更新
システムコア誤字解決済み修正済み2008-02-09 13:162010-07-16 01:25
 
テスター-Misc Reporters-担当者 ソース
バージョン0.57発生バージョン修正バージョン0.66
フラグ旧BugIDv30057ora
セット
セット詳細
 
概 要V30コアの問題。
詳 細-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.
再現手順 
追加情報Posted by Tomasz Slanina / stephh
 
添付ファイル