GBHawk: finish intergration functions

This commit is contained in:
alyosha-tas 2020-03-29 10:10:13 -04:00
parent 8274c2c115
commit 73afca9c67
6 changed files with 211 additions and 21 deletions

View File

@ -42,6 +42,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int GB_load(IntPtr core, byte[] romdata_1, uint length_1, char[] MD5, uint RTC_init, uint RTC_offset);
/// <summary>
/// Reset.
/// </summary>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GB_Reset(IntPtr core);
/// <summary>
/// Advance a frame and send controller data.
/// </summary>
@ -52,7 +58,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
/// <param name="sound">Mapper number to load core with</param>
/// <returns>0 on success, negative value on failure.</returns>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool GB_frame_advance(IntPtr core, byte ctrl1, byte ctrl2, byte[] kbrows, bool render, bool sound);
public static extern bool GB_frame_advance(IntPtr core, byte ctrl1, uint accx, uint accy, bool render, bool sound);
/// <summary>
/// do a singlt step in the core
/// </summary>
/// <param name="core">opaque state pointer</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GB_do_single_step(IntPtr core);
/// <summary>
/// Get Video data

View File

@ -65,6 +65,8 @@ namespace GBHawk
// initialize the proper mapper
Setup_Mapper(MD5, RTC_initial, RTC_offset);
MemMap.mapper_pntr = &mapper[0];
// set up pointers
MemMap.cpu_pntr = &cpu;
MemMap.psg_pntr = &psg;
@ -82,7 +84,7 @@ namespace GBHawk
MemMap.ppu_pntr->VRAM = &MemMap.VRAM[0];
MemMap.ppu_pntr->VRAM_Bank = &MemMap.VRAM_Bank;
MemMap.ppu_pntr->cpu_halted = &cpu.halted;
MemMap.ppu_pntr->_vidbuffer = &MemMap._vidbuffer[0];
MemMap.ppu_pntr->_vidbuffer = &MemMap.vidbuffer[0];
MemMap.ppu_pntr->color_palette = &MemMap.color_palette[0];
MemMap.ppu_pntr->HDMA_transfer = &MemMap.HDMA_transfer;
MemMap.ppu_pntr->GBC_compat = &MemMap.GBC_compat;
@ -128,22 +130,193 @@ namespace GBHawk
cpu.Reset();
}
bool FrameAdvance(uint8_t controller_1, uint8_t controller_2, uint8_t* kb_rows_ptr, bool render, bool rendersound)
bool FrameAdvance(uint8_t new_controller_1, uint32_t new_accx, uint32_t new_accy, bool render, bool rendersound)
{
MemMap.controller_byte_1 = controller_1;
MemMap.controller_byte_2 = controller_2;
MemMap.kb_rows = kb_rows_ptr;
MemMap.lagged = true;
for (int i = 0; i < 70224; i++)
{
// These things do not change speed in GBC double spped mode
psg.tick();
ppu->tick();
if (MemMap.Use_MT) { mapper->Mapper_Tick(); }
uint32_t scanlinesPerFrame = 262;
if (!MemMap.HDMA_transfer)
{
// These things all tick twice as fast in GBC double speed mode
ppu->DMA_tick();
timer.tick_1();
serialport.serial_transfer_tick();
cpu.ExecuteOne(&MemMap.REG_FF0F, MemMap.REG_FFFF);
timer.tick_2();
if (MemMap.double_speed)
{
ppu->DMA_tick();
timer.tick_1();
serialport.serial_transfer_tick();
cpu.ExecuteOne(&MemMap.REG_FF0F, MemMap.REG_FFFF);
timer.tick_2();
}
}
else
{
timer.tick_1();
timer.tick_2();
cpu.TotalExecutedCycles++;
if (MemMap.double_speed)
{
timer.tick_1();
timer.tick_2();
cpu.TotalExecutedCycles++;
}
}
if (MemMap.in_vblank && !MemMap.in_vblank_old)
{
MemMap.lagged = false;
// update the controller state on VBlank
MemMap.controller_state = new_controller_1;
MemMap.Acc_X_state = new_accx;
MemMap.Acc_Y_state = new_accy;
// check if controller state caused interrupt
do_controller_check();
// send the image on VBlank
SendVideoBuffer();
}
MemMap.REG_FF0F_OLD = MemMap.REG_FF0F;
MemMap.in_vblank_old = MemMap.in_vblank;
}
// turn off the screen so the image doesnt persist
// but don't turn off blank_frame yet, it still needs to be true until the next VBL
// this doesn't run for GBC, some games, ex MIB the series 2, rely on the screens persistence while off to make video look smooth.
// But some GB gams, ex Battletoads, turn off the screen for a long time from the middle of the frame, so need to be cleared.
if (ppu->clear_screen)
{
for (int j = 0; j < (160 * 144); j++) { MemMap.frame_buffer[j] = (int)MemMap.color_palette[0]; }
ppu->clear_screen = false;
}
return MemMap.lagged;
}
void do_single_step()
{
// These things do not change speed in GBC double spped mode
psg.tick();
ppu->tick();
if (MemMap.Use_MT) { mapper->Mapper_Tick(); }
if (!MemMap.HDMA_transfer)
{
// These things all tick twice as fast in GBC double speed mode
ppu->DMA_tick();
timer.tick_1();
serialport.serial_transfer_tick();
cpu.ExecuteOne(&MemMap.REG_FF0F, MemMap.REG_FFFF);
timer.tick_2();
if (MemMap.double_speed)
{
ppu->DMA_tick();
timer.tick_1();
serialport.serial_transfer_tick();
cpu.ExecuteOne(&MemMap.REG_FF0F, MemMap.REG_FFFF);
timer.tick_2();
}
}
else
{
timer.tick_1();
timer.tick_2();
cpu.TotalExecutedCycles++;
if (MemMap.double_speed)
{
timer.tick_1();
timer.tick_2();
cpu.TotalExecutedCycles++;
}
}
if (MemMap.in_vblank && !MemMap.in_vblank_old)
{
MemMap.vblank_rise = true;
}
MemMap.in_vblank_old = MemMap.in_vblank;
MemMap.REG_FF0F_OLD = MemMap.REG_FF0F;
}
void do_controller_check()
{
// check if new input changed the input register and triggered IRQ
uint8_t contr_prev = MemMap.input_register;
MemMap.input_register &= 0xF0;
if ((MemMap.input_register & 0x30) == 0x20)
{
MemMap.input_register |= (uint8_t)(MemMap.controller_state & 0xF);
}
else if ((MemMap.input_register & 0x30) == 0x10)
{
MemMap.input_register |= (uint8_t)((MemMap.controller_state & 0xF0) >> 4);
}
else if ((MemMap.input_register & 0x30) == 0x00)
{
// if both polls are set, then a bit is zero if either or both pins are zero
uint8_t temp = (uint8_t)((MemMap.controller_state & 0xF) & ((MemMap.controller_state & 0xF0) >> 4));
MemMap.input_register |= temp;
}
else
{
MemMap.input_register |= 0xF;
}
// check for interrupts
if (((contr_prev & 8) > 0) && ((MemMap.input_register & 8) == 0) ||
((contr_prev & 4) > 0) && ((MemMap.input_register & 4) == 0) ||
((contr_prev & 2) > 0) && ((MemMap.input_register & 2) == 0) ||
((contr_prev & 1) > 0) && ((MemMap.input_register & 1) == 0))
{
if ((MemMap.REG_FFFF & 0x10) > 0) { cpu.FlagI = true; }
MemMap.REG_FF0F |= 0x10;
}
}
void SendVideoBuffer()
{
if (MemMap.GBC_compat)
{
if (!ppu->blank_frame)
{
for (int j = 0; j < (160 * 144); j++) { MemMap.frame_buffer[j] = MemMap.vidbuffer[j]; }
}
ppu->blank_frame = false;
}
else
{
if (ppu->blank_frame)
{
for (int i = 0; i < (160 * 144); i++)
{
MemMap.vidbuffer[i] = (int)MemMap.color_palette[0];
}
}
for (int j = 0; j < (160 * 144); j++) { MemMap.frame_buffer[j] = MemMap.vidbuffer[j]; }
ppu->blank_frame = false;
}
}
void GetVideo(uint32_t* dest)
{
uint32_t* src = MemMap.FrameBuffer;
uint32_t* src = MemMap.frame_buffer;
uint32_t* dst = dest;
std::memcpy(dst, src, sizeof uint32_t * 256 * 192);

View File

@ -45,10 +45,17 @@ GBHawk_EXPORT void GB_Reset(GBCore* p)
{
p->Reset();
}
// advance a frame
GBHawk_EXPORT bool GB_frame_advance(GBCore* p, uint8_t ctrl1, uint8_t ctrl2, uint8_t* kbrows, bool render, bool sound)
GBHawk_EXPORT bool GB_frame_advance(GBCore* p, uint8_t new_ctrl1, uint32_t new_accx, uint32_t new_accy, bool render, bool sound)
{
return p->FrameAdvance(ctrl1, ctrl2, kbrows, render, sound);
return p->FrameAdvance(new_ctrl1, new_accx, new_accy, render, sound);
}
// advance a single step
GBHawk_EXPORT void GB_do_single_step(GBCore* p)
{
p->do_single_step();
}
// send video data to external video provider

View File

@ -81,6 +81,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>..\..\..\output\dll</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>

View File

@ -417,7 +417,7 @@ namespace GBHawk
{
// Read Input
case 0xFF00:
_islag = false;
lagged = false;
ret = input_register;
break;

View File

@ -46,10 +46,6 @@ namespace GBHawk
uint32_t ROM_Mapper;
uint32_t Cart_RAM_Length;
// controls are not stated
uint8_t controller_byte_1, controller_byte_2;
uint8_t* kb_rows;
// State
bool lagged;
bool is_GBC;
@ -57,9 +53,9 @@ namespace GBHawk
bool speed_switch, double_speed;
bool in_vblank;
bool in_vblank_old;
bool vblank_rise;
bool GB_bios_register;
bool HDMA_transfer;
bool _islag;
bool Use_MT;
bool has_bat;
@ -84,13 +80,12 @@ namespace GBHawk
uint8_t VRAM[0x4000] = {};
uint8_t OAM[0xA0] = {};
uint8_t header[0x50] = {};
uint32_t _vidbuffer[160 * 144] = {};
uint32_t vidbuffer[160 * 144] = {};
uint32_t frame_buffer[160 * 144] = {};
uint32_t color_palette[4] = { 0xFFFFFFFF , 0xFFAAAAAA, 0xFF555555, 0xFF000000 };
const uint8_t GBA_override[13] = { 0xFF, 0x00, 0xCD, 0x03, 0x35, 0xAA, 0x31, 0x90, 0x94, 0x00, 0x00, 0x00, 0x00 };
uint32_t FrameBuffer[160 * 144] = {};
#pragma endregion
#pragma region Functions