GBHawk: TAMA5 initial work

This commit is contained in:
alyosha-tas 2019-10-18 17:35:59 -04:00
parent 854315d96d
commit 9da739eaeb
2 changed files with 248 additions and 27 deletions
BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk

View File

@ -342,7 +342,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
case 0x20: mapper = new MapperMBC6(); mppr = "MBC6"; break;
case 0x22: mapper = new MapperMBC7(); mppr = "MBC7"; has_bat = true; break;
case 0xFC: mapper = new MapperCamera(); mppr = "CAM"; break;
case 0xFD: mapper = new MapperTAMA5(); mppr = "TAMA5"; break;
case 0xFD: mapper = new MapperTAMA5(); mppr = "TAMA5"; has_bat = true; break;
case 0xFE: mapper = new MapperHuC3(); mppr = "HuC3"; break;
case 0xFF: mapper = new MapperHuC1(); mppr = "HuC1"; break;
@ -453,6 +453,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
has_bat = true;
}
// TAMA5 has 0x1000 bytes of RAM, regardless of any header info
if (mppr == "TAMA5")
{
cart_RAM = new byte[0x20];
has_bat = true;
}
mapper.Core = this;
mapper.Initialize();
@ -466,7 +473,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
}
// Extra RTC initialization for mbc3
// Extra RTC initialization for mbc3, HuC3, and TAMA5
if (mppr == "MBC3")
{
Use_MT = true;
@ -521,6 +528,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
mapper.RTC_Get(minutes_upper, 8);
mapper.RTC_Get(remaining & 0xFF, 0);
}
if (mppr == "TAMA5")
{
Use_MT = true;
// currently no date / time input for TAMA5
}
}
}
}

View File

@ -6,49 +6,95 @@ using BizHawk.Emulation.Common.Components.LR35902;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{
// Default mapper with no bank switching
// Tama 5 mapper used in tamagatchi 3
public class MapperTAMA5 : MapperBase
{
public int ROM_bank;
public int RAM_bank;
public int ROM_mask;
public int RAM_mask;
public byte[] RTC_regs = new byte[10];
public int RTC_timer;
public int RTC_low_clock;
public bool halt;
public int RTC_offset;
public int ctrl;
public int RAM_addr_low;
public int RAM_addr_high;
public int RAM_val_low;
public int RAM_val_high;
public byte Chip_return_low;
public byte Chip_return_high;
public override void Initialize()
{
// nothing to initialize
ROM_bank = 0;
RAM_bank = 0;
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;
ctrl = 0;
}
public override byte ReadMemory(ushort addr)
{
if (addr < 0x8000)
if (addr < 0x4000)
{
return Core._rom[addr];
}
else if (addr < 0x8000)
{
return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000];
}
else
{
if (Core.cart_RAM != null)
switch (ctrl)
{
return Core.cart_RAM[addr - 0xA000];
}
else
{
return 0;
case 0xA:
// The game won't proceed unless this value (anded with 3) is 1
// see bank 0: 0x1A7D to 0x1A89
return 1;
case 0xC:
//Console.WriteLine("read low: " + Chip_return_low);
return Chip_return_low;
case 0xD:
//Console.WriteLine("read high: " + Chip_return_high);
return Chip_return_high;
}
return 0x0;
}
}
public override void MapCDL(ushort addr, LR35902.eCDLogMemFlags flags)
{
if (addr < 0x8000)
if (addr < 0x4000)
{
SetCDLROM(flags, addr);
}
else if (addr < 0x8000)
{
SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000);
}
else
{
if (Core.cart_RAM != null)
{
SetCDLRAM(flags, addr - 0xA000);
}
else
{
return;
}
}
}
@ -59,22 +105,183 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public override void WriteMemory(ushort addr, byte value)
{
if (addr < 0x8000)
if (addr == 0xA000)
{
// no mapping hardware available
}
else
{
if (Core.cart_RAM != null)
switch (ctrl)
{
Core.cart_RAM[addr - 0xA000] = value;
case 0:
ROM_bank &= 0xF0;
ROM_bank |= (value & 0xF);
break;
case 1:
ROM_bank &= 0x0F;
ROM_bank |= ((value & 0x1) << 4);
break;
case 4:
RAM_val_low = (value & 0xF);
break;
case 5:
RAM_val_high = (value & 0xF);
//Core.cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] = (byte)((RAM_val_high << 4) | RAM_val_low);
break;
case 6:
RAM_addr_high = (value & 1);
switch ((value & 0xE) >> 1)
{
case 0:
// write to RAM
Core.cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] = (byte)((RAM_val_high << 4) | RAM_val_low);
break;
case 1:
// read from RAM
Chip_return_high = (byte)(Core.cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] >> 4);
Chip_return_low = (byte)(Core.cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] & 0xF);
break;
case 2:
// read from RTC registers
if (RAM_addr_low == 3)
{
Chip_return_high = RTC_regs[2];
Chip_return_low = RTC_regs[1];
}
else if (RAM_addr_low == 6)
{
Chip_return_high = RTC_regs[4];
Chip_return_low = RTC_regs[3];
}
else
{
Chip_return_high = 1;
Chip_return_low = 1;
}
break;
case 3:
// write to RTC registers (probably wrong, not well tested)
if (RAM_addr_low == 3)
{
RTC_regs[2] = (byte)(RAM_val_high & 0xF);
RTC_regs[1] = (byte)(RAM_val_low & 0xF);
}
else if (RAM_addr_low == 6)
{
RTC_regs[4] = (byte)(RAM_val_high & 0xF);
RTC_regs[3] = (byte)(RAM_val_low & 0xF);
}
else
{
}
break;
case 4:
// read from seconds register (time changes are checked when it rolls over)
Chip_return_low = (byte)(RTC_regs[0] & 0xF);
break;
}
//Console.WriteLine("CTRL: " + (value >> 1) + " RAM_high:" + RAM_addr_high + " RAM_low: " + RAM_addr_low + " val: " + (byte)((RAM_val_high << 4) | RAM_val_low) + " Cpu: " + Core.cpu.TotalExecutedCycles);
break;
case 7:
RAM_addr_low = (value & 0xF);
//Console.WriteLine(" RAM_low:" + RAM_addr_low + " Cpu: " + Core.cpu.TotalExecutedCycles);
break;
}
}
else if (addr == 0xA001)
{
ctrl = value;
}
}
public override void PokeMemory(ushort addr, byte value)
{
WriteMemory(addr, value);
}
public override void RTC_Get(int value, int index)
{
if (index < 10)
{
RTC_regs[index] = (byte)value;
}
else
{
RTC_offset = value;
}
}
public override void Mapper_Tick()
{
if (!halt)
{
RTC_timer++;
if (RTC_timer == 128)
{
RTC_timer = 0;
RTC_low_clock++;
if (RTC_low_clock == 32768)
{
RTC_low_clock = 0;
RTC_timer = RTC_offset;
RTC_regs[0]++;
if (RTC_regs[0] > 59)
{
RTC_regs[0] = 0;
RTC_regs[1]++;
// 1's digit of minutes
if (RTC_regs[1] > 9)
{
RTC_regs[1] = 0;
RTC_regs[2]++;
// 10's digit of minutes
if (RTC_regs[2] > 5)
{
RTC_regs[2] = 0;
RTC_regs[3]++;
// 1's digit of hours
if (RTC_regs[3] > 9)
{
RTC_regs[3] = 0;
RTC_regs[4]++;
// 10's digit of hours
if (RTC_regs[4] > 2)
{
RTC_regs[4] = 0;
RTC_regs[5]++;
}
}
}
}
}
}
}
}
}
public override void SyncState(Serializer ser)
{
ser.Sync(nameof(ROM_bank), ref ROM_bank);
ser.Sync(nameof(ROM_mask), ref ROM_mask);
ser.Sync(nameof(RAM_bank), ref RAM_bank);
ser.Sync(nameof(RAM_mask), ref RAM_mask);
ser.Sync(nameof(halt), ref halt);
ser.Sync(nameof(RTC_regs), ref RTC_regs, false);
ser.Sync(nameof(RTC_timer), ref RTC_timer);
ser.Sync(nameof(RTC_low_clock), ref RTC_low_clock);
ser.Sync(nameof(RTC_offset), ref RTC_offset);
ser.Sync(nameof(ctrl), ref ctrl);
ser.Sync(nameof(RAM_addr_low), ref RAM_addr_low);
ser.Sync(nameof(RAM_addr_high), ref RAM_addr_high);
ser.Sync(nameof(RAM_val_low), ref RAM_val_low);
ser.Sync(nameof(RAM_val_high), ref RAM_val_high);
ser.Sync(nameof(Chip_return_low), ref Chip_return_low);
ser.Sync(nameof(Chip_return_high), ref Chip_return_high);
}
}
}