GBHawk: Fix some GBC Behaviours, start MBC7
This commit is contained in:
parent
fde2035f31
commit
6019073157
|
@ -52,6 +52,35 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
OP };
|
||||
}
|
||||
|
||||
private void INTERRUPT_GBC_NOP()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
IDLE,
|
||||
WR, SPl, SPh, PCh,
|
||||
IDLE,
|
||||
INT_GET, W,// NOTE: here is where we check for a cancelled IRQ
|
||||
DEC16, SPl, SPh,
|
||||
WR, SPl, SPh, PCl,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
TR, PCl, W,
|
||||
ASGN, PCh, 0,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60, 0x00};
|
||||
|
||||
public ushort int_src;
|
||||
|
|
|
@ -279,18 +279,21 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
});
|
||||
}
|
||||
halted = false;
|
||||
|
||||
|
||||
if (is_GBC)
|
||||
{
|
||||
// call the interrupt processor after 4 extra cycles
|
||||
/*
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
GBC_INTERRUPT };
|
||||
*/
|
||||
INTERRUPT_GBC_NOP();
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
// call interrupt processor
|
||||
INTERRUPT_();
|
||||
}
|
||||
|
@ -309,6 +312,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
halted = false;
|
||||
if (OnExecFetch != null) OnExecFetch(RegPC);
|
||||
if (TraceCallback != null && !CB_prefix) TraceCallback(State());
|
||||
|
||||
if (is_GBC)
|
||||
{
|
||||
// extra 4 cycles for GBC
|
||||
|
@ -319,7 +323,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
OP };
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
FetchInstruction(ReadMemory(RegPC++));
|
||||
}
|
||||
}
|
||||
|
@ -335,7 +339,6 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
break;
|
||||
case STOP:
|
||||
stopped = true;
|
||||
|
||||
if (!stop_check)
|
||||
{
|
||||
stop_time = SpeedFunc(0);
|
||||
|
|
|
@ -79,7 +79,6 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
|
||||
if (FlagI && (EI_pending == 0))
|
||||
{
|
||||
|
||||
if (is_GBC)
|
||||
{
|
||||
// in GBC mode, the HALT bug is worked around by simply adding a NOP
|
||||
|
|
|
@ -22,6 +22,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
public byte HDMA_src_lo;
|
||||
public byte HDMA_dest_hi;
|
||||
public byte HDMA_dest_lo;
|
||||
public int HDMA_tick;
|
||||
public byte HDMA_byte;
|
||||
|
||||
// accessors for derived values
|
||||
public byte BG_pal_ret
|
||||
|
@ -179,6 +181,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
HDMA_mode = value.Bit(7);
|
||||
HDMA_countdown = 4;
|
||||
HDMA_tick = 0;
|
||||
if (value.Bit(7))
|
||||
{
|
||||
// HDMA during HBlank only
|
||||
|
@ -253,59 +256,47 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
if (HDMA_countdown == 0)
|
||||
{
|
||||
if (!HDMA_mode)
|
||||
if (HDMA_length > 0)
|
||||
{
|
||||
// immediately transfer bytes, 2 bytes per cycles
|
||||
if (HDMA_length > 0)
|
||||
if (!HDMA_mode)
|
||||
{
|
||||
Core.VRAM[(Core.VRAM_Bank * 0x2000) + cur_DMA_dest] = Core.ReadMemory(cur_DMA_src);
|
||||
cur_DMA_dest = (ushort)((cur_DMA_dest + 1) & 0x1FFF);
|
||||
cur_DMA_src = (ushort)((cur_DMA_src + 1) & 0xFFFF);
|
||||
HDMA_length--;
|
||||
|
||||
Core.VRAM[(Core.VRAM_Bank * 0x2000) + cur_DMA_dest] = Core.ReadMemory(cur_DMA_src);
|
||||
cur_DMA_dest = (ushort)((cur_DMA_dest + 1) & 0x1FFF);
|
||||
cur_DMA_src = (ushort)((cur_DMA_src + 1) & 0xFFFF);
|
||||
HDMA_length--;
|
||||
|
||||
if (HDMA_length == 0)
|
||||
// immediately transfer bytes, 2 bytes per cycles
|
||||
if ((HDMA_tick % 2) == 0)
|
||||
{
|
||||
HDMA_active = false;
|
||||
Core.HDMA_transfer = false;
|
||||
HDMA_byte = Core.ReadMemory(cur_DMA_src);
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.VRAM[(Core.VRAM_Bank * 0x2000) + cur_DMA_dest] = HDMA_byte;
|
||||
cur_DMA_dest = (ushort)((cur_DMA_dest + 1) & 0x1FFF);
|
||||
cur_DMA_src = (ushort)((cur_DMA_src + 1) & 0xFFFF);
|
||||
HDMA_length--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// only transfer during mode 0, and only 16 bytes at a time
|
||||
if (((STAT & 3) == 0) && (LY != last_HBL) && HBL_test)
|
||||
else
|
||||
{
|
||||
HBL_HDMA_go = true;
|
||||
HBL_test = false;
|
||||
}
|
||||
|
||||
if (HBL_HDMA_go && (HBL_HDMA_count > 0))
|
||||
{
|
||||
Core.HDMA_transfer = true;
|
||||
|
||||
if (HDMA_length > 0)
|
||||
// only transfer during mode 0, and only 16 bytes at a time
|
||||
if (((STAT & 3) == 0) && (LY != last_HBL) && HBL_test)
|
||||
{
|
||||
Core.VRAM[(Core.VRAM_Bank * 0x2000) + cur_DMA_dest] = Core.ReadMemory(cur_DMA_src);
|
||||
cur_DMA_dest = (ushort)((cur_DMA_dest + 1) & 0x1FFF);
|
||||
cur_DMA_src = (ushort)((cur_DMA_src + 1) & 0xFFFF);
|
||||
HDMA_length--;
|
||||
HBL_HDMA_count--;
|
||||
HBL_HDMA_go = true;
|
||||
HBL_test = false;
|
||||
}
|
||||
|
||||
Core.VRAM[(Core.VRAM_Bank * 0x2000) + cur_DMA_dest] = Core.ReadMemory(cur_DMA_src);
|
||||
cur_DMA_dest = (ushort)((cur_DMA_dest + 1) & 0x1FFF);
|
||||
cur_DMA_src = (ushort)((cur_DMA_src + 1) & 0xFFFF);
|
||||
HDMA_length--;
|
||||
HBL_HDMA_count--;
|
||||
if (HBL_HDMA_go && (HBL_HDMA_count > 0))
|
||||
{
|
||||
Core.HDMA_transfer = true;
|
||||
|
||||
if (HDMA_length == 0)
|
||||
if ((HDMA_tick % 2) == 0)
|
||||
{
|
||||
HDMA_active = false;
|
||||
Core.HDMA_transfer = false;
|
||||
HDMA_byte = Core.ReadMemory(cur_DMA_src);
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.VRAM[(Core.VRAM_Bank * 0x2000) + cur_DMA_dest] = HDMA_byte;
|
||||
cur_DMA_dest = (ushort)((cur_DMA_dest + 1) & 0x1FFF);
|
||||
cur_DMA_src = (ushort)((cur_DMA_src + 1) & 0xFFFF);
|
||||
HDMA_length--;
|
||||
HBL_HDMA_count--;
|
||||
}
|
||||
|
||||
if ((HBL_HDMA_count == 0) && (HDMA_length != 0))
|
||||
|
@ -316,11 +307,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
HBL_HDMA_go = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.HDMA_transfer = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.HDMA_transfer = false;
|
||||
}
|
||||
|
||||
HDMA_tick++;
|
||||
}
|
||||
else
|
||||
{
|
||||
HDMA_active = false;
|
||||
Core.HDMA_transfer = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1481,6 +1479,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
ser.Sync("HDMA_src_lo", ref HDMA_src_lo);
|
||||
ser.Sync("HDMA_dest_hi", ref HDMA_dest_hi);
|
||||
ser.Sync("HDMA_dest_lo", ref HDMA_dest_lo);
|
||||
ser.Sync("HDMA_tick", ref HDMA_tick);
|
||||
ser.Sync("HDMA_byte", ref HDMA_byte);
|
||||
|
||||
ser.Sync("VRAM_sel", ref VRAM_sel);
|
||||
ser.Sync("BG_V_flip", ref BG_V_flip);
|
||||
|
|
|
@ -137,9 +137,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
timer.tick_1();
|
||||
timer.tick_2();
|
||||
cpu.TotalExecutedCycles++;
|
||||
if (double_speed)
|
||||
{
|
||||
timer.tick_1();
|
||||
timer.tick_2();
|
||||
cpu.TotalExecutedCycles++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
byte Read(IController c);
|
||||
|
||||
ushort ReadAccX(IController c);
|
||||
|
||||
ushort ReadAccY(IController c);
|
||||
|
||||
ControllerDefinition Definition { get; }
|
||||
|
||||
void SyncState(Serializer ser);
|
||||
|
@ -81,6 +85,98 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
return result;
|
||||
}
|
||||
|
||||
public ushort ReadAccX(IController c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ushort ReadAccY(IController c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power"
|
||||
};
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
//nothing
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName("Gameboy Controller + Kirby")]
|
||||
public class StandardKirby : IPort
|
||||
{
|
||||
public StandardKirby(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = "Gameboy Controller + Kirby",
|
||||
BoolButtons = BaseDefinition
|
||||
.Select(b => "P" + PortNum + " " + b)
|
||||
.ToList(),
|
||||
FloatControls = { "P" + PortNum + " Tilt X", "P" + PortNum + " Tilt Y" },
|
||||
FloatRanges = { new[] { -127.0f, 0, 127.0f }, new[] { -127.0f, 0, 127.0f } }
|
||||
};
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public byte Read(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
if (c.IsPressed(Definition.BoolButtons[0]))
|
||||
{
|
||||
result -= 4;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[1]))
|
||||
{
|
||||
result -= 8;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[2]))
|
||||
{
|
||||
result -= 2;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[3]))
|
||||
{
|
||||
result -= 1;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[4]))
|
||||
{
|
||||
result -= 128;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[5]))
|
||||
{
|
||||
result -= 64;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[6]))
|
||||
{
|
||||
result -= 32;
|
||||
}
|
||||
if (c.IsPressed(Definition.BoolButtons[7]))
|
||||
{
|
||||
result -= 16;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ushort ReadAccX(IController c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ushort ReadAccY(IController c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power"
|
||||
|
|
|
@ -4,7 +4,7 @@ using System;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
// MBC5, common mapper for GBC games
|
||||
public class MapperMBC5 : MapperBase
|
||||
{
|
||||
public int ROM_bank;
|
||||
|
|
|
@ -4,31 +4,63 @@ using System;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
// Default mapper with no bank switching
|
||||
// Mapper with built in EEPROM, also used with Kirby's tilt 'n tumble
|
||||
// The EEPROM contains 256 bytes of read/write memory
|
||||
public class MapperMBC7 : MapperBase
|
||||
{
|
||||
public int ROM_bank;
|
||||
public bool RAM_enable_1, RAM_enable_2;
|
||||
public int ROM_mask;
|
||||
public byte acc_x_low;
|
||||
public byte acc_x_high;
|
||||
public byte acc_y_low;
|
||||
public byte acc_y_high;
|
||||
public bool is_erased;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
// nothing to initialize
|
||||
ROM_bank = 1;
|
||||
RAM_enable_1 = RAM_enable_2 = false;
|
||||
ROM_mask = Core._rom.Length / 0x4000 - 1;
|
||||
|
||||
// some games have sizes that result in a degenerate ROM, account for it here
|
||||
if (ROM_mask > 4) { ROM_mask |= 3; }
|
||||
|
||||
acc_x_low = 0;
|
||||
acc_x_high = 0x80;
|
||||
acc_y_low = 0;
|
||||
acc_y_high = 0x80;
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
if (addr < 0x4000)
|
||||
{
|
||||
return Core._rom[addr];
|
||||
}
|
||||
else
|
||||
else if (addr < 0x8000)
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000];
|
||||
}
|
||||
else if (addr < 0xA000)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
else if (addr < 0xB000)
|
||||
{
|
||||
if (RAM_enable_2)
|
||||
{
|
||||
return Core.cart_RAM[addr - 0xA000];
|
||||
return Register_Access_Read(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
public override byte PeekMemory(ushort addr)
|
||||
|
@ -38,15 +70,33 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr < 0x8000)
|
||||
if (addr < 0xA000)
|
||||
{
|
||||
// no mapping hardware available
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
RAM_enable_1 = (value & 0xF) == 0xA;
|
||||
}
|
||||
else if (addr < 0x4000)
|
||||
{
|
||||
value &= 0xFF;
|
||||
|
||||
ROM_bank &= 0x100;
|
||||
ROM_bank |= value;
|
||||
ROM_bank &= ROM_mask;
|
||||
}
|
||||
else if (addr < 0x6000)
|
||||
{
|
||||
if (RAM_enable_1)
|
||||
{
|
||||
RAM_enable_2 = (value & 0xF0) == 0x40;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM != null)
|
||||
if (RAM_enable_2)
|
||||
{
|
||||
Core.cart_RAM[addr - 0xA000] = value;
|
||||
Register_Access_Write(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,5 +105,90 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("ROM_Bank", ref ROM_bank);
|
||||
ser.Sync("ROM_Mask", ref ROM_mask);
|
||||
ser.Sync("RAM_enable_1", ref RAM_enable_1);
|
||||
ser.Sync("RAM_enable_2", ref RAM_enable_2);
|
||||
ser.Sync("acc_x_low", ref acc_x_low);
|
||||
ser.Sync("acc_x_high", ref acc_x_high);
|
||||
ser.Sync("acc_y_low", ref acc_y_low);
|
||||
ser.Sync("acc_y_high", ref acc_y_high);
|
||||
ser.Sync("is_erased", ref is_erased);
|
||||
}
|
||||
|
||||
public void Register_Access_Write(ushort addr, byte value)
|
||||
{
|
||||
if ((addr & 0xA0F0) == 0xA000)
|
||||
{
|
||||
if (value == 0x55)
|
||||
{
|
||||
is_erased = true;
|
||||
acc_x_low = 0;
|
||||
acc_x_high = 0x80;
|
||||
acc_y_low = 0;
|
||||
acc_y_high = 0x80;
|
||||
}
|
||||
}
|
||||
else if ((addr & 0xA0F0) == 0xA010)
|
||||
{
|
||||
if ((value == 0xAA) && is_erased)
|
||||
{
|
||||
// latch new accelerometer values
|
||||
}
|
||||
}
|
||||
else if ((addr & 0xA0F0) == 0xA080)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public byte Register_Access_Read(ushort addr)
|
||||
{
|
||||
if ((addr & 0xA0F0) == 0xA000)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
else if ((addr & 0xA0F0) == 0xA010)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
else if ((addr & 0xA0F0) == 0xA020)
|
||||
{
|
||||
return acc_x_low;
|
||||
}
|
||||
else if ((addr & 0xA0F0) == 0xA030)
|
||||
{
|
||||
return acc_x_high;
|
||||
}
|
||||
else if ((addr & 0xA0F0) == 0xA040)
|
||||
{
|
||||
return acc_y_low;
|
||||
}
|
||||
else if ((addr & 0xA0F0) == 0xA050)
|
||||
{
|
||||
return acc_y_high;
|
||||
}
|
||||
else if ((addr & 0xA0F0) == 0xA060)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
else if ((addr & 0xA0F0) == 0xA070)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
else if ((addr & 0xA0F0) == 0xA080)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue