GBHAwk more work:
-Add basic serial port support -Fix Mortal Kombat -Add controller IRQs -Fix contols and Bomberman
This commit is contained in:
parent
63f8fc0d90
commit
f494b58f3b
|
@ -582,6 +582,7 @@
|
|||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\VBARegisterHelper.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\Audio.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\SerialPort.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.IDebuggable.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.IEmulator.cs" />
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
public bool in_vblank_old;
|
||||
public bool in_vblank;
|
||||
public bool vblank_rise;
|
||||
bool contr_check_once;
|
||||
|
||||
public void FrameAdvance(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
|
@ -56,16 +57,54 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
// gameboy frames can be variable lengths
|
||||
// we want to end a frame when VBlank turns from false to true
|
||||
int ticker = 0;
|
||||
contr_check_once = true;
|
||||
while (!vblank_rise && (ticker < 100000))
|
||||
{
|
||||
audio.tick();
|
||||
timer.tick_1();
|
||||
ppu.tick();
|
||||
serialport.serial_transfer_tick();
|
||||
|
||||
cpu.ExecuteOne(ref REG_FF0F, REG_FFFF);
|
||||
|
||||
timer.tick_2();
|
||||
|
||||
// check for controller interrupts somewhere around the middle of the frame
|
||||
if ((cpu.LY == 50) && contr_check_once)
|
||||
{
|
||||
byte contr_prev = input_register;
|
||||
|
||||
input_register &= 0xF0;
|
||||
if ((input_register & 0x30) == 0x20)
|
||||
{
|
||||
input_register |= (byte)(controller_state & 0xF);
|
||||
}
|
||||
else if ((input_register & 0x30) == 0x10)
|
||||
{
|
||||
input_register |= (byte)((controller_state & 0xF0) >> 4);
|
||||
}
|
||||
else if ((input_register & 0x30) == 0x00)
|
||||
{
|
||||
// if both polls are set, then a bit is zero if either or both pins are zero
|
||||
byte temp = (byte)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4));
|
||||
input_register |= temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
input_register |= 0xF;
|
||||
}
|
||||
|
||||
// check for interrupts
|
||||
if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) ||
|
||||
((contr_prev & 4) > 0) && ((input_register & 4) == 0) ||
|
||||
((contr_prev & 2) > 0) && ((input_register & 2) == 0) ||
|
||||
((contr_prev & 2) > 0) && ((input_register & 1) == 0))
|
||||
{
|
||||
if (REG_FFFF.Bit(4)) { cpu.FlagI = true; }
|
||||
REG_FF0F |= 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (in_vblank && !in_vblank_old)
|
||||
{
|
||||
|
@ -98,17 +137,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
controller_state_old = controller_state;
|
||||
}
|
||||
|
||||
public void serial_transfer()
|
||||
{
|
||||
if (serial_control.Bit(7) && !serial_start_old)
|
||||
{
|
||||
serial_start_old = true;
|
||||
|
||||
// transfer out on byte of data
|
||||
// needs to be modelled
|
||||
}
|
||||
}
|
||||
|
||||
public int Frame => _frame;
|
||||
|
||||
public string SystemId => "GB";
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
mapper.SyncState(ser);
|
||||
timer.SyncState(ser);
|
||||
ppu.SyncState(ser);
|
||||
serialport.SyncState(ser);
|
||||
audio.SyncState(ser);
|
||||
|
||||
ser.BeginSection("Gameboy");
|
||||
|
@ -68,11 +69,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
ser.Sync("GB_bios_register", ref GB_bios_register);
|
||||
ser.Sync("input_register", ref input_register);
|
||||
|
||||
ser.Sync("serial_control", ref serial_control);
|
||||
ser.Sync("serial_data_out", ref serial_data_out);
|
||||
ser.Sync("serial_data_in", ref serial_data_in);
|
||||
ser.Sync("serial_start_old", ref serial_start_old);
|
||||
|
||||
ser.Sync("REG_FFFF", ref REG_FFFF);
|
||||
ser.Sync("REG_FF0F", ref REG_FF0F);
|
||||
ser.Sync("enable_VBL", ref enable_VBL);
|
||||
|
|
|
@ -21,11 +21,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
public byte input_register;
|
||||
|
||||
public byte serial_control;
|
||||
public byte serial_data_out;
|
||||
public byte serial_data_in;
|
||||
public bool serial_start_old;
|
||||
|
||||
// The unused bits in this register are still read/writable
|
||||
public byte REG_FFFF;
|
||||
// The unused bits in this register (interrupt flags) are always set
|
||||
|
@ -62,6 +57,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
public PPU ppu;
|
||||
public Timer timer;
|
||||
public Audio audio;
|
||||
public SerialPort serialport;
|
||||
|
||||
[CoreConstructor("GB")]
|
||||
public GBHawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings)
|
||||
|
@ -79,6 +75,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
ppu = new PPU();
|
||||
timer = new Timer();
|
||||
audio = new Audio();
|
||||
serialport = new SerialPort();
|
||||
|
||||
CoreComm = comm;
|
||||
|
||||
|
@ -109,6 +106,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
timer.Core = this;
|
||||
audio.Core = this;
|
||||
ppu.Core = this;
|
||||
serialport.Core = this;
|
||||
|
||||
ser.Register<IVideoProvider>(this);
|
||||
ser.Register<ISoundProvider>(audio);
|
||||
|
@ -138,6 +136,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
timer.Reset();
|
||||
ppu.Reset();
|
||||
audio.Reset();
|
||||
serialport.Reset();
|
||||
|
||||
cpu.SetCallbacks(ReadMemory, ReadMemory, ReadMemory, WriteMemory);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
input_register |= (byte)((controller_state & 0xF0) >> 4);
|
||||
}
|
||||
else if ((input_register & 0x30) == 0x30)
|
||||
else if ((input_register & 0x30) == 0x00)
|
||||
{
|
||||
// if both polls are set, then a bit is zero if either or both pins are zero
|
||||
byte temp = (byte)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4));
|
||||
|
@ -41,12 +41,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
// Serial data port
|
||||
case 0xFF01:
|
||||
ret = serial_data_in;
|
||||
ret = serialport.ReadReg(addr);
|
||||
break;
|
||||
|
||||
// Serial port control
|
||||
case 0xFF02:
|
||||
ret = serial_control;
|
||||
ret = serialport.ReadReg(addr);
|
||||
break;
|
||||
|
||||
// Timer Registers
|
||||
|
@ -148,13 +148,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
// Serial data port
|
||||
case 0xFF01:
|
||||
serial_data_out = value;
|
||||
serial_data_in = serial_data_out;
|
||||
serialport.WriteReg(addr, value);
|
||||
break;
|
||||
|
||||
// Serial port control
|
||||
case 0xFF02:
|
||||
serial_control = (byte)(0x7E | (value & 0x81)); // middle six bits always 1
|
||||
serialport.WriteReg(addr, value);
|
||||
break;
|
||||
|
||||
// Timer Registers
|
||||
|
@ -277,7 +276,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
public void Register_Reset()
|
||||
{
|
||||
input_register = 0xCF; // not reading any input
|
||||
serial_control = 0x7E;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||
{
|
||||
public class SerialPort
|
||||
{
|
||||
public GBHawk Core { get; set; }
|
||||
|
||||
public byte serial_control;
|
||||
public byte serial_data;
|
||||
public bool serial_start;
|
||||
public int serial_clock;
|
||||
public int serial_bits;
|
||||
public bool clk_internal;
|
||||
public int clk_rate;
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
{
|
||||
byte ret = 0;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0xFF01:
|
||||
return serial_data;
|
||||
case 0xFF02:
|
||||
return serial_control;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void WriteReg(int addr, byte value)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0xFF01:
|
||||
serial_data = value;
|
||||
break;
|
||||
|
||||
case 0xFF02:
|
||||
if (((value & 0x80) > 0) && !serial_start)
|
||||
{
|
||||
serial_start = true;
|
||||
serial_bits = 8;
|
||||
if ((value & 1) > 0)
|
||||
{
|
||||
clk_internal = true;
|
||||
clk_rate = 512;
|
||||
serial_clock = clk_rate;
|
||||
}
|
||||
else
|
||||
{
|
||||
clk_internal = false;
|
||||
clk_rate = get_external_clock();
|
||||
serial_clock = clk_rate;
|
||||
}
|
||||
}
|
||||
|
||||
serial_control = (byte)(0x7E | (value & 0x81)); // middle six bits always 1
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void serial_transfer_tick()
|
||||
{
|
||||
if (serial_start)
|
||||
{
|
||||
serial_clock--;
|
||||
if (serial_clock == 0)
|
||||
{
|
||||
if (serial_bits > 0)
|
||||
{
|
||||
send_external_bit((byte)(serial_data & 0x80));
|
||||
|
||||
byte temp = get_external_bit();
|
||||
serial_data = (byte)((serial_data << 1) | temp);
|
||||
|
||||
serial_bits--;
|
||||
if (serial_bits == 0)
|
||||
{
|
||||
serial_control &= 0x7F;
|
||||
serial_start = false;
|
||||
|
||||
if (Core.REG_FFFF.Bit(3)) { Core.cpu.FlagI = true; }
|
||||
Core.REG_FF0F |= 0x08;
|
||||
}
|
||||
else
|
||||
{
|
||||
serial_clock = clk_rate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// call this function to get the clock rate of a connected device
|
||||
// internal rate is 512
|
||||
public int get_external_clock()
|
||||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
// call this function to get the next bit from the connected device
|
||||
// no device connected returns 0xFF
|
||||
public byte get_external_bit()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void send_external_bit(byte bit_send)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
serial_control = 0x7E;
|
||||
serial_start = false;
|
||||
serial_data = 0xFF;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("serial_control", ref serial_control);
|
||||
ser.Sync("serial_data", ref serial_data);
|
||||
ser.Sync("serial_start", ref serial_start);
|
||||
ser.Sync("serial_clock", ref serial_clock);
|
||||
ser.Sync("serial_bits", ref serial_bits);
|
||||
ser.Sync("clk_internal", ref clk_internal);
|
||||
ser.Sync("clk_rate", ref clk_rate);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue