GBHawk: finish intergration functions
This commit is contained in:
parent
8274c2c115
commit
73afca9c67
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -417,7 +417,7 @@ namespace GBHawk
|
|||
{
|
||||
// Read Input
|
||||
case 0xFF00:
|
||||
_islag = false;
|
||||
lagged = false;
|
||||
ret = input_register;
|
||||
break;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue