Page 1 of 1

Blood Shot issue

Posted: Tue Aug 03, 2010 9:49 pm
by fox68k
Hi,

we have found a weird bug in this game. As soon as you enter the room, turn right and get the player just in the corner. Then, turn the player left slowly, and you will eventually see some perspective errors and a blackish screen which locks up the emulator. Regen 0.972, Genesis Plus GX 1.4.0, Kega Fusion 3.64 and all the Gens versions I have tried so far (including Gens/GS) are affected by this issue.

Does anybody know what is causing this issue?

Thank you.

Posted: Wed Aug 04, 2010 8:43 am
by Eke
This is strange indeed, only happens randomly when you turn VERY slowly (to the left or to the right) when the graphics are garbled, it does not crash if you just turn around rapidly...

Have you verified it does not happen similarely on real hardware ? The fact it crashes in every emulator the same way seems to indicate a game bug but you never know, could be bad documented cpu flag or instruction.

According to Gens KMOD, 68k is crashing because A2 got corrupted then apparently PC got loaded with the content of A2 (jump instruction ?)

Posted: Wed Aug 04, 2010 9:37 am
by fox68k
Eke wrote:Have you verified it does not happen similarely on real hardware ? The fact it crashes in every emulator the same way seems to indicate a game bug but you never know, could be bad documented cpu flag or instruction.
I have verified it on real hardware (PAL MD-1) and it does work beautifully. No glitches or blackish screens whatsoever.
Eke wrote:According to Gens KMOD, 68k is crashing because A2 got corrupted then apparently PC got loaded with the content of A2 (jump instruction ?)
As far as i could see, there is a jump to 0x8XXXXX, which is illegal. The address comes from an indexed RAM read, and the index is coming from a MULS (in the particular case i have debugged values are 0x3200 -setup at the beginning of gameplay- and 0x2c, IIRC).

Posted: Wed Aug 04, 2010 10:45 am
by Eke
on a side note, exception and TRAP0 entry points have quite unexpected values in the ROM header , seems to point out of ROM area (above $200000)...

I have no way to test right now, but try to mirror ROM data above $200000 or change the exception vectors to fit in within ROM and see what happen ?


EDIT: i spotted a possible issue in Musashi regarding the following MULS instruction

Code: Select all

static void m68k_op_muls_16_d(void)
{
  uint* r_dst = &DX;
  uint src = MAKE_INT_16(DY);
  uint res = MASK_OUT_ABOVE_32( src * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst)));

  uint cyc = getMuls68kCycles(src);
  USE_CYCLES(cyc);

  *r_dst = res;

  FLAG_Z = res;
  FLAG_N = NFLAG_32(res);
  FLAG_V = VFLAG_CLEAR;
  FLAG_C = CFLAG_CLEAR;
}
with

Code: Select all

/* Allow for architectures that don't have 16-bit sizes */
#if USHRT_MAX == 0xffff
  #define MAKE_INT_16(A) (sint16)(A)
#else
  #undef  sint16
  #define sint16 signed   int
  #undef  uint16
  #define uint16 unsigned int
  INLINE sint MAKE_INT_16(uint value)
  {
    return (value & 0x8000) ? value | ~0xffff : value & 0xffff;
  }
#endif /* USHRT_MAX == 0xffff */

it seems the src register is not properly masked, it should be:

Code: Select all

 uint src = MAKE_INT_16(MASK_OUT_ABOVE_16(DY));
otherwise,I think it can overflow when it shouldn't

Posted: Wed Aug 04, 2010 2:52 pm
by fox68k
Eke wrote:on a side note, exception and TRAP0 entry points have quite unexpected values in the ROM header , seems to point out of ROM area (above $200000)...

I have no way to test right now, but try to mirror ROM data above $200000 or change the exception vectors to fit in within ROM and see what happen ?
No, I have not. I can do when i get home.
Eke wrote:EDIT: i spotted a possible issue in Musashi regarding the following MULS instruction
It is unlikely this is caused by a buggy opcode implementation. That would mean different cores have the same bug. And I do not think that is the case.

Posted: Wed Aug 04, 2010 4:29 pm
by Eke
yes, probably
and after some thought, seems like Musashi implementation is correct, I forgot it was signed multiplication so casting to signed short would extend the sign bit, it does not matter if MSB are masked or not :oops:

Posted: Wed Aug 04, 2010 8:19 pm
by Gigasoft
DIVU doesn't set the N flag correctly when there is an overflow. The manual doesn't tell how it should be set, so someone has to test it on a real Mega Drive.

I found that putting $6D00 at location $EDEA fixes the problem. I don't know what to do about the messed up textures in the first room, though.

Posted: Thu Aug 05, 2010 8:25 am
by Eke
Great find ! I see your patch changes a BMI instruction to BLT after a DIVU instruction, patching with BVS also fixes it so it is definitively related to undefined N flag behavior when overflow occurs.

According to this code(from Hatari emulator), the 68k on Atari ST sets N flag when overflow occurs on DIVU/DIVS

It seems to be also the case on Mega Drive.
I don't know what to do about the messed up textures in the first room, though.
i think they are supposed to look like that :?
http://www.youtube.com/watch?v=Lbj1OXv8xuo

EDIT: found another issue in Musashi regarding flags, C flag is not cleared when overflow or division by zero occur, while it should always be cleared everytime DIVU/DIVS is executed.

Posted: Thu Aug 05, 2010 9:04 am
by Shiru
The textures are messed on real HW. Long ago I've thought my cartridge is glitchy because of that, but later I've seen other cartridges, there the textures were messed as well.

Posted: Thu Aug 05, 2010 12:57 pm
by fox68k
Gigasoft wrote:DIVU doesn't set the N flag correctly when there is an overflow. The manual doesn't tell how it should be set, so someone has to test it on a real Mega Drive.

I found that putting $6D00 at location $EDEA fixes the problem. I don't know what to do about the messed up textures in the first room, though.
So I was wrong. DIVU is buggy. Thanks for your help.

By the way, how did you figure out?

Posted: Thu Aug 05, 2010 8:38 pm
by Gigasoft
It was using a negative value as a function table index, so I found out, using Gens' instruction logging feature, that the value was coming from that DIVU instruction, and that it was overflowing, so that the old value in the register was used, without N being set. Since there was a BMI afterwards, it was obvious that N was supposed to be set for the faces that shouldn't be displayed.