gen: fix dumb tile priority bug (primarily affects Ghouls n Ghosts, which use the layers backwards from normal)
This commit is contained in:
parent
ff84855f2a
commit
e24f0962fc
|
@ -48,6 +48,9 @@ namespace Native68000
|
|||
[DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int QueryCpuState(int regcode);
|
||||
|
||||
[DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int GetCyclesRemaining();
|
||||
|
||||
public static int D0 { get { return QueryCpuState(0); } }
|
||||
public static int D1 { get { return QueryCpuState(1); } }
|
||||
public static int D2 { get { return QueryCpuState(2); } }
|
||||
|
|
|
@ -6,3 +6,26 @@ Timings:
|
|||
- How many cycles does TRAP take to execute?
|
||||
- How many cycles does it take to accept an interrupt?
|
||||
- AND has some funky timings when it comes to immediates?
|
||||
|
||||
GAMES:
|
||||
|
||||
Monster World 4 - Music is messed up now. Timing is all off. It used to work.
|
||||
Quackshot doesn't boot.
|
||||
Moonwalker doesn't boot.
|
||||
Altered Beast: start with 0 health, 0 lives???
|
||||
Contra Hard Corps: Scrolling is messed up in level 1... used to work.
|
||||
After Burner 2: No music
|
||||
MUSHA: Intro music starts too soon
|
||||
MUSHA: uses unimplemented VRAM copy
|
||||
MUSHA: Some sprites have messed up left/right symmetry
|
||||
Landstalker: freezes during new game sequence, very early
|
||||
|
||||
Things that read from VRAM work like 50%-90%, but not 100%. It's frustrating. Kid Chameleon and Eternal Champions are examples.
|
||||
|
||||
Some games flicker in the rightmost columns. Is this caused by mid-frame mode shifting(32/40 col modes?) Alisia Dragoon is one example.
|
||||
|
||||
|
||||
TODO: non-instant DMA emulation
|
||||
TODO: Add 68000/VDP interrupt enable delay (one instruction, similar to After Burner/PCE)
|
||||
TODO: freaking H-interrupts
|
||||
TODO: Test DMA/ VDP command words.... I'm not at all convinced that VRAM is always correct
|
|
@ -64,7 +64,7 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
int palette = (nameTableEntry >> 13) & 3;
|
||||
|
||||
if (priority && PriorityBuffer[x] >= highPriority) continue;
|
||||
if (PriorityBuffer[x] >= lowPriority) continue;
|
||||
if (!priority && PriorityBuffer[x] >= lowPriority) continue;
|
||||
|
||||
if (vFlip) yOfs = 7 - yOfs;
|
||||
if (hFlip) xOfs = 7 - xOfs;
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
public int FrameWidth = 256;
|
||||
|
||||
public int ScanLine;
|
||||
public int HIntLineCounter;
|
||||
|
||||
public bool HInterruptsEnabled { get { return (Registers[0] & 0x10) != 0; } }
|
||||
public bool DisplayEnabled { get { return (Registers[1] & 0x40) != 0; } }
|
||||
|
@ -26,6 +27,8 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
public bool CellBasedVertScroll { get { return (Registers[11] & 0x08) != 0; } }
|
||||
public bool Display40Mode { get { return (Registers[12] & 0x81) != 0; } }
|
||||
|
||||
public bool InDisplayPeriod { get { return ScanLine < 224 && DisplayEnabled; } }
|
||||
|
||||
ushort NameTableAddrA;
|
||||
ushort NameTableAddrB;
|
||||
ushort NameTableAddrWindow;
|
||||
|
@ -46,12 +49,12 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
const int CommandCramRead = 7;
|
||||
|
||||
public ushort VdpStatusWord = 0x3400;
|
||||
public const int StatusVerticalInterruptPending = 0x80;
|
||||
public const int StatusSpriteOverflow = 0x40;
|
||||
public const int StatusSpriteCollision = 0x20;
|
||||
public const int StatusOddFrame = 0x10;
|
||||
public const int StatusVerticalBlanking = 0x08;
|
||||
public const int StatusHorizBlanking = 0x04;
|
||||
public const int StatusVerticalBlanking = 0x08;
|
||||
public const int StatusOddFrame = 0x10;
|
||||
public const int StatusSpriteCollision = 0x20;
|
||||
public const int StatusSpriteOverflow = 0x40;
|
||||
public const int StatusVerticalInterruptPending = 0x80;
|
||||
|
||||
public ushort ReadVdp(int addr)
|
||||
{
|
||||
|
@ -64,8 +67,7 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
case 6:
|
||||
return ReadVdpControl();
|
||||
default:
|
||||
//throw new Exception("HV Counter read....");
|
||||
return 0;
|
||||
return ReadHVCounter();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,7 +144,11 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
|
||||
public ushort ReadVdpControl()
|
||||
{
|
||||
VdpStatusWord |= 0x0200; // Fifo empty
|
||||
VdpStatusWord |= 0x0200; // Fifo empty // TODO kill this, emulating the damn FIFO.
|
||||
|
||||
// sprite overflow flag should clear.
|
||||
// sprite collision flag should clear.
|
||||
|
||||
return VdpStatusWord;
|
||||
}
|
||||
|
||||
|
@ -151,9 +157,11 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
ControlWordPending = false;
|
||||
|
||||
// byte-swap incoming data when A0 is set
|
||||
// TODO what is the reason for thinking that this happens?
|
||||
//if ((VdpDataAddr & 1) != 0)
|
||||
// data = (ushort) ((data >> 8) | (data << 8));
|
||||
if ((VdpDataAddr & 1) != 0)
|
||||
{
|
||||
data = (ushort)((data >> 8) | (data << 8));
|
||||
Console.WriteLine("VRAM byte-swap is happening because A0 is not 0");
|
||||
}
|
||||
|
||||
if (DmaFillModePending)
|
||||
{
|
||||
|
@ -182,7 +190,7 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
VdpDataAddr += Registers[0x0F];
|
||||
break;
|
||||
default:
|
||||
//Console.WriteLine("VDP DATA WRITE WITH UNHANDLED CODE!!!");
|
||||
Console.WriteLine("VDP DATA WRITE WITH UNHANDLED CODE!!!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -203,11 +211,30 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
throw new Exception("VSRAM read");
|
||||
case CommandCramRead:
|
||||
throw new Exception("CRAM read");
|
||||
default:
|
||||
throw new Exception("VRAM read with unexpected code!!!");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
ushort ReadHVCounter()
|
||||
{
|
||||
int vcounter = ScanLine;
|
||||
if (vcounter > 0xEA)
|
||||
vcounter -= 7;
|
||||
// TODO generalize this across multiple video modes and stuff.
|
||||
|
||||
// TODO dont tie this to musashi cycle count.
|
||||
// Figure out a "clean" way to get cycle counter information available to VDP.
|
||||
int hcounter = (487 - Native68000.Musashi.GetCyclesRemaining()) * 255 / 487;
|
||||
|
||||
ushort res = (ushort) ((vcounter << 8) | (hcounter & 0xFF));
|
||||
Console.WriteLine("READ HVC: V={0:X2} H={1:X2} ret={2:X4}", vcounter, hcounter, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public void WriteVdpRegister(int register, byte data)
|
||||
{
|
||||
Log.Note("VDP", "Register {0}: {1:X2}", register, data);
|
||||
|
@ -317,13 +344,13 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
case 0x11: // Window H Position
|
||||
int whp = data & 31;
|
||||
bool fromright = (data & 0x80) != 0;
|
||||
Log.Error("VDP", "Window H is {0} units from {1}", whp, fromright ? "right" : "left");
|
||||
//Log.Error("VDP", "Window H is {0} units from {1}", whp, fromright ? "right" : "left");
|
||||
break;
|
||||
|
||||
case 0x12: // Window V
|
||||
whp = data & 31;
|
||||
fromright = (data & 0x80) != 0;
|
||||
Log.Error("VDP", "Window V is {0} units from {1}", whp, fromright ? "lower" : "upper");
|
||||
//Log.Error("VDP", "Window V is {0} units from {1}", whp, fromright ? "lower" : "upper");
|
||||
break;
|
||||
|
||||
case 0x13: // DMA Length Low
|
||||
|
|
|
@ -137,6 +137,12 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
Controller.UpdateControls(Frame++);
|
||||
PSG.BeginFrame(SoundCPU.TotalExecutedCycles);
|
||||
YM2612.BeginFrame(SoundCPU.TotalExecutedCycles);
|
||||
|
||||
// Do start-of-frame events
|
||||
VDP.HIntLineCounter = VDP.Registers[10];
|
||||
//VDP.VdpStatusWord &=
|
||||
unchecked { VDP.VdpStatusWord &= (ushort)~GenVDP.StatusVerticalBlanking; }
|
||||
|
||||
for (VDP.ScanLine = 0; VDP.ScanLine < 262; VDP.ScanLine++)
|
||||
{
|
||||
//Log.Error("VDP","FRAME {0}, SCANLINE {1}", Frame, VDP.ScanLine);
|
||||
|
@ -164,12 +170,13 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
|
||||
if (Z80Runnable)
|
||||
SoundCPU.Interrupt = true;
|
||||
//The INT output is asserted every frame for exactly one scanline, and it can't be disabled. A very short Z80 interrupt routine would be triggered multiple times if it finishes within 228 Z80 clock cycles. I think (but cannot recall the specifics) that some games have delay loops in the interrupt handler for this very reason.
|
||||
}
|
||||
}
|
||||
PSG.EndFrame(SoundCPU.TotalExecutedCycles);
|
||||
YM2612.EndFrame(SoundCPU.TotalExecutedCycles);
|
||||
|
||||
unchecked { VDP.VdpStatusWord &= (ushort)~GenVDP.StatusVerticalBlanking; }
|
||||
|
||||
|
||||
if (lagged)
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace BizHawk.Emulation.Consoles.Sega
|
|||
|
||||
if (address >= 0xC00000 && address < 0xC00010)
|
||||
{
|
||||
Console.WriteLine("byte-reading the VDP. someone is probably stupid.");
|
||||
//Console.WriteLine("byte-reading the VDP. someone is probably stupid.");
|
||||
ushort value = VDP.ReadVdp(address & 0x0E);
|
||||
if ((address & 1) == 0) // read MSB
|
||||
return (sbyte) (value >> 8);
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue