830 lines
18 KiB
C++
830 lines
18 KiB
C++
/******************************************************************************/
|
|
/* Mednafen Virtual Boy Emulation Module */
|
|
/******************************************************************************/
|
|
/* vb.cpp:
|
|
** Copyright (C) 2010-2017 Mednafen Team
|
|
**
|
|
** This program is free software; you can redistribute it and/or
|
|
** modify it under the terms of the GNU General Public License
|
|
** as published by the Free Software Foundation; either version 2
|
|
** of the License, or (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "vb.h"
|
|
#include "../emulibc/emulibc.h"
|
|
#include "../emulibc/waterboxcore.h"
|
|
#define EXPORT extern "C" ECL_EXPORT
|
|
|
|
namespace MDFN_IEN_VB
|
|
{
|
|
struct NativeSyncSettings
|
|
{
|
|
int InstantReadHack;
|
|
int DisableParallax;
|
|
};
|
|
struct NativeSettings
|
|
{
|
|
int ThreeDeeMode;
|
|
int SwapViews;
|
|
int AnaglyphPreset;
|
|
int AnaglyphCustomLeftColor;
|
|
int AnaglyphCustomRightColor;
|
|
int NonAnaglyphColor;
|
|
int LedOnScale;
|
|
int InterlacePrescale;
|
|
int SideBySideSeparation;
|
|
};
|
|
|
|
static void (*input_callback)();
|
|
static bool lagged;
|
|
|
|
enum
|
|
{
|
|
ANAGLYPH_PRESET_DISABLED = 0,
|
|
ANAGLYPH_PRESET_RED_BLUE,
|
|
ANAGLYPH_PRESET_RED_CYAN,
|
|
ANAGLYPH_PRESET_RED_ELECTRICCYAN,
|
|
ANAGLYPH_PRESET_RED_GREEN,
|
|
ANAGLYPH_PRESET_GREEN_MAGENTA,
|
|
ANAGLYPH_PRESET_YELLOW_BLUE,
|
|
};
|
|
|
|
static const uint32 AnaglyphPreset_Colors[][2] =
|
|
{
|
|
{0, 0},
|
|
{0xFF0000, 0x0000FF},
|
|
{0xFF0000, 0x00B7EB},
|
|
{0xFF0000, 0x00FFFF},
|
|
{0xFF0000, 0x00FF00},
|
|
{0x00FF00, 0xFF00FF},
|
|
{0xFFFF00, 0x0000FF},
|
|
};
|
|
|
|
static uint32 VB3DMode;
|
|
|
|
static uint8 *WRAM = NULL;
|
|
|
|
static uint8 *GPRAM = NULL;
|
|
static const uint32 GPRAM_Mask = 0xFFFF;
|
|
|
|
static uint8 *GPROM = NULL;
|
|
static uint32 GPROM_Mask;
|
|
|
|
V810 *VB_V810 = NULL;
|
|
|
|
VSU *VB_VSU = NULL;
|
|
static uint32 VSU_CycleFix;
|
|
|
|
static uint8 WCR;
|
|
|
|
static int32 next_vip_ts, next_timer_ts, next_input_ts;
|
|
|
|
static uint32 IRQ_Asserted;
|
|
|
|
static INLINE void RecalcIntLevel(void)
|
|
{
|
|
int ilevel = -1;
|
|
|
|
for (int i = 4; i >= 0; i--)
|
|
{
|
|
if (IRQ_Asserted & (1 << i))
|
|
{
|
|
ilevel = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
VB_V810->SetInt(ilevel);
|
|
}
|
|
|
|
void VBIRQ_Assert(int source, bool assert)
|
|
{
|
|
assert(source >= 0 && source <= 4);
|
|
|
|
IRQ_Asserted &= ~(1 << source);
|
|
|
|
if (assert)
|
|
IRQ_Asserted |= 1 << source;
|
|
|
|
RecalcIntLevel();
|
|
}
|
|
|
|
static MDFN_FASTCALL uint8 HWCTRL_Read(v810_timestamp_t ×tamp, uint32 A)
|
|
{
|
|
uint8 ret = 0;
|
|
|
|
if (A & 0x3)
|
|
{
|
|
//puts("HWCtrl Bogus Read?");
|
|
return (ret);
|
|
}
|
|
|
|
switch (A & 0xFF)
|
|
{
|
|
default: //printf("Unknown HWCTRL Read: %08x\n", A);
|
|
break;
|
|
|
|
case 0x18:
|
|
case 0x1C:
|
|
case 0x20:
|
|
ret = TIMER_Read(timestamp, A);
|
|
break;
|
|
|
|
case 0x24:
|
|
ret = WCR | 0xFC;
|
|
break;
|
|
|
|
case 0x10:
|
|
case 0x14:
|
|
case 0x28:
|
|
lagged = false;
|
|
if (input_callback)
|
|
input_callback();
|
|
ret = VBINPUT_Read(timestamp, A);
|
|
break;
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static MDFN_FASTCALL void HWCTRL_Write(v810_timestamp_t ×tamp, uint32 A, uint8 V)
|
|
{
|
|
if (A & 0x3)
|
|
{
|
|
puts("HWCtrl Bogus Write?");
|
|
return;
|
|
}
|
|
|
|
switch (A & 0xFF)
|
|
{
|
|
default: //printf("Unknown HWCTRL Write: %08x %02x\n", A, V);
|
|
break;
|
|
|
|
case 0x18:
|
|
case 0x1C:
|
|
case 0x20:
|
|
TIMER_Write(timestamp, A, V);
|
|
break;
|
|
|
|
case 0x24:
|
|
WCR = V & 0x3;
|
|
break;
|
|
|
|
case 0x10:
|
|
case 0x14:
|
|
case 0x28:
|
|
VBINPUT_Write(timestamp, A, V);
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint8 MDFN_FASTCALL MemRead8(v810_timestamp_t ×tamp, uint32 A)
|
|
{
|
|
uint8 ret = 0;
|
|
A &= (1 << 27) - 1;
|
|
|
|
//if((A >> 24) <= 2)
|
|
// printf("Read8: %d %08x\n", timestamp, A);
|
|
|
|
switch (A >> 24)
|
|
{
|
|
case 0:
|
|
ret = VIP_Read8(timestamp, A);
|
|
break;
|
|
|
|
case 1:
|
|
break;
|
|
|
|
case 2:
|
|
ret = HWCTRL_Read(timestamp, A);
|
|
break;
|
|
|
|
case 3:
|
|
break;
|
|
case 4:
|
|
break;
|
|
|
|
case 5:
|
|
ret = WRAM[A & 0xFFFF];
|
|
break;
|
|
|
|
case 6:
|
|
if (GPRAM)
|
|
ret = GPRAM[A & GPRAM_Mask];
|
|
break;
|
|
|
|
case 7:
|
|
ret = GPROM[A & GPROM_Mask];
|
|
break;
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
uint16 MDFN_FASTCALL MemRead16(v810_timestamp_t ×tamp, uint32 A)
|
|
{
|
|
uint16 ret = 0;
|
|
|
|
A &= (1 << 27) - 1;
|
|
|
|
//if((A >> 24) <= 2)
|
|
// printf("Read16: %d %08x\n", timestamp, A);
|
|
|
|
switch (A >> 24)
|
|
{
|
|
case 0:
|
|
ret = VIP_Read16(timestamp, A);
|
|
break;
|
|
|
|
case 1:
|
|
break;
|
|
|
|
case 2:
|
|
ret = HWCTRL_Read(timestamp, A);
|
|
break;
|
|
|
|
case 3:
|
|
break;
|
|
|
|
case 4:
|
|
break;
|
|
|
|
case 5:
|
|
ret = MDFN_de16lsb<true>(&WRAM[A & 0xFFFF]);
|
|
break;
|
|
|
|
case 6:
|
|
if (GPRAM)
|
|
ret = MDFN_de16lsb<true>(&GPRAM[A & GPRAM_Mask]);
|
|
break;
|
|
|
|
case 7:
|
|
ret = MDFN_de16lsb<true>(&GPROM[A & GPROM_Mask]);
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void MDFN_FASTCALL MemWrite8(v810_timestamp_t ×tamp, uint32 A, uint8 V)
|
|
{
|
|
A &= (1 << 27) - 1;
|
|
|
|
//if((A >> 24) <= 2)
|
|
// printf("Write8: %d %08x %02x\n", timestamp, A, V);
|
|
|
|
switch (A >> 24)
|
|
{
|
|
case 0:
|
|
VIP_Write8(timestamp, A, V);
|
|
break;
|
|
|
|
case 1:
|
|
VB_VSU->Write((timestamp + VSU_CycleFix) >> 2, A, V);
|
|
break;
|
|
|
|
case 2:
|
|
HWCTRL_Write(timestamp, A, V);
|
|
break;
|
|
|
|
case 3:
|
|
break;
|
|
|
|
case 4:
|
|
break;
|
|
|
|
case 5:
|
|
WRAM[A & 0xFFFF] = V;
|
|
break;
|
|
|
|
case 6:
|
|
if (GPRAM)
|
|
GPRAM[A & GPRAM_Mask] = V;
|
|
break;
|
|
|
|
case 7: // ROM, no writing allowed!
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MDFN_FASTCALL MemWrite16(v810_timestamp_t ×tamp, uint32 A, uint16 V)
|
|
{
|
|
A &= (1 << 27) - 1;
|
|
|
|
//if((A >> 24) <= 2)
|
|
// printf("Write16: %d %08x %04x\n", timestamp, A, V);
|
|
|
|
switch (A >> 24)
|
|
{
|
|
case 0:
|
|
VIP_Write16(timestamp, A, V);
|
|
break;
|
|
|
|
case 1:
|
|
VB_VSU->Write((timestamp + VSU_CycleFix) >> 2, A, V);
|
|
break;
|
|
|
|
case 2:
|
|
HWCTRL_Write(timestamp, A, V);
|
|
break;
|
|
|
|
case 3:
|
|
break;
|
|
|
|
case 4:
|
|
break;
|
|
|
|
case 5:
|
|
MDFN_en16lsb<true>(&WRAM[A & 0xFFFF], V);
|
|
break;
|
|
|
|
case 6:
|
|
if (GPRAM)
|
|
MDFN_en16lsb<true>(&GPRAM[A & GPRAM_Mask], V);
|
|
break;
|
|
|
|
case 7: // ROM, no writing allowed!
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void FixNonEvents(void)
|
|
{
|
|
if (next_vip_ts & 0x40000000)
|
|
next_vip_ts = VB_EVENT_NONONO;
|
|
|
|
if (next_timer_ts & 0x40000000)
|
|
next_timer_ts = VB_EVENT_NONONO;
|
|
|
|
if (next_input_ts & 0x40000000)
|
|
next_input_ts = VB_EVENT_NONONO;
|
|
}
|
|
|
|
static void EventReset(void)
|
|
{
|
|
next_vip_ts = VB_EVENT_NONONO;
|
|
next_timer_ts = VB_EVENT_NONONO;
|
|
next_input_ts = VB_EVENT_NONONO;
|
|
}
|
|
|
|
static INLINE int32 CalcNextTS(void)
|
|
{
|
|
int32 next_timestamp = next_vip_ts;
|
|
|
|
if (next_timestamp > next_timer_ts)
|
|
next_timestamp = next_timer_ts;
|
|
|
|
if (next_timestamp > next_input_ts)
|
|
next_timestamp = next_input_ts;
|
|
|
|
return (next_timestamp);
|
|
}
|
|
|
|
static void RebaseTS(const v810_timestamp_t timestamp)
|
|
{
|
|
//printf("Rebase: %08x %08x %08x\n", timestamp, next_vip_ts, next_timer_ts);
|
|
|
|
assert(next_vip_ts > timestamp);
|
|
assert(next_timer_ts > timestamp);
|
|
assert(next_input_ts > timestamp);
|
|
|
|
next_vip_ts -= timestamp;
|
|
next_timer_ts -= timestamp;
|
|
next_input_ts -= timestamp;
|
|
}
|
|
|
|
void VB_SetEvent(const int type, const v810_timestamp_t next_timestamp)
|
|
{
|
|
//assert(next_timestamp > VB_V810->v810_timestamp);
|
|
|
|
if (type == VB_EVENT_VIP)
|
|
next_vip_ts = next_timestamp;
|
|
else if (type == VB_EVENT_TIMER)
|
|
next_timer_ts = next_timestamp;
|
|
else if (type == VB_EVENT_INPUT)
|
|
next_input_ts = next_timestamp;
|
|
|
|
if (next_timestamp < VB_V810->GetEventNT())
|
|
VB_V810->SetEventNT(next_timestamp);
|
|
}
|
|
|
|
static int32 MDFN_FASTCALL EventHandler(const v810_timestamp_t timestamp)
|
|
{
|
|
if (timestamp >= next_vip_ts)
|
|
next_vip_ts = VIP_Update(timestamp);
|
|
|
|
if (timestamp >= next_timer_ts)
|
|
next_timer_ts = TIMER_Update(timestamp);
|
|
|
|
if (timestamp >= next_input_ts)
|
|
next_input_ts = VBINPUT_Update(timestamp);
|
|
|
|
return (CalcNextTS());
|
|
}
|
|
|
|
// Called externally from debug.cpp in some cases.
|
|
void ForceEventUpdates(const v810_timestamp_t timestamp)
|
|
{
|
|
next_vip_ts = VIP_Update(timestamp);
|
|
next_timer_ts = TIMER_Update(timestamp);
|
|
next_input_ts = VBINPUT_Update(timestamp);
|
|
|
|
VB_V810->SetEventNT(CalcNextTS());
|
|
//printf("FEU: %d %d %d\n", next_vip_ts, next_timer_ts, next_input_ts);
|
|
}
|
|
|
|
static void VB_Power(void)
|
|
{
|
|
memset(WRAM, 0, 65536);
|
|
|
|
VIP_Power();
|
|
VB_VSU->Power();
|
|
TIMER_Power();
|
|
VBINPUT_Power();
|
|
|
|
EventReset();
|
|
IRQ_Asserted = 0;
|
|
RecalcIntLevel();
|
|
VB_V810->Reset();
|
|
|
|
VSU_CycleFix = 0;
|
|
WCR = 0;
|
|
|
|
ForceEventUpdates(0); //VB_V810->v810_timestamp);
|
|
}
|
|
|
|
/*struct VB_HeaderInfo
|
|
{
|
|
char game_title[256];
|
|
uint32 game_code;
|
|
uint16 manf_code;
|
|
uint8 version;
|
|
};*/
|
|
|
|
/*static void ReadHeader(const uint8 *const rom_data, const uint64 rom_size, VB_HeaderInfo *hi)
|
|
{
|
|
iconv_t sjis_ict = iconv_open("UTF-8", "shift_jis");
|
|
|
|
if (sjis_ict != (iconv_t)-1)
|
|
{
|
|
char *in_ptr, *out_ptr;
|
|
size_t ibl, obl;
|
|
|
|
ibl = 20;
|
|
obl = sizeof(hi->game_title) - 1;
|
|
|
|
in_ptr = (char *)rom_data + (0xFFFFFDE0 & (rom_size - 1));
|
|
out_ptr = hi->game_title;
|
|
|
|
iconv(sjis_ict, (ICONV_CONST char **)&in_ptr, &ibl, &out_ptr, &obl);
|
|
iconv_close(sjis_ict);
|
|
|
|
*out_ptr = 0;
|
|
|
|
MDFN_zapctrlchars(hi->game_title);
|
|
MDFN_trim(hi->game_title);
|
|
}
|
|
else
|
|
hi->game_title[0] = 0;
|
|
|
|
hi->game_code = MDFN_de32lsb(rom_data + (0xFFFFFDFB & (rom_size - 1)));
|
|
hi->manf_code = MDFN_de16lsb(rom_data + (0xFFFFFDF9 & (rom_size - 1)));
|
|
hi->version = rom_data[0xFFFFFDFF & (rom_size - 1)];
|
|
}*/
|
|
|
|
void VB_ExitLoop(void)
|
|
{
|
|
VB_V810->Exit();
|
|
}
|
|
|
|
/*MDFNGI EmulatedVB =
|
|
{
|
|
|
|
PortInfo,
|
|
Load,
|
|
TestMagic,
|
|
NULL,
|
|
NULL,
|
|
CloseGame,
|
|
|
|
SetLayerEnableMask,
|
|
NULL, // Layer names, null-delimited
|
|
|
|
NULL,
|
|
NULL,
|
|
|
|
VIP_CPInfo,
|
|
1 << 0,
|
|
|
|
CheatInfo_Empty,
|
|
|
|
false,
|
|
StateAction,
|
|
Emulate,
|
|
NULL,
|
|
VBINPUT_SetInput,
|
|
NULL,
|
|
DoSimpleCommand,
|
|
NULL,
|
|
VBSettings,
|
|
MDFN_MASTERCLOCK_FIXED(VB_MASTER_CLOCK),
|
|
0,
|
|
false, // Multires possible?
|
|
|
|
0, // lcm_width
|
|
0, // lcm_height
|
|
NULL, // Dummy
|
|
|
|
384, // Nominal width
|
|
224, // Nominal height
|
|
|
|
384, // Framebuffer width
|
|
256, // Framebuffer height
|
|
|
|
2, // Number of output sound channels
|
|
};*/
|
|
}
|
|
|
|
using namespace MDFN_IEN_VB;
|
|
|
|
EXPORT int Load(const uint8 *rom, int length, const NativeSyncSettings *syncSettings)
|
|
{
|
|
const uint64 rom_size = length;
|
|
V810_Emu_Mode cpu_mode = V810_EMU_MODE_ACCURATE;
|
|
|
|
if (rom_size != round_up_pow2(rom_size))
|
|
{
|
|
return 0;
|
|
// throw MDFN_Error(0, _("VB ROM image size is not a power of 2."));
|
|
}
|
|
|
|
if (rom_size < 256)
|
|
{
|
|
return 0;
|
|
//throw MDFN_Error(0, _("VB ROM image size is too small."));
|
|
}
|
|
|
|
if (rom_size > (1 << 24))
|
|
{
|
|
return 0;
|
|
//throw MDFN_Error(0, _("VB ROM image size is too large."));
|
|
}
|
|
|
|
VB_V810 = new V810();
|
|
VB_V810->Init(cpu_mode, true);
|
|
|
|
VB_V810->SetMemReadHandlers(MemRead8, MemRead16, NULL);
|
|
VB_V810->SetMemWriteHandlers(MemWrite8, MemWrite16, NULL);
|
|
|
|
VB_V810->SetIOReadHandlers(MemRead8, MemRead16, NULL);
|
|
VB_V810->SetIOWriteHandlers(MemWrite8, MemWrite16, NULL);
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
VB_V810->SetMemReadBus32(i, false);
|
|
VB_V810->SetMemWriteBus32(i, false);
|
|
}
|
|
|
|
std::vector<uint32> Map_Addresses;
|
|
|
|
for (uint64 A = 0; A < 1ULL << 32; A += (1 << 27))
|
|
{
|
|
for (uint64 sub_A = 5 << 24; sub_A < (6 << 24); sub_A += 65536)
|
|
{
|
|
Map_Addresses.push_back(A + sub_A);
|
|
}
|
|
}
|
|
|
|
WRAM = VB_V810->SetFastMap(alloc_plain, &Map_Addresses[0], 65536, Map_Addresses.size(), "WRAM");
|
|
Map_Addresses.clear();
|
|
|
|
// Round up the ROM size to 65536(we mirror it a little later)
|
|
GPROM_Mask = (rom_size < 65536) ? (65536 - 1) : (rom_size - 1);
|
|
|
|
for (uint64 A = 0; A < 1ULL << 32; A += (1 << 27))
|
|
{
|
|
for (uint64 sub_A = 7 << 24; sub_A < (8 << 24); sub_A += GPROM_Mask + 1)
|
|
{
|
|
Map_Addresses.push_back(A + sub_A);
|
|
//printf("%08x\n", (uint32)(A + sub_A));
|
|
}
|
|
}
|
|
|
|
GPROM = VB_V810->SetFastMap(alloc_sealed, &Map_Addresses[0], GPROM_Mask + 1, Map_Addresses.size(), "Cart ROM");
|
|
Map_Addresses.clear();
|
|
|
|
memcpy(GPROM, rom, rom_size);
|
|
|
|
// Mirror ROM images < 64KiB to 64KiB
|
|
for (uint64 i = rom_size; i < 65536; i += rom_size)
|
|
{
|
|
memcpy(GPROM + i, GPROM, rom_size);
|
|
}
|
|
|
|
/*VB_HeaderInfo hinfo;
|
|
|
|
ReadHeader(GPROM, rom_size, &hinfo);
|
|
|
|
MDFN_printf(_("Title: %s\n"), hinfo.game_title);
|
|
MDFN_printf(_("Game ID Code: %u\n"), hinfo.game_code);
|
|
MDFN_printf(_("Manufacturer Code: %d\n"), hinfo.manf_code);
|
|
MDFN_printf(_("Version: %u\n"), hinfo.version);
|
|
|
|
MDFN_printf(_("ROM: %uKiB\n"), (unsigned)(rom_size / 1024));
|
|
MDFN_printf(_("ROM MD5: 0x%s\n"), md5_context::asciistr(MDFNGameInfo->MD5, 0).c_str());*/
|
|
|
|
/*MDFN_printf("\n");
|
|
|
|
MDFN_printf(_("V810 Emulation Mode: %s\n"), (cpu_mode == V810_EMU_MODE_ACCURATE) ? _("Accurate") : _("Fast"));*/
|
|
|
|
for (uint64 A = 0; A < 1ULL << 32; A += (1 << 27))
|
|
{
|
|
for (uint64 sub_A = 6 << 24; sub_A < (7 << 24); sub_A += GPRAM_Mask + 1)
|
|
{
|
|
//printf("GPRAM: %08x\n", A + sub_A);
|
|
Map_Addresses.push_back(A + sub_A);
|
|
}
|
|
}
|
|
|
|
GPRAM = VB_V810->SetFastMap(alloc_plain, &Map_Addresses[0], GPRAM_Mask + 1, Map_Addresses.size(), "Cart RAM");
|
|
Map_Addresses.clear();
|
|
|
|
memset(GPRAM, 0, GPRAM_Mask + 1);
|
|
|
|
VIP_Init();
|
|
VB_VSU = new VSU();
|
|
VBINPUT_Init();
|
|
|
|
VB3DMode = 0;
|
|
uint32 prescale = 1;
|
|
uint32 sbs_separation = 0;
|
|
bool reverse = false;
|
|
|
|
VIP_Set3DMode(VB3DMode, reverse, prescale, sbs_separation);
|
|
|
|
VIP_SetParallaxDisable(syncSettings->DisableParallax);
|
|
|
|
{
|
|
auto presetColor = 1;
|
|
|
|
uint32 lcolor = 0xff0000;
|
|
uint32 rcolor = 0x00ff00;
|
|
|
|
if (presetColor != ANAGLYPH_PRESET_DISABLED)
|
|
{
|
|
lcolor = AnaglyphPreset_Colors[presetColor][0];
|
|
rcolor = AnaglyphPreset_Colors[presetColor][1];
|
|
}
|
|
VIP_SetAnaglyphColors(lcolor, rcolor);
|
|
VIP_SetDefaultColor(0xffffff);
|
|
}
|
|
|
|
VBINPUT_SetInstantReadHack(syncSettings->InstantReadHack);
|
|
|
|
VIP_SetLEDOnScale(1750 / 1000.0);
|
|
|
|
VB_Power();
|
|
|
|
/*switch (VB3DMode)
|
|
{
|
|
default:
|
|
break;
|
|
|
|
case VB3DMODE_VLI:
|
|
MDFNGameInfo->nominal_width = 768 * prescale;
|
|
MDFNGameInfo->nominal_height = 224;
|
|
MDFNGameInfo->fb_width = 768 * prescale;
|
|
MDFNGameInfo->fb_height = 224;
|
|
break;
|
|
|
|
case VB3DMODE_HLI:
|
|
MDFNGameInfo->nominal_width = 384;
|
|
MDFNGameInfo->nominal_height = 448 * prescale;
|
|
MDFNGameInfo->fb_width = 384;
|
|
MDFNGameInfo->fb_height = 448 * prescale;
|
|
break;
|
|
|
|
case VB3DMODE_CSCOPE:
|
|
MDFNGameInfo->nominal_width = 512;
|
|
MDFNGameInfo->nominal_height = 384;
|
|
MDFNGameInfo->fb_width = 512;
|
|
MDFNGameInfo->fb_height = 384;
|
|
break;
|
|
|
|
case VB3DMODE_SIDEBYSIDE:
|
|
MDFNGameInfo->nominal_width = 384 * 2 + sbs_separation;
|
|
MDFNGameInfo->nominal_height = 224;
|
|
MDFNGameInfo->fb_width = 384 * 2 + sbs_separation;
|
|
MDFNGameInfo->fb_height = 224;
|
|
break;
|
|
}
|
|
MDFNGameInfo->lcm_width = MDFNGameInfo->fb_width;
|
|
MDFNGameInfo->lcm_height = MDFNGameInfo->fb_height;*/
|
|
|
|
VB_VSU->SetSoundRate(44100);
|
|
|
|
return 1;
|
|
}
|
|
|
|
EXPORT void SetSettings(const NativeSettings *settings)
|
|
{
|
|
VB3DMode = settings->ThreeDeeMode;
|
|
uint32 prescale = settings->InterlacePrescale;
|
|
uint32 sbs_separation = settings->SideBySideSeparation;
|
|
bool reverse = settings->SwapViews;
|
|
|
|
VIP_Set3DMode(VB3DMode, reverse, prescale, sbs_separation);
|
|
|
|
{
|
|
auto presetColor = settings->AnaglyphPreset;
|
|
|
|
uint32 lcolor = settings->AnaglyphCustomLeftColor;
|
|
uint32 rcolor = settings->AnaglyphCustomRightColor;
|
|
|
|
if (presetColor != ANAGLYPH_PRESET_DISABLED)
|
|
{
|
|
lcolor = AnaglyphPreset_Colors[presetColor][0];
|
|
rcolor = AnaglyphPreset_Colors[presetColor][1];
|
|
}
|
|
VIP_SetAnaglyphColors(lcolor, rcolor);
|
|
VIP_SetDefaultColor(settings->NonAnaglyphColor);
|
|
}
|
|
|
|
VIP_SetLEDOnScale(settings->LedOnScale / 1000.0);
|
|
}
|
|
|
|
EXPORT void GetMemoryAreas(MemoryArea *m)
|
|
{
|
|
m[0].Data = WRAM;
|
|
m[0].Name = "WRAM";
|
|
m[0].Size = 65536;
|
|
m[0].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_PRIMARY | MEMORYAREA_FLAGS_WORDSIZE4;
|
|
|
|
m[1].Data = GPRAM;
|
|
m[1].Name = "CARTRAM";
|
|
m[1].Size = GPRAM_Mask + 1;
|
|
m[1].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_SAVERAMMABLE | MEMORYAREA_FLAGS_WORDSIZE4;
|
|
|
|
m[2].Data = GPROM;
|
|
m[2].Name = "ROM";
|
|
m[2].Size = GPROM_Mask + 1;
|
|
m[2].Flags = MEMORYAREA_FLAGS_WORDSIZE4;
|
|
}
|
|
|
|
EXPORT void FrameAdvance(MyFrameInfo *frame)
|
|
{
|
|
v810_timestamp_t v810_timestamp;
|
|
lagged = true;
|
|
|
|
VBINPUT_Frame(&frame->Buttons);
|
|
|
|
VIP_StartFrame(frame);
|
|
|
|
v810_timestamp = VB_V810->Run(EventHandler);
|
|
|
|
FixNonEvents();
|
|
ForceEventUpdates(v810_timestamp);
|
|
|
|
frame->Samples = VB_VSU->EndFrame((v810_timestamp + VSU_CycleFix) >> 2, frame->SoundBuffer, 8192);
|
|
|
|
VSU_CycleFix = (v810_timestamp + VSU_CycleFix) & 3;
|
|
|
|
frame->Cycles = v810_timestamp;
|
|
frame->Lagged = lagged;
|
|
|
|
TIMER_ResetTS();
|
|
VBINPUT_ResetTS();
|
|
VIP_ResetTS();
|
|
|
|
RebaseTS(v810_timestamp);
|
|
|
|
VB_V810->ResetTS(0);
|
|
}
|
|
|
|
EXPORT void PredictFrameSize(MyFrameInfo *frame)
|
|
{
|
|
VIP_CalcFrameSize(frame);
|
|
}
|
|
|
|
EXPORT void HardReset()
|
|
{
|
|
VB_Power();
|
|
}
|
|
|
|
EXPORT void SetInputCallback(void (*callback)())
|
|
{
|
|
input_callback = callback;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
return 0;
|
|
}
|