GBHawk: MBC3
This commit is contained in:
parent
ffbb1f3399
commit
cbd217d479
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue