GBHawk: MBC3

This commit is contained in:
alyosha-tas 2017-11-24 15:44:29 -05:00
parent ffbb1f3399
commit cbd217d479
9 changed files with 261 additions and 22 deletions

View File

@ -68,7 +68,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
case 0x27: INT_OP(DA, A); break; // DAA
case 0x28: JR_COND(FlagZ); break; // JR Z, r8
case 0x29: ADD_16(L, H, L, H); break; // ADD HL, HL
case 0x2A: LD_IND_8_INC(A, L, H); break; // LD A, (HL+)
case 0x2A: LD_IND_8_INC_HL(A, L, H); break; // LD A, (HL+)
case 0x2B: DEC_16(L, H); break; // DEC HL
case 0x2C: INT_OP(INC8, L); break; // INC L
case 0x2D: INT_OP(DEC8, L); break; // DEC L
@ -84,7 +84,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
case 0x37: INT_OP(SCF, A); break; // SCF
case 0x38: JR_COND(FlagC); break; // JR C, r8
case 0x39: ADD_16(L, H, SPl, SPh); break; // ADD HL, SP
case 0x3A: LD_IND_8_DEC(A, L, H); break; // LD A, (HL-)
case 0x3A: LD_IND_8_DEC_HL(A, L, H); break; // LD A, (HL-)
case 0x3B: DEC_16(SPl, SPh); break; // DEC SP
case 0x3C: INT_OP(INC8, A); break; // INC A
case 0x3D: INT_OP(DEC8, A); break; // DEC A

View File

@ -19,10 +19,10 @@ namespace BizHawk.Emulation.Common.Components.LR35902
private void INC_16(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{INC16, src_l, src_h,
IDLE,
{IDLE,
IDLE,
IDLE,
INC16, src_l, src_h,
IDLE,
IDLE,
IDLE,
@ -33,10 +33,10 @@ namespace BizHawk.Emulation.Common.Components.LR35902
private void DEC_16(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{DEC16, src_l, src_h,
IDLE,
{IDLE,
IDLE,
IDLE,
DEC16, src_l, src_h,
IDLE,
IDLE,
IDLE,
@ -46,10 +46,10 @@ namespace BizHawk.Emulation.Common.Components.LR35902
private void ADD_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{ADD16, dest_l, dest_h, src_l, src_h,
IDLE,
{IDLE,
IDLE,
IDLE,
ADD16, dest_l, dest_h, src_l, src_h,
IDLE,
IDLE,
IDLE,

View File

@ -169,7 +169,20 @@
OP };
}
private void LD_IND_8_DEC(ushort dest, ushort src_l, ushort src_h)
private void LD_IND_8_INC_HL(ushort dest, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, dest, src_l, src_h,
IDLE,
INC16, src_l, src_h,
IDLE,
OP };
}
private void LD_IND_8_DEC_HL(ushort dest, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,

View File

@ -116,6 +116,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
ppu.tick();
serialport.serial_transfer_tick();
if (Use_RTC) { mapper.RTC_Tick(); }
cpu.ExecuteOne(ref REG_FF0F, REG_FFFF);
timer.tick_2();

View File

@ -75,6 +75,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
}
[DisplayName("RTC Initial Time")]
[Description("Set the initial RTC time in terms of elapsed seconds. Only used when RealTimeRTC is false.")]
[DefaultValue(0)]
public int RTCInitialTime
{
get { return _RTCInitialTime; }
set { _RTCInitialTime = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); }
}
[JsonIgnore]
private int _RTCInitialTime;
public GBSyncSettings Clone()
{
return (GBSyncSettings)MemberwiseClone();

View File

@ -83,6 +83,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
ser.Sync("BG_map_1", ref BG_map_1, false);
ser.Sync("BG_map_2", ref BG_map_2, false);
ser.Sync("OAM", ref OAM, false);
ser.Sync("Use_RTC", ref Use_RTC);
// probably a better way to do this
if (cart_RAM != null)
{

View File

@ -49,6 +49,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
private int _frame = 0;
public bool Use_RTC;
public MapperBase mapper;
private readonly ITraceable _tracer;
@ -262,6 +264,34 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
mapper.Core = this;
mapper.Initialize();
// Extra RTC initialization for mbc3
if (mppr == "MBC3")
{
Use_RTC = true;
int days = (int)Math.Floor(_syncSettings.RTCInitialTime / 86400.0);
int days_upper = ((days & 0x100) >> 8) | ((days & 0x200) >> 2);
mapper.RTC_Get((byte)days_upper, 4);
mapper.RTC_Get((byte)(days & 0xFF), 3);
int remaining = _syncSettings.RTCInitialTime - (days * 86400);
int hours = (int)Math.Floor(remaining / 3600.0);
mapper.RTC_Get((byte)(hours & 0xFF), 2);
remaining = remaining - (hours * 3600);
int minutes = (int)Math.Floor(remaining / 60.0);
mapper.RTC_Get((byte)(minutes & 0xFF), 1);
remaining = remaining - (minutes * 60);
mapper.RTC_Get((byte)(remaining & 0xFF), 0);
}
}
}
}

View File

@ -36,5 +36,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public virtual void Initialize()
{
}
public virtual void RTC_Tick()
{
}
public virtual void RTC_Get(byte value, int index)
{
}
}
}

View File

@ -4,29 +4,94 @@ using System;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{
// Default mapper with no bank switching
// MBC3 mapper with Real Time Clock
public class MapperMBC3 : MapperBase
{
public int ROM_bank;
public int RAM_bank;
public bool RAM_enable;
public bool sel_mode;
public int ROM_mask;
public int RAM_mask;
public byte[] RTC_regs = new byte[5];
public byte[] RTC_regs_latch = new byte[5];
public bool RTC_regs_latch_wr;
public int RTC_timer;
public int RTC_low_clock;
public override void Initialize()
{
// nothing to initialize
ROM_bank = 1;
RAM_bank = 0;
RAM_enable = false;
sel_mode = 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; }
RAM_mask = 0;
if (Core.cart_RAM != null)
{
RAM_mask = Core.cart_RAM.Length / 0x2000 - 1;
if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; }
}
RTC_regs[0] = 0;
RTC_regs[1] = 0;
RTC_regs[2] = 0;
RTC_regs[3] = 0;
RTC_regs[4] = 0;
RTC_regs_latch_wr = true;
}
public override byte ReadMemory(ushort addr)
{
if (addr < 0x8000)
if (addr < 0x4000)
{
return Core._rom[addr];
}
else
{
if (Core.cart_RAM != null)
// lowest bank is fixed, but is still effected by mode
if (sel_mode)
{
return Core.cart_RAM[addr - 0xA000];
return Core._rom[(ROM_bank & 0x60) * 0x4000 + addr];
}
else
{
return 0;
return Core._rom[addr];
}
}
else if (addr < 0x8000)
{
return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000];
}
else
{
if (RAM_enable)
{
if ((Core.cart_RAM != null) && (RAM_bank < 3))
{
if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)
{
return Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000];
}
else
{
return 0xFF;
}
}
if ((RAM_bank >= 8) && (RAM_bank < 0xC))
{
return RTC_regs_latch[RAM_bank - 8];
}
else
{
return 0xFF;
}
}
else
{
return 0xFF;
}
}
}
@ -40,13 +105,52 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{
if (addr < 0x8000)
{
// no mapping hardware available
if (addr < 0x2000)
{
RAM_enable = ((value & 0xA) == 0xA) ? true : false;
}
else if (addr < 0x4000)
{
value &= 0x3F;
// writing zero gets translated to 1
if (value == 0) { value = 1; }
ROM_bank = value;
ROM_bank &= ROM_mask;
}
else if (addr < 0x6000)
{
RAM_bank = value;
}
else
{
if (!RTC_regs_latch_wr && ((value & 1) == 1))
{
for (int i = 0; i < 5; i++)
{
RTC_regs_latch[i] = RTC_regs[i];
}
}
RTC_regs_latch_wr = (value & 1) > 0;
}
}
else
{
if (Core.cart_RAM != null)
if (RAM_enable)
{
Core.cart_RAM[addr - 0xA000] = value;
if ((Core.cart_RAM != null) && (RAM_bank <= 3))
{
if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)
{
Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value;
}
}
else if ((RAM_bank >= 8) && (RAM_bank < 0xC))
{
RTC_regs[RAM_bank - 8] = value;
}
}
}
}
@ -55,5 +159,71 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{
WriteMemory(addr, value);
}
public override void RTC_Get(byte value, int index)
{
RTC_regs[index] = value;
}
public override void RTC_Tick()
{
RTC_timer++;
if (RTC_timer == 128)
{
RTC_timer = 0;
RTC_low_clock++;
if (RTC_low_clock == 32768)
{
RTC_low_clock = 0;
RTC_regs[0]++;
if (RTC_regs[0] > 59)
{
RTC_regs[0] = 0;
RTC_regs[1]++;
if (RTC_regs[1] > 59)
{
RTC_regs[2]++;
if (RTC_regs[2] > 23)
{
RTC_regs[2] = 0;
if (RTC_regs[3] < 0xFF)
{
RTC_regs[3]++;
}
else
{
RTC_regs[3] = 0;
if ((RTC_regs[4] & 1) == 0)
{
RTC_regs[4] |= 1;
}
else
{
RTC_regs[4] &= 0xFE;
RTC_regs[4] |= 0x80;
}
}
}
}
}
}
}
}
public override void SyncState(Serializer ser)
{
ser.Sync("ROM_Bank", ref ROM_bank);
ser.Sync("ROM_Mask", ref ROM_mask);
ser.Sync("RAM_Bank", ref RAM_bank);
ser.Sync("RAM_Mask", ref RAM_mask);
ser.Sync("RAM_enable", ref RAM_enable);
ser.Sync("sel_mode", ref sel_mode);
}
}
}