GBHawk: MBC7 (Kirby tilt n tumble)
- Implement controller - Fix some GBC bugs - Start eeprom (WIP)
This commit is contained in:
parent
6019073157
commit
a5eca362c8
|
@ -230,7 +230,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
// change the appropriate palette color
|
||||
color_compute_BG();
|
||||
|
||||
if (BG_bytes_inc) { BG_bytes_index++; BG_bytes_index &= 0x3F; }
|
||||
break;
|
||||
case 0xFF6A: // OBPI
|
||||
|
@ -272,11 +271,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
cur_DMA_src = (ushort)((cur_DMA_src + 1) & 0xFFFF);
|
||||
HDMA_length--;
|
||||
}
|
||||
|
||||
HDMA_tick++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// only transfer during mode 0, and only 16 bytes at a time
|
||||
if (((STAT & 3) == 0) && (LY != last_HBL) && HBL_test)
|
||||
if (((STAT & 3) == 0) && (LY != last_HBL) && HBL_test && (LY_inc == 1))
|
||||
{
|
||||
HBL_HDMA_go = true;
|
||||
HBL_test = false;
|
||||
|
@ -306,14 +307,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
HBL_HDMA_count = 0x10;
|
||||
HBL_HDMA_go = false;
|
||||
}
|
||||
|
||||
HDMA_tick++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.HDMA_transfer = false;
|
||||
}
|
||||
}
|
||||
|
||||
HDMA_tick++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -13,6 +13,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
public ControllerDefinition ControllerDefinition => _controllerDeck.Definition;
|
||||
|
||||
public byte controller_state;
|
||||
public ushort Acc_X_state;
|
||||
public ushort Acc_Y_state;
|
||||
public bool in_vblank_old;
|
||||
public bool in_vblank;
|
||||
public bool vblank_rise;
|
||||
|
@ -188,6 +190,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
InputCallbacks.Call();
|
||||
controller_state = _controllerDeck.ReadPort1(controller);
|
||||
|
||||
Acc_X_state = _controllerDeck.ReadAccX1(controller);
|
||||
Acc_Y_state = _controllerDeck.ReadAccY1(controller);
|
||||
}
|
||||
|
||||
public int Frame => _frame;
|
||||
|
|
|
@ -58,20 +58,30 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
public class GBSyncSettings
|
||||
{
|
||||
private string _port1 = GBHawkControllerDeck.DefaultControllerName;
|
||||
[JsonIgnore]
|
||||
public string Port1 = GBHawkControllerDeck.DefaultControllerName;
|
||||
|
||||
public enum ControllerType
|
||||
{
|
||||
Default,
|
||||
Kirby
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string Port1
|
||||
private ControllerType _GBController;
|
||||
|
||||
[DisplayName("Controller")]
|
||||
[Description("Select Controller Type")]
|
||||
[DefaultValue(ControllerType.Default)]
|
||||
public ControllerType GBController
|
||||
{
|
||||
get { return _port1; }
|
||||
get { return _GBController; }
|
||||
set
|
||||
{
|
||||
if (!GBHawkControllerDeck.ValidControllerTypes.ContainsKey(value))
|
||||
{
|
||||
throw new InvalidOperationException("Invalid controller type: " + value);
|
||||
}
|
||||
if (value == ControllerType.Default) { Port1 = GBHawkControllerDeck.DefaultControllerName; }
|
||||
else { Port1 = "Gameboy Controller + Kirby"; }
|
||||
|
||||
_port1 = value;
|
||||
_GBController = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
_controllerDeck.SyncState(ser);
|
||||
|
||||
ser.Sync("controller_state", ref controller_state);
|
||||
ser.Sync("Acc_X_state", ref Acc_X_state);
|
||||
ser.Sync("Acc_Y_state", ref Acc_Y_state);
|
||||
ser.Sync("in_vblank", ref in_vblank);
|
||||
ser.Sync("in_vblank_old", ref in_vblank_old);
|
||||
ser.Sync("vblank_rise", ref vblank_rise);
|
||||
|
|
|
@ -415,10 +415,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
cart_RAM = new byte[0x200];
|
||||
}
|
||||
|
||||
// mbc7 has 256 bytes of RAM, regardless of any header info
|
||||
if (mppr == "MBC7")
|
||||
{
|
||||
cart_RAM = new byte[0x100];
|
||||
has_bat = true;
|
||||
}
|
||||
|
||||
mapper.Core = this;
|
||||
mapper.Initialize();
|
||||
|
||||
if (cart_RAM != null)
|
||||
if (cart_RAM != null && (mppr != "MBC7"))
|
||||
{
|
||||
Console.Write("RAM: "); Console.WriteLine(cart_RAM.Length);
|
||||
|
||||
|
|
|
@ -36,6 +36,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
return Port1.Read(c);
|
||||
}
|
||||
|
||||
public ushort ReadAccX1(IController c)
|
||||
{
|
||||
return Port1.ReadAccX(c);
|
||||
}
|
||||
|
||||
public ushort ReadAccY1(IController c)
|
||||
{
|
||||
return Port1.ReadAccY(c);
|
||||
}
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
|
|
|
@ -119,7 +119,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
.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 } }
|
||||
FloatRanges = { new[] { -45.0f, 0, 45.0f }, new[] { -45.0f, 0, 45.0f } }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -167,14 +167,23 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
return result;
|
||||
}
|
||||
|
||||
// acc x is the result of rotating around body y AFTER rotating around body x
|
||||
// therefore this control scheme gives decreasing sensitivity in X as Y rotation inscreases
|
||||
public ushort ReadAccX(IController c)
|
||||
{
|
||||
return 0;
|
||||
double theta = c.GetFloat(Definition.FloatControls[1]) * Math.PI / 180.0;
|
||||
double phi = c.GetFloat(Definition.FloatControls[0]) * Math.PI / 180.0;
|
||||
|
||||
float temp = (float)(Math.Cos(theta) * Math.Sin(phi));
|
||||
|
||||
return (ushort)(0x81D0 - Math.Floor(temp * 125));
|
||||
}
|
||||
|
||||
// acc y is just the sine of the angle
|
||||
public ushort ReadAccY(IController c)
|
||||
{
|
||||
return 0;
|
||||
float temp = (float)Math.Sin(c.GetFloat(Definition.FloatControls[1]) * Math.PI / 180.0);
|
||||
return (ushort)(0x81D0 - Math.Floor(temp * 125));
|
||||
}
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
|
|
|
@ -361,7 +361,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
// RAM Bank in GBC mode
|
||||
case 0xFF70:
|
||||
//Console.WriteLine(value);
|
||||
if (is_GBC && !ppu.HDMA_active)
|
||||
if (is_GBC)
|
||||
{
|
||||
RAM_Bank = value & 7;
|
||||
if (RAM_Bank == 0) { RAM_Bank = 1; }
|
||||
|
|
|
@ -17,6 +17,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
public byte acc_y_high;
|
||||
public bool is_erased;
|
||||
|
||||
// EEPROM related
|
||||
public bool CS_prev;
|
||||
public bool CLK_prev;
|
||||
public bool DI_prev;
|
||||
public bool DO;
|
||||
public bool instr_read;
|
||||
public bool perf_instr;
|
||||
public int instr_bit_counter;
|
||||
public int instr;
|
||||
public bool WR_EN;
|
||||
public int EE_addr;
|
||||
public int instr_case;
|
||||
public int instr_clocks;
|
||||
public int EE_value;
|
||||
public int countdown;
|
||||
public bool countdown_start;
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
ROM_bank = 1;
|
||||
|
@ -80,6 +98,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
value &= 0xFF;
|
||||
|
||||
//Console.WriteLine(Core.cpu.TotalExecutedCycles);
|
||||
//Console.WriteLine(value);
|
||||
|
||||
ROM_bank &= 0x100;
|
||||
ROM_bank |= value;
|
||||
ROM_bank &= ROM_mask;
|
||||
|
@ -117,32 +138,22 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
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)
|
||||
{
|
||||
|
||||
}
|
||||
ser.Sync("CS_prev", ref CS_prev);
|
||||
ser.Sync("CLK_prev", ref CLK_prev);
|
||||
ser.Sync("DI_prev", ref DI_prev);
|
||||
ser.Sync("DO", ref DO);
|
||||
ser.Sync("instr_read", ref instr_read);
|
||||
ser.Sync("perf_instr", ref perf_instr);
|
||||
ser.Sync("instr_bit_counter", ref instr_bit_counter);
|
||||
ser.Sync("instr", ref instr);
|
||||
ser.Sync("WR_EN", ref WR_EN);
|
||||
ser.Sync("EE_addr", ref EE_addr);
|
||||
ser.Sync("instr_case", ref instr_case);
|
||||
ser.Sync("instr_clocks", ref instr_clocks);
|
||||
ser.Sync("EE_value", ref EE_value);
|
||||
ser.Sync("countdown", ref countdown);
|
||||
ser.Sync("countdown_start", ref countdown_start);
|
||||
}
|
||||
|
||||
public byte Register_Access_Read(ushort addr)
|
||||
|
@ -181,7 +192,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
else if ((addr & 0xA0F0) == 0xA080)
|
||||
{
|
||||
return 0xFF;
|
||||
return (byte)((CS_prev ? 0x80 : 0) |
|
||||
(CLK_prev ? 0x40 : 0) |
|
||||
(DI_prev ? 2 : 0) |
|
||||
(DO ? 1 : 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -189,6 +203,240 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
acc_x_low = (byte)(Core.Acc_X_state & 0xFF);
|
||||
acc_x_high = (byte)((Core.Acc_X_state & 0xFF00) >> 8);
|
||||
acc_y_low = (byte)(Core.Acc_Y_state & 0xFF);
|
||||
acc_y_high = (byte)((Core.Acc_Y_state & 0xFF00) >> 8);
|
||||
}
|
||||
}
|
||||
else if ((addr & 0xA0F0) == 0xA080)
|
||||
{
|
||||
// EEPROM writes
|
||||
EEPROM_write(value);
|
||||
}
|
||||
}
|
||||
|
||||
private void EEPROM_write(byte value)
|
||||
{
|
||||
bool CS = value.Bit(7);
|
||||
bool CLK = value.Bit(6);
|
||||
bool DI = value.Bit(1);
|
||||
|
||||
// if we deselect the chip, complete instructions or countdown and stop
|
||||
if (!CS)
|
||||
{
|
||||
CS_prev = CS;
|
||||
CLK_prev = CLK;
|
||||
DI_prev = DI;
|
||||
|
||||
DO = true;
|
||||
countdown_start = false;
|
||||
}
|
||||
|
||||
if (!instr_read && !perf_instr)
|
||||
{
|
||||
// if we aren't performing an operation or reading an incoming instruction, we are waiting for one
|
||||
// this is signalled by CS and DI both being 1 while CLK goes from 0 to 1
|
||||
if (CLK && !CLK_prev && DI && CS)
|
||||
{
|
||||
instr_read = true;
|
||||
instr_bit_counter = 0;
|
||||
instr = 0;
|
||||
DO = false;
|
||||
Console.Write("Initiating command: ");
|
||||
Console.WriteLine(Core.cpu.TotalExecutedCycles);
|
||||
}
|
||||
}
|
||||
else if (instr_read && CLK && !CLK_prev)
|
||||
{
|
||||
// all instructions are 10 bits long
|
||||
instr = (instr << 1) | ((value & 2) >> 1);
|
||||
|
||||
instr_bit_counter++;
|
||||
if (instr_bit_counter == 10)
|
||||
{
|
||||
instr_read = false;
|
||||
perf_instr = true;
|
||||
instr_clocks = 0;
|
||||
EE_addr = instr & 0x7F;
|
||||
EE_value = 0;
|
||||
|
||||
|
||||
|
||||
switch (instr & 0x300)
|
||||
{
|
||||
case 0x0:
|
||||
switch (instr & 0xC0)
|
||||
{
|
||||
case 0x0: // disable writes
|
||||
instr_case = 0;
|
||||
break;
|
||||
case 0x40: // fill mem with value
|
||||
instr_case = 1;
|
||||
break;
|
||||
case 0x80: // fill mem with FF
|
||||
instr_case = 2;
|
||||
break;
|
||||
case 0xC0: // enable writes
|
||||
instr_case = 3;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x100: // write to address
|
||||
instr_case = 4;
|
||||
break;
|
||||
case 0x200: // read from address
|
||||
instr_case = 5;
|
||||
break;
|
||||
case 0x300: // set address to FF
|
||||
instr_case = 6;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
Console.Write("Selected Command: ");
|
||||
Console.Write(instr_case);
|
||||
Console.Write(" ");
|
||||
Console.WriteLine(Core.cpu.TotalExecutedCycles);
|
||||
}
|
||||
}
|
||||
else if (perf_instr && CLK && !CLK_prev)
|
||||
{
|
||||
switch (instr_case)
|
||||
{
|
||||
case 0:
|
||||
WR_EN = false;
|
||||
instr_case = 7;
|
||||
countdown = 8;
|
||||
break;
|
||||
case 1:
|
||||
if (instr_clocks < 16)
|
||||
{
|
||||
EE_value = (EE_value << 1) | ((value & 2) >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WR_EN)
|
||||
{
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
Core.cart_RAM[i * 2] = (byte)(EE_value & 0xFF);
|
||||
Core.cart_RAM[i * 2 + 1] = (byte)((EE_value & 0xFF00) >> 8);
|
||||
}
|
||||
}
|
||||
instr_case = 7;
|
||||
countdown = 8;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (WR_EN)
|
||||
{
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
Core.cart_RAM[i] = 0xFF;
|
||||
}
|
||||
}
|
||||
instr_case = 7;
|
||||
countdown = 8;
|
||||
break;
|
||||
case 3:
|
||||
WR_EN = true;
|
||||
instr_case = 7;
|
||||
countdown = 8;
|
||||
break;
|
||||
case 4:
|
||||
if (instr_clocks < 16)
|
||||
{
|
||||
EE_value = (EE_value << 1) | ((value & 2) >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WR_EN)
|
||||
{
|
||||
Core.cart_RAM[EE_addr * 2] = (byte)(EE_value & 0xFF);
|
||||
Core.cart_RAM[EE_addr * 2 + 1] = (byte)((EE_value & 0xFF00) >> 8);
|
||||
}
|
||||
instr_case = 7;
|
||||
countdown = 8;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (instr_clocks < 16)
|
||||
{
|
||||
if ((instr_clocks >= 0) && (instr_clocks <= 7))
|
||||
{
|
||||
DO = (Core.cart_RAM[EE_addr * 2 + 1] >> (8 - instr_clocks)) == 1 ? true : false;
|
||||
}
|
||||
else if ((instr_clocks >= 8) && (instr_clocks <= 15))
|
||||
{
|
||||
DO = (Core.cart_RAM[EE_addr * 2] >> (8 - instr_clocks)) == 1 ? true : false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
instr_case = 7;
|
||||
countdown = 8;
|
||||
}
|
||||
|
||||
break;
|
||||
case 6:
|
||||
if (WR_EN)
|
||||
{
|
||||
Core.cart_RAM[EE_addr * 2] = 0xFF;
|
||||
Core.cart_RAM[EE_addr * 2 + 1] = 0xFF;
|
||||
}
|
||||
instr_case = 7;
|
||||
countdown = 8;
|
||||
break;
|
||||
case 7:
|
||||
// completed operations take time, so countdown a bit here.
|
||||
// not cycle accurate for operations like writing to all of the EEPROM, but good enough
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (instr_case == 7)
|
||||
{
|
||||
perf_instr = false;
|
||||
countdown_start = true;
|
||||
}
|
||||
|
||||
instr_clocks++;
|
||||
}
|
||||
else if (countdown_start)
|
||||
{
|
||||
countdown--;
|
||||
if (countdown == 0)
|
||||
{
|
||||
countdown_start = false;
|
||||
DO = true;
|
||||
|
||||
Console.Write("Command Complete: ");
|
||||
Console.WriteLine(Core.cpu.TotalExecutedCycles);
|
||||
}
|
||||
}
|
||||
|
||||
CS_prev = CS;
|
||||
CLK_prev = CLK;
|
||||
DI_prev = DI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue