Add new console target: GBA

This commit is contained in:
taoenwen committed 2026-08-06 04:15:51 +08:00
1 parent a85b0974d7
commit cde78e9a72
28 files changed
+9887 -18

No files matched your search

+3 -1
View File
@@ -1,5 +1,5 @@
alldir = burn burn/devices burn/snd burn/drv burn/drv/atari burn/drv/capcom burn/drv/cave burn/drv/channelf burn/drv/coleco burn/drv/cps3 burn/drv/dataeast \
burn/drv/galaxian burn/drv/irem burn/drv/konami burn/drv/megadrive burn/drv/midway burn/drv/pce burn/drv/pst90s burn/drv/pre90s burn/drv/neogeo burn/drv/nes burn/drv/snes \
burn/drv/galaxian burn/drv/gba burn/drv/irem burn/drv/konami burn/drv/megadrive burn/drv/midway burn/drv/pce burn/drv/pst90s burn/drv/pre90s burn/drv/neogeo burn/drv/nes burn/drv/snes \
burn/drv/pgm burn/drv/pgm2 burn/drv/psikyo burn/drv/sega burn/drv/sg1000 burn/drv/sms burn/drv/msx burn/drv/spectrum burn/drv/taito \
burn/drv/toaplan cpu cpu/a68k cpu/arm cpu/arm7 cpu/arm9 cpu/e132xs cpu/f8 cpu/h6280 cpu/hd6309 cpu/hmcs40 cpu/i386 cpu/i8039 cpu/i8x41 cpu/i8051 cpu/i8085 cpu/adsp2100 cpu/konami cpu/m377 cpu/mips3 cpu/m68k \
cpu/mb88xx cpu/m6502 cpu/m6800 cpu/m6805 cpu/m6809 cpu/nec cpu/pic16c5x cpu/s2650 cpu/tlcs90 cpu/tlcs900 cpu/sh2 cpu/sh4 cpu/t11 cpu/tms32010 cpu/tms34 cpu/upd7725 cpu/upd7810 \
@@ -26,6 +26,8 @@ drvsrc = d_akkaarrh.o d_arcadecl.o d_atarig1.o d_atarisy1.o d_badlands.o d_batm
\
d_119.o d_galaxian.o \
\
d_gba.o gba.o \
\
d_m52.o d_m57.o d_m58.o d_m62.o d_m63.o d_m72.o d_m90.o d_m92.o d_m107.o d_travrusa.o d_vigilant.o \
\
d_88games.o d_ajax.o d_aliens.o d_asterix.o d_battlnts.o d_bishi.o d_bladestl.o d_blockhl.o d_bottom9.o d_chqflag.o d_circusc.o d_combatsc.o \
+3
View File
@@ -672,6 +672,9 @@ $(cave_tile_func.h): $(srcdir)dep/scripts/cave_tile_func.pl
cave_sprite.d cave_sprite.o: $(cave_sprite_func.h)
gba.d gba.o: $(srcdir)burn/drv/gba/gba.h $(srcdir)burn/drv/gba/gba_impl.h $(srcdir)burn/drv/gba/host.h $(srcdir)burn/drv/gba/arm7.h $(srcdir)burn/drv/gba/bios.h $(srcdir)burn/drv/gba/rtc.h
d_gba.d d_gba.o: $(srcdir)burn/drv/gba/gba.h
$(cave_sprite_func.h): $(srcdir)dep/scripts/cave_sprite_func.pl
@$(srcdir)dep/scripts/cave_sprite_func.pl -o $(cave_sprite_func.h)
+1
View File
@@ -21,6 +21,7 @@ option('driver_list',
'cps3',
'dataeast',
'galaxian',
'gba',
'irem',
'konami',
'megadrive',
@@ -555,6 +555,8 @@ del %(Filename).exe</Command>
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_run.cpp" />
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_sound.cpp" />
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_stars.cpp" />
<ClCompile Include="..\..\src\burn\drv\gba\d_gba.cpp" />
<ClCompile Include="..\..\src\burn\drv\gba\gba.cpp" />
<ClCompile Include="..\..\src\burn\drv\irem\d_m107.cpp" />
<ClCompile Include="..\..\src\burn\drv\irem\d_m52.cpp" />
<ClCompile Include="..\..\src\burn\drv\irem\d_m57.cpp" />
@@ -418,6 +418,12 @@
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_stars.cpp">
<Filter>burn\drv\galaxian</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\gba\d_gba.cpp">
<Filter>burn\drv\gba</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\gba\gba.cpp">
<Filter>burn\drv\gba</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\irem\d_m62.cpp">
<Filter>burn\drv\irem</Filter>
</ClCompile>
@@ -3876,6 +3882,9 @@
<Filter Include="burn\drv\galaxian">
<UniqueIdentifier>{c4b93ffc-1f2a-4461-a73b-d7153fd1a1e6}</UniqueIdentifier>
</Filter>
<Filter Include="burn\drv\gba">
<UniqueIdentifier>{6b17d54b-49ca-4e1f-9f6f-418472209f26}</UniqueIdentifier>
</Filter>
<Filter Include="burn\drv\irem">
<UniqueIdentifier>{0937431a-c5c3-4079-86ff-f553d99ef136}</UniqueIdentifier>
</Filter>
@@ -555,6 +555,8 @@ del %(Filename).exe</Command>
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_run.cpp" />
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_sound.cpp" />
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_stars.cpp" />
<ClCompile Include="..\..\src\burn\drv\gba\d_gba.cpp" />
<ClCompile Include="..\..\src\burn\drv\gba\gba.cpp" />
<ClCompile Include="..\..\src\burn\drv\irem\d_m107.cpp" />
<ClCompile Include="..\..\src\burn\drv\irem\d_m52.cpp" />
<ClCompile Include="..\..\src\burn\drv\irem\d_m57.cpp" />
@@ -418,6 +418,12 @@
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_stars.cpp">
<Filter>burn\drv\galaxian</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\gba\d_gba.cpp">
<Filter>burn\drv\gba</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\gba\gba.cpp">
<Filter>burn\drv\gba</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\irem\d_m62.cpp">
<Filter>burn\drv\irem</Filter>
</ClCompile>
@@ -3876,6 +3882,9 @@
<Filter Include="burn\drv\galaxian">
<UniqueIdentifier>{c4b93ffc-1f2a-4461-a73b-d7153fd1a1e6}</UniqueIdentifier>
</Filter>
<Filter Include="burn\drv\gba">
<UniqueIdentifier>{6b17d54b-49ca-4e1f-9f6f-418472209f26}</UniqueIdentifier>
</Filter>
<Filter Include="burn\drv\irem">
<UniqueIdentifier>{0937431a-c5c3-4079-86ff-f553d99ef136}</UniqueIdentifier>
</Filter>
@@ -555,6 +555,8 @@ del %(Filename).exe</Command>
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_run.cpp" />
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_sound.cpp" />
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_stars.cpp" />
<ClCompile Include="..\..\src\burn\drv\gba\d_gba.cpp" />
<ClCompile Include="..\..\src\burn\drv\gba\gba.cpp" />
<ClCompile Include="..\..\src\burn\drv\irem\d_m107.cpp" />
<ClCompile Include="..\..\src\burn\drv\irem\d_m52.cpp" />
<ClCompile Include="..\..\src\burn\drv\irem\d_m57.cpp" />
@@ -418,6 +418,12 @@
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_stars.cpp">
<Filter>burn\drv\galaxian</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\gba\d_gba.cpp">
<Filter>burn\drv\gba</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\gba\gba.cpp">
<Filter>burn\drv\gba</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\irem\d_m62.cpp">
<Filter>burn\drv\irem</Filter>
</ClCompile>
@@ -3876,6 +3882,9 @@
<Filter Include="burn\drv\galaxian">
<UniqueIdentifier>{c4b93ffc-1f2a-4461-a73b-d7153fd1a1e6}</UniqueIdentifier>
</Filter>
<Filter Include="burn\drv\gba">
<UniqueIdentifier>{6b17d54b-49ca-4e1f-9f6f-418472209f26}</UniqueIdentifier>
</Filter>
<Filter Include="burn\drv\irem">
<UniqueIdentifier>{0937431a-c5c3-4079-86ff-f553d99ef136}</UniqueIdentifier>
</Filter>
@@ -243,6 +243,8 @@
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_run.cpp" />
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_sound.cpp" />
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_stars.cpp" />
<ClCompile Include="..\..\src\burn\drv\gba\d_gba.cpp" />
<ClCompile Include="..\..\src\burn\drv\gba\gba.cpp" />
<ClCompile Include="..\..\src\burn\drv\irem\d_m107.cpp" />
<ClCompile Include="..\..\src\burn\drv\irem\d_m52.cpp" />
<ClCompile Include="..\..\src\burn\drv\irem\d_m57.cpp" />
@@ -1443,7 +1445,7 @@ cd scripts
cl.exe /D "_UNICODE" %(Filename).cpp
.%(Filename).exe &gt;../../../projectfiles/visualstudio-2026/generated/%(Filename).h
.\%(Filename).exe &gt;../../../projectfiles/visualstudio-2026/generated/%(Filename).h
del %(Filename).obj
@@ -1462,7 +1464,7 @@ cd scripts
cl.exe /D "_UNICODE" %(Filename).cpp
.%(Filename).exe &gt;../../../projectfiles/visualstudio-2026/generated/%(Filename).h
.\%(Filename).exe &gt;../../../projectfiles/visualstudio-2026/generated/%(Filename).h
del %(Filename).obj
@@ -1481,7 +1483,7 @@ cd scripts
cl.exe /D "_UNICODE" /D "BUILD_X64_EXE" %(Filename).cpp
.%(Filename).exe &gt;../../../projectfiles/visualstudio-2026/generated/%(Filename).h
.\%(Filename).exe &gt;../../../projectfiles/visualstudio-2026/generated/%(Filename).h
del %(Filename).obj
@@ -1500,7 +1502,7 @@ cd scripts
cl.exe /D "_UNICODE" /D "BUILD_X64_EXE" %(Filename).cpp
.%(Filename).exe &gt;../../../projectfiles/visualstudio-2026/generated/%(Filename).h
.\%(Filename).exe &gt;../../../projectfiles/visualstudio-2026/generated/%(Filename).h
del %(Filename).obj
@@ -637,6 +637,12 @@
<ClCompile Include="..\..\src\burn\drv\galaxian\gal_stars.cpp">
<Filter>burn\drv\galaxian</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\gba\d_gba.cpp">
<Filter>burn\drv\gba</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\gba\gba.cpp">
<Filter>burn\drv\gba</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\irem\d_m107.cpp">
<Filter>burn\drv\irem</Filter>
</ClCompile>
@@ -3876,6 +3882,9 @@
<Filter Include="burn\drv\galaxian">
<UniqueIdentifier>{c4b93ffc-1f2a-4461-a73b-d7153fd1a1e6}</UniqueIdentifier>
</Filter>
<Filter Include="burn\drv\gba">
<UniqueIdentifier>{6b17d54b-49ca-4e1f-9f6f-418472209f26}</UniqueIdentifier>
</Filter>
<Filter Include="burn\drv\irem">
<UniqueIdentifier>{0937431a-c5c3-4079-86ff-f553d99ef136}</UniqueIdentifier>
</Filter>
+28 -8
View File
@@ -1741,8 +1741,20 @@ extern struct MovieExtInfo MovieInfo; // from replay.cpp
struct MovieExtInfo MovieInfo = { 0, 0, 0, 0, 0, 0, 0 };
#endif
static INT32 BurnDayOfYear(INT32 year, INT32 month, INT32 day)
{
static const INT32 daysBeforeMonth[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
INT32 result = daysBeforeMonth[month] + day - 1;
if (month > 1 && year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) result++;
return result;
}
void BurnGetLocalTime(tm *nTime)
{
if (nTime == NULL) return;
memset(nTime, 0, sizeof(*nTime));
nTime->tm_isdst = -1;
if (is_netgame_or_recording()) {
if (is_netgame_or_recording() & 2) { // recording/playback
nTime->tm_sec = MovieInfo.second;
@@ -1752,19 +1764,27 @@ void BurnGetLocalTime(tm *nTime)
nTime->tm_wday = MovieInfo.dayofweek;
nTime->tm_mon = MovieInfo.month;
nTime->tm_year = MovieInfo.year;
if (nTime->tm_mon >= 0 && nTime->tm_mon < 12 && nTime->tm_mday > 0) {
nTime->tm_yday = BurnDayOfYear(nTime->tm_year + 1900, nTime->tm_mon, nTime->tm_mday);
}
} else {
nTime->tm_sec = 0; // defaults for netgame
nTime->tm_min = 0;
nTime->tm_hour = 0;
nTime->tm_mday = 1;
nTime->tm_wday = 3;
nTime->tm_mon = 6 - 1;
nTime->tm_year = 2018;
nTime->tm_mday = 1; // 2018-06-01 00:00:00 for netgame
nTime->tm_wday = 5;
nTime->tm_yday = 151;
nTime->tm_mon = 5;
nTime->tm_year = 2018 - 1900;
}
} else {
time_t nLocalTime = time(NULL); // query current time from this machine
tm* tmLocalTime = localtime(&nLocalTime);
memcpy(nTime, tmLocalTime, sizeof(tm));
if (tmLocalTime) {
memcpy(nTime, tmLocalTime, sizeof(*nTime));
} else {
nTime->tm_mday = 1;
nTime->tm_wday = 6;
nTime->tm_mon = 0;
nTime->tm_year = 2000 - 1900;
}
}
}
+4
View File
@@ -34,6 +34,7 @@
#define BUILD_CPS3
#define BUILD_DATAEAST
#define BUILD_GALAXIAN
#define BUILD_GBA
#define BUILD_IREM
#define BUILD_KONAMI
#define BUILD_MEGADRIVE
@@ -601,6 +602,7 @@ int BurnComputeSHA1(const UINT8 *buffer, int buffer_size, char *hash_str);
#define HARDWARE_PREFIX_SNES (0x22000000)
#define HARDWARE_PREFIX_IGS_PGM2 (0x23000000)
#define HARDWARE_PREFIX_ASTROHOME (0x24000000)
#define HARDWARE_PREFIX_GBA (0x25000000)
#define HARDWARE_SNK_NGP (HARDWARE_PREFIX_NGP | 0x00000000)
#define HARDWARE_SNK_NGPC (HARDWARE_PREFIX_NGP | 0x00000001) // must not be 0x10000
@@ -852,6 +854,8 @@ int BurnComputeSHA1(const UINT8 *buffer, int buffer_size, char *hash_str);
#define HARDWARE_ASTROHOME (HARDWARE_PREFIX_ASTROHOME)
#define HARDWARE_GBA (HARDWARE_PREFIX_GBA)
// flags for the genre member
#define GBF_HORSHOOT (1 << 0)
#define GBF_VERSHOOT (1 << 1)
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+527
View File
@@ -0,0 +1,527 @@
// FBNeo Game Boy Advance driver
#include "burnint.h"
#include "gba.h"
static GbaCore* Gba;
static UINT8* DrvRom;
static UINT8* DrvBios;
static UINT8* DrvState;
static UINT8* DrvBattery;
static INT32 DrvStateSize;
static INT32 DrvBatterySize;
static UINT8 DrvJoy[10];
static UINT8 DrvReset;
static UINT8 DrvRecalc;
static UINT16 DrvSolar;
static UINT8 DrvSolarUp;
static UINT8 DrvSolarDown;
static UINT8 DrvSolarUpLast;
static UINT8 DrvSolarDownLast;
static UINT16 DrvGyroZ;
static UINT16 DrvTiltX;
static UINT16 DrvTiltY;
#define GBA_BUTTON_INPUTS \
{ "P1 Up", BIT_DIGITAL, DrvJoy + GBA_BUTTON_UP, "p1 up" }, \
{ "P1 Down", BIT_DIGITAL, DrvJoy + GBA_BUTTON_DOWN, "p1 down" }, \
{ "P1 Left", BIT_DIGITAL, DrvJoy + GBA_BUTTON_LEFT, "p1 left" }, \
{ "P1 Right", BIT_DIGITAL, DrvJoy + GBA_BUTTON_RIGHT, "p1 right" }, \
{ "P1 Button A", BIT_DIGITAL, DrvJoy + GBA_BUTTON_A, "p1 fire 1" }, \
{ "P1 Button B", BIT_DIGITAL, DrvJoy + GBA_BUTTON_B, "p1 fire 2" }, \
{ "P1 Button L", BIT_DIGITAL, DrvJoy + GBA_BUTTON_L, "p1 fire 3" }, \
{ "P1 Button R", BIT_DIGITAL, DrvJoy + GBA_BUTTON_R, "p1 fire 4" },
#define GBA_RESET_INPUTS \
{ "P1 Select", BIT_DIGITAL, DrvJoy + GBA_BUTTON_SELECT, "p1 select" }, \
{ "P1 Start", BIT_DIGITAL, DrvJoy + GBA_BUTTON_START, "p1 start" }, \
{ "Reset", BIT_DIGITAL, &DrvReset, "reset" },
#define GBA_SOLAR_INPUTS \
{ "Solar Brighter", BIT_DIGITAL, &DrvSolarUp, "p1 fire 5" }, \
{ "Solar Darker", BIT_DIGITAL, &DrvSolarDown, "p1 fire 6" },
#define GBA_GYRO_INPUTS \
{ "Gyro Z", BIT_ANALOG_ABS, (UINT8*)&DrvGyroZ, "p1 gyro z-axis" },
#define GBA_TILT_INPUTS \
{ "Tilt X", BIT_ANALOG_ABS, (UINT8*)&DrvTiltX, "p1 tilt x-axis" }, \
{ "Tilt Y", BIT_ANALOG_ABS, (UINT8*)&DrvTiltY, "p1 tilt y-axis" },
static struct BurnInputInfo GbaInputList[] = {
GBA_BUTTON_INPUTS
GBA_RESET_INPUTS
};
STDINPUTINFO(Gba)
static struct BurnInputInfo SolarInputList[] = { // Solar sensor
GBA_BUTTON_INPUTS
GBA_SOLAR_INPUTS
GBA_RESET_INPUTS
};
STDINPUTINFO(Solar)
static struct BurnInputInfo GyroInputList[] = { // Gyroscope
GBA_BUTTON_INPUTS
GBA_GYRO_INPUTS
GBA_RESET_INPUTS
};
STDINPUTINFO(Gyro)
static struct BurnInputInfo TiltInputList[] = { // Tilt sensor
GBA_BUTTON_INPUTS
GBA_TILT_INPUTS
GBA_RESET_INPUTS
};
STDINPUTINFO(Tilt)
static struct BurnInputInfo AioInputList[] = { // All-in-one
GBA_BUTTON_INPUTS
GBA_SOLAR_INPUTS
GBA_GYRO_INPUTS
GBA_TILT_INPUTS
GBA_RESET_INPUTS
};
STDINPUTINFO(Aio)
#undef GBA_BUTTON_INPUTS
#undef GBA_SOLAR_INPUTS
#undef GBA_GYRO_INPUTS
#undef GBA_TILT_INPUTS
#undef GBA_RESET_INPUTS
static INT32 DrvDoReset()
{
return GbaCoreReset(Gba);
}
static INT32 DrvInit()
{
struct BurnRomInfo ri;
memset(&ri, 0, sizeof(ri));
if (BurnDrvGetRomInfo(&ri, 0) || ri.nLen == 0 || ri.nLen > 32 * 1024 * 1024)
return 1;
BurnSetRefreshRate(59.72750057);
UINT32 romSize = ri.nLen;
DrvRom = (UINT8 *)BurnMalloc((INT32)romSize);
if (DrvRom == NULL)
return 1;
if (BurnLoadRom(DrvRom, 0, 1))
return 1;
if (GbaCoreInit(&Gba))
return 1;
memset(&ri, 0, sizeof(ri));
if (BurnDrvGetRomInfo(&ri, 0x80) == 0 && ri.nType && ri.nLen == 0x4000) {
DrvBios = (UINT8 *)BurnMalloc(0x4000);
if (DrvBios && BurnLoadRom(DrvBios, 0x80, 1) == 0) {
if (GbaCoreLoadBios(Gba, DrvBios, 0x4000))
return 1;
} else {
BurnFree(DrvBios);
}
}
tm localTime;
memset(&localTime, 0, sizeof(localTime));
BurnGetLocalTime(&localTime);
GbaRtcSeed rtcSeed;
rtcSeed.year = (UINT16)(localTime.tm_year + 1900);
rtcSeed.month = (UINT8) (localTime.tm_mon + 1);
rtcSeed.day = (UINT8) localTime.tm_mday;
rtcSeed.weekday = (UINT8) localTime.tm_wday;
rtcSeed.hour = (UINT8) localTime.tm_hour;
rtcSeed.minute = (UINT8) localTime.tm_min;
rtcSeed.second = (UINT8) localTime.tm_sec;
bprintf(PRINT_NORMAL, _T("GBA RTC seed: %04d-%02d-%02d %02d:%02d:%02d (wday %d)\n"),
rtcSeed.year, rtcSeed.month, rtcSeed.day, rtcSeed.hour, rtcSeed.minute, rtcSeed.second, rtcSeed.weekday);
if (GbaCoreLoadRom(Gba, DrvRom, romSize, &rtcSeed)) return 1;
DrvStateSize = (INT32)GbaCoreStateSize();
DrvState = (UINT8*)BurnMalloc(DrvStateSize);
DrvBattery = (UINT8*)BurnMalloc((INT32)GbaCoreGetBatteryCapacity());
if (DrvState == NULL || DrvBattery == NULL)
return 1;
DrvBatterySize = (INT32)GbaCoreGetBatterySize(Gba);
bprintf(PRINT_NORMAL, _T("GBA cartridge features: %08x, battery: %d\n"), GbaCoreGetCartridgeFeatures(Gba), DrvBatterySize);
if (DrvBatterySize > 0) {
memcpy(DrvBattery, GbaCoreGetBatteryDataConst(Gba), DrvBatterySize);
}
GbaCoreClearAudio(Gba);
DrvRecalc = 1;
DrvSolar = 0;
DrvSolarUpLast = 0;
DrvSolarDownLast = 0;
DrvGyroZ = 0x8000;
DrvTiltX = 0x8000;
DrvTiltY = 0x8000;
return 0;
}
static INT32 DrvExit()
{
GbaCoreExit(&Gba);
BurnFree(DrvRom);
BurnFree(DrvBios);
BurnFree(DrvState);
BurnFree(DrvBattery);
DrvStateSize = 0;
DrvBatterySize = 0;
DrvSolar = 0;
DrvSolarUpLast = 0;
DrvSolarDownLast = 0;
DrvGyroZ = 0x8000;
DrvTiltX = 0x8000;
DrvTiltY = 0x8000;
return 0;
}
static double DrvAudioRate()
{
return nBurnSoundLen * (GBA_MASTER_CLOCK / 280896.0);
}
static INT32 DrvDraw()
{
const UINT32 *framebuffer = GbaCoreGetFramebuffer(Gba);
if (framebuffer == NULL || pBurnDraw == NULL)
return 0;
for (INT32 y = 0; y < GBA_HEIGHT; y++) {
UINT8 *dest = pBurnDraw + y * nBurnPitch;
const UINT32 *source = framebuffer + y * GBA_WIDTH;
for (INT32 x = 0; x < GBA_WIDTH; x++) {
UINT32 pixel = source[x];
PutPix(dest + x * nBurnBpp, BurnHighCol(pixel & 0xff, (pixel >> 8) & 0xff, (pixel >> 16) & 0xff, 0));
}
}
return 0;
}
static INT32 DrvFrame()
{
if (DrvReset && !bBurnRunAheadFrame && DrvDoReset()) return 1;
GbaInput input;
memset(&input, 0, sizeof(input));
input.gyroZ = GbaMotionAxisToInput(DrvGyroZ);
input.tiltX = GbaMotionAxisToInput(DrvTiltX);
input.tiltY = GbaMotionAxisToInput(DrvTiltY);
if (DrvSolarUp && !DrvSolarDown && !DrvSolarUpLast && DrvSolar < GBA_SOLAR_LEVEL_MAX) {
DrvSolar++;
} else if (DrvSolarDown && !DrvSolarUp && !DrvSolarDownLast && DrvSolar > 0) {
DrvSolar--;
}
DrvSolarUpLast = DrvSolarUp;
DrvSolarDownLast = DrvSolarDown;
input.solar = GbaSolarLevelToInput((UINT8)DrvSolar);
for (INT32 i = 0; i < 10; i++) {
input.buttons |= (DrvJoy[i] & 1) << i;
}
GbaCoreSetInput(Gba, &input);
INT32 runAhead = bBurnRunAheadFrame != 0;
double audioRate = nBurnSoundLen > 0 ? DrvAudioRate() : 0.0;
if (GbaCoreConfigureAudio(Gba, audioRate, nBurnSoundLen, !runAhead && nBurnSoundLen > 0))
return 1;
if (GbaCoreRunFrame(Gba))
return 1;
if (!runAhead && GbaCoreRenderAudio(Gba, pBurnSoundOut, nBurnSoundLen) != nBurnSoundLen)
return 1;
if (pBurnDraw) {
DrvDraw();
}
return 0;
}
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
if (pnMin) {
*pnMin = 0x029698;
}
if ((nAction & ACB_VOLATILE) && Gba && DrvState) {
SCAN_VAR(DrvSolar);
if (nAction & ACB_WRITE) {
if (DrvSolar > GBA_SOLAR_LEVEL_MAX)
DrvSolar = GbaSolarLegacyToLevel(DrvSolar);
DrvSolarUpLast = DrvSolarUp;
DrvSolarDownLast = DrvSolarDown;
ScanVar(DrvState, DrvStateSize, "gba_machine");
if (GbaCoreLoadState(Gba, DrvState, DrvStateSize, (nAction & ACB_RUNAHEAD) != 0))
return 1;
} else {
if (GbaCoreSaveState(Gba, DrvState, DrvStateSize))
return 1;
ScanVar(DrvState, DrvStateSize, "gba_machine");
}
}
if ((nAction & ACB_NVRAM) && Gba && DrvBattery && DrvBatterySize > 0) {
if (nAction & ACB_WRITE) {
ScanVar(DrvBattery, DrvBatterySize, "gba_battery");
if (GbaCoreLoadBattery(Gba, DrvBattery, DrvBatterySize))
return 1;
} else {
memcpy(DrvBattery, GbaCoreGetBatteryDataConst(Gba), DrvBatterySize);
ScanVar(DrvBattery, DrvBatterySize, "gba_battery");
if (!(nAction & ACB_RUNAHEAD))
GbaCoreClearBatteryDirty(Gba);
}
}
return 0;
}
static INT32 GbaGetZipName(char **pszName, UINT32 i)
{
static char szFilename[MAX_PATH];
char *pszGameName = NULL;
if (pszName == NULL)
return 1;
if (i == 0) {
pszGameName = BurnDrvGetTextA(DRV_NAME);
} else if (i == 1 && BurnDrvGetTextA(DRV_BOARDROM)) {
pszGameName = BurnDrvGetTextA(DRV_BOARDROM);
} else {
pszGameName = BurnDrvGetTextA(DRV_PARENT);
}
if (pszGameName == NULL || i > 2) {
*pszName = NULL;
return 1;
}
strncpy(szFilename, pszGameName, MAX_PATH - 1);
szFilename[MAX_PATH - 1] = 0;
if (strncmp(szFilename, "gba_", 4) == 0) {
memmove(szFilename, szFilename + 4, strlen(szFilename + 4) + 1);
}
*pszName = szFilename;
return 0;
}
static struct BurnRomInfo emptyRomDesc[] = {
{ "", 0, 0, 0 },
};
static struct BurnRomInfo gba_gbaRomDesc[] = {
{ "gba_gba.bin", 0x4000, 0x81977335, BRF_PRG | BRF_BIOS | BRF_OPT },
};
STD_ROM_PICK(gba_gba)
STD_ROM_FN(gba_gba)
struct BurnDriver BurnDrvgba_gba = {
"gba_gba", NULL, NULL, NULL, "2001",
"Game Boy Advance BIOS\0", "Optional BIOS, bundled replacement is used when absent", "Nintendo", "Game Boy Advance",
NULL, NULL, NULL, NULL,
BDF_BOARDROM, 0, HARDWARE_GBA, GBF_BIOS, 0,
GbaGetZipName, gba_gbaRomInfo, gba_gbaRomName, NULL, NULL, NULL, NULL, GbaInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0,
GBA_WIDTH, GBA_HEIGHT, 3, 2
};
// =========================================================================================
// Please use short names from the MAME softwarelist/gba set wherever possible.
// Avoid excessively‑long titles that contradict the intent of the short‑name identifiers.
// [Example] Fire Emblem : The Sacred Stones(USA, Australia)
// ShortName: gba_firembssu
// =========================================================================================
// Fire Emblem: The Sacred Stones (USA, Australia)
static struct BurnRomInfo gba_firembssuRomDesc[] = {
{ "Fire Emblem - The Sacred Stones (U, A)(2005)(Nintendo).gba", 0x1000000, 0xa47246ae, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(gba_firembssu, gba_firembssu, gba_gba)
STD_ROM_FN(gba_firembssu)
struct BurnDriver BurnDrvgba_firembssu = {
"gba_firembssu", NULL, "gba_gba", NULL, "2005",
"Fire Emblem: The Sacred Stones (USA, Australia)\0", NULL, "Nintendo", "Game Boy Advance",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 1, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_GBA, GBF_RPG | GBF_STRATEGY, 0,
GbaGetZipName, gba_firembssuRomInfo, gba_firembssuRomName, NULL, NULL, NULL, NULL, GbaInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0,
GBA_WIDTH, GBA_HEIGHT, 3, 2
};
// Fire Emblem: Seima no Kouseki (Japan)
static struct BurnRomInfo gba_firembssjRomDesc[] = {
{ "Fire Emblem - Seima no Kouseki (J)(2004)(Nintendo).gba", 0x1000000, 0x9d76826f, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(gba_firembssj, gba_firembssj, gba_gba)
STD_ROM_FN(gba_firembssj)
struct BurnDriver BurnDrvgba_firembssj = {
"gba_firembssj", "gba_firembssu", "gba_gba", NULL, "2004",
"Fire Emblem: Seima no Kouseki (Japan)\0", NULL, "Nintendo", "Game Boy Advance",
L"Fire Emblem: Seima no Kouseki (Japan)\0\u30d5\u30a1\u30a4\u30a2\u30fc\u30a8\u30e0\u30d6\u30ec\u30e0 \u8056\u9b54\u306e\u5149\u77f3\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE, 1, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_GBA, GBF_RPG | GBF_STRATEGY, 0,
GbaGetZipName, gba_firembssjRomInfo, gba_firembssjRomName, NULL, NULL, NULL, NULL, GbaInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0,
GBA_WIDTH, GBA_HEIGHT, 3, 2
};
// Fire Emblem: Sheng Xie De Yi Zhi (Hack, v1.4)
static struct BurnRomInfo gba_firembssxRomDesc[] = {
{ "Fire Emblem - Sheng Xie De Yi Zhi (C)(2006)(ChinaFE & Wolf Group).gba", 0x1000000, 0x9cbb923e, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(gba_firembssx, gba_firembssx, gba_gba)
STD_ROM_FN(gba_firembssx)
struct BurnDriver BurnDrvgba_firembssx = {
"gba_firembssx", "gba_firembssu", "gba_gba", NULL, "2006",
"Fire Emblem: Sheng Xie De Yi Zhi (Hack, v1.4)\0", NULL, "ChinaFE & Wolf Group", "Game Boy Advance",
L"Fire Emblem: Sheng Xie De Yi Zhi (Hack, v1.4)\0\u706b\u7130\u4e4b\u7eb9\u7ae0: \u5723\u90aa\u7684\u610f\u5fd7\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 1, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_GBA, GBF_RPG | GBF_STRATEGY, 0,
GbaGetZipName, gba_firembssxRomInfo, gba_firembssxRomName, NULL, NULL, NULL, NULL, GbaInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0,
GBA_WIDTH, GBA_HEIGHT, 3, 2
};
// WarioWare: Twisted! (USA, Australia)
// Gyro sensor
static struct BurnRomInfo gba_wariotwsRomDesc[] = {
{ "WarioWare ‑ Twisted! (U, A)(2005)(Nintendo).gba", 0x1000000, 0xcb4e844b, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(gba_wariotws, gba_wariotws, gba_gba)
STD_ROM_FN(gba_wariotws)
struct BurnDriver BurnDrvgba_wariotws = {
"gba_wariotws", NULL, "gba_gba", NULL, "2005",
"WarioWare: Twisted! (USA, Australia)\0", NULL, "Nintendo", "Game Boy Advance",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 1, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_GBA, GBF_MISC, 0,
GbaGetZipName, gba_wariotwsRomInfo, gba_wariotwsRomName, NULL, NULL, NULL, NULL, GyroInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0,
GBA_WIDTH, GBA_HEIGHT, 3, 2
};
// Mawaru: Made in Wario (Japan)
// Gyro sensor
static struct BurnRomInfo gba_wariotwjRomDesc[] = {
{"Mawaru - Made in Wario (J)(2005)(Nintendo).gba", 0x1000000, 0xe69964f1, BRF_ESS | BRF_PRG},
};
STDROMPICKEXT(gba_wariotwj, gba_wariotwj, gba_gba)
STD_ROM_FN(gba_wariotwj)
struct BurnDriver BurnDrvGbaMawaruWario = {
"gba_wariotwj", "gba_wariotws", "gba_gba", NULL, "2005",
"Mawaru: Made in Wario (Japan)\0", NULL, "Nintendo", "Game Boy Advance",
L"Mawaru: Made in Wario (Japan)\0\u307e\u308f\u308b\u30e1\u30a4\u30c9\u30a4\u30f3\u30ef\u30ea\u30aa\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE, 1, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_GBA, GBF_MISC, 0,
GbaGetZipName, gba_wariotwjRomInfo, gba_wariotwjRomName, NULL, NULL, NULL, NULL, GyroInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0,
GBA_WIDTH, GBA_HEIGHT, 3, 2
};
// Yoshi Topsy: Turvy (USA)
static struct BurnRomInfo gba_yoshittRomDesc[] = {
{ "Yoshi Topsy ‑ Turvy (U)(2005)(Nintendo).gba", 0x800000, 0xe64c265c, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(gba_yoshitt, gba_yoshitt, gba_gba)
STD_ROM_FN(gba_yoshitt)
struct BurnDriver BurnDrvgba_yoshitt = {
"gba_yoshitt", NULL, "gba_gba", NULL, "2005",
"Yoshi Topsy: Turvy (USA)\0", NULL, "Nintendo", "Game Boy Advance",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 1, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_GBA, GBF_PLATFORM, 0,
GbaGetZipName, gba_yoshittRomInfo, gba_yoshittRomName, NULL, NULL, NULL, NULL, TiltInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0,
GBA_WIDTH, GBA_HEIGHT, 3, 2
};
// Yoshi no Banyuuinryoku (Japan)
// Tilt sensor
static struct BurnRomInfo gba_yoshibanRomDesc[] = {
{ "Yoshi no Banyuuinryoku (J)(2005)(Nintendo).gba", 0x800000, 0x31594b7a, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(gba_yoshiban, gba_yoshiban, gba_gba)
STD_ROM_FN(gba_yoshiban)
struct BurnDriver BurnDrvgba_yoshiban = {
"gba_yoshiban", "gba_yoshitt", "gba_gba", NULL, "2005",
"Yoshi no Banyuuinryoku (Japan)\0", NULL, "Nintendo", "Game Boy Advance",
L"Yoshi no Banyuuinryoku (Japan)\0\u30e8\u30c3\u30b7\u30fc\u306e\u4e07\u6709\u5f15\u529b\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE, 1, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_GBA, GBF_PLATFORM, 0,
GbaGetZipName, gba_yoshibanRomInfo, gba_yoshibanRomName, NULL, NULL, NULL, NULL, TiltInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0,
GBA_WIDTH, GBA_HEIGHT, 3, 2
};
// Boktai 2: Solar Boy Django (USA)
// Solar sensor + RTC clock
static struct BurnRomInfo gba_boktai2uRomDesc[] = {
{ "Boktai 2 ‑ Solar Boy Django (U)(2004)(Konami).gba", 0x1000000, 0xe1ffb2d1, BRF_ESS | BRF_PRG },
};
STDROMPICKEXT(gba_boktai2u, gba_boktai2u, gba_gba)
STD_ROM_FN(gba_boktai2u)
struct BurnDriver BurnDrvgba_boktai2u = {
"gba_boktai2u", NULL, "gba_gba", NULL, "2004",
"Boktai 2: Solar Boy Django (USA)\0", NULL, "Konami", "Game Boy Advance",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 1, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_GBA, GBF_ACTION | GBF_RPG, 0,
GbaGetZipName, gba_boktai2uRomInfo, gba_boktai2uRomName, NULL, NULL, NULL, NULL, SolarInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0,
GBA_WIDTH, GBA_HEIGHT, 3, 2
};
// Zoku Bokura no Taiyou: Taiyou Shounen Django (Japan, Rev 1)
// Solar light‑sensor + RTC clock
static struct BurnRomInfo gba_boktai2jRomDesc[] = {
{"Zoku Bokura no Taiyou - Taiyou Shounen Django (J, Rev 1)(2004)(Konami).gba", 0x1000000, 0x71e2cd01, BRF_ESS | BRF_PRG},
};
STDROMPICKEXT(gba_boktai2j, gba_boktai2j, gba_gba)
STD_ROM_FN(gba_boktai2j)
struct BurnDriver BurnDrvGbaBoktai2j = {
"gba_boktai2j", "gba_boktai2u", "gba_gba", NULL, "2004",
"Zoku Bokura no Taiyou: Taiyou Shounen Django (Japan, Rev 1)\0", NULL, "Konami", "Game Boy Advance",
L"Zoku Bokura no Taiyou: Taiyou Shounen Django (Japan, Rev 1)\0\u7d9a \u30dc\u30af\u3089\u306e\u592a\u967d \u592a\u967d\u5c11\u5e74\u30b8\u30e3\u30f3\u30b4\0", NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE, 1, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_GBA, GBF_ACTION | GBF_RPG, 0,
GbaGetZipName, gba_boktai2jRomInfo, gba_boktai2jRomName, NULL, NULL, NULL, NULL, SolarInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0,
GBA_WIDTH, GBA_HEIGHT, 3, 2
};
+498
View File
@@ -0,0 +1,498 @@
#ifndef GBA_STANDALONE
#include "burnint.h"
#else
#include <stdlib.h>
#define BurnMalloc(x) malloc(x)
#define BurnFree(x) do { free(x); (x) = NULL; } while (0)
#endif
#include "gba.h"
#include "gba_impl.h"
struct GbaCore {
gba_t state;
gba_scratch_t scratch;
sb_emu_state_t host;
UINT8* rom;
size_t romSize;
bool ownsRom;
UINT8 externalBios[16 * 1024];
bool externalBiosLoaded;
UINT32 cartridgeFeatures;
UINT8 cartridgeBackupType;
double sourceRate;
INT32 outputFrames;
};
struct GbaCartridgeProfile {
UINT8 gameCode[4];
UINT32 features;
UINT8 backupType;
};
static const UINT8 GbaSolarCounts[GBA_SOLAR_LEVEL_MAX + 1] = {
233, 228, 222, 215, 206, 191, 171, 149, 124, 94, 50
};
INT32 GbaMotionAxisToInput(UINT16 axis)
{
return (INT32)(((INT64)(INT32(axis) - 0x8000)) * 0x10000);
}
UINT8 GbaSolarLevelToInput(UINT8 level)
{
if (level > GBA_SOLAR_LEVEL_MAX)
level = GBA_SOLAR_LEVEL_MAX;
return (UINT8)(((233 - GbaSolarCounts[level]) * 255) / 183);
}
UINT8 GbaSolarLegacyToLevel(UINT16 legacy)
{
UINT8 input = legacy >> 8;
INT32 count = 233 - (input * 183) / 255;
UINT8 closest = 0;
INT32 closestDistance = count - GbaSolarCounts[0];
if (closestDistance < 0)
closestDistance = -closestDistance;
for (UINT8 level = 1; level <= GBA_SOLAR_LEVEL_MAX; level++) {
INT32 distance = count - GbaSolarCounts[level];
if (distance < 0)
distance = -distance;
if (distance < closestDistance) {
closest = level;
closestDistance = distance;
}
}
return closest;
}
static const GbaCartridgeProfile GbaCartridgeProfiles[] = {
{{'U', '3', 'I', 'J'}, GBA_CART_RTC | GBA_CART_SOLAR, GBA_BACKUP_EEPROM },
{{'U', '3', 'I', 'E'}, GBA_CART_RTC | GBA_CART_SOLAR, GBA_BACKUP_EEPROM },
{{'U', '3', 'I', 'P'}, GBA_CART_RTC | GBA_CART_SOLAR, GBA_BACKUP_EEPROM },
{{'U', '3', '2', 'J'}, GBA_CART_RTC | GBA_CART_SOLAR, GBA_BACKUP_EEPROM },
{{'U', '3', '2', 'E'}, GBA_CART_RTC | GBA_CART_SOLAR, GBA_BACKUP_EEPROM },
{{'U', '3', '2', 'P'}, GBA_CART_RTC | GBA_CART_SOLAR, GBA_BACKUP_EEPROM },
{{'U', '3', '3', 'J'}, GBA_CART_RTC | GBA_CART_SOLAR, GBA_BACKUP_EEPROM },
{{'V', '4', '9', 'J'}, GBA_CART_RUMBLE, GBA_BACKUP_SRAM },
{{'V', '4', '9', 'E'}, GBA_CART_RUMBLE, GBA_BACKUP_SRAM },
{{'V', '4', '9', 'P'}, GBA_CART_RUMBLE, GBA_BACKUP_SRAM },
{{'2', 'G', 'B', 'P'}, GBA_CART_RUMBLE, GBA_BACKUP_SRAM },
{{'R', 'Z', 'W', 'J'}, GBA_CART_RUMBLE | GBA_CART_GYRO, GBA_BACKUP_SRAM },
{{'R', 'Z', 'W', 'E'}, GBA_CART_RUMBLE | GBA_CART_GYRO, GBA_BACKUP_SRAM },
{{'R', 'Z', 'W', 'P'}, GBA_CART_RUMBLE | GBA_CART_GYRO, GBA_BACKUP_SRAM },
{{'K', 'H', 'P', 'J'}, GBA_CART_TILT, GBA_BACKUP_EEPROM },
{{'K', 'Y', 'G', 'J'}, GBA_CART_TILT, GBA_BACKUP_EEPROM },
{{'K', 'Y', 'G', 'E'}, GBA_CART_TILT, GBA_BACKUP_EEPROM },
{{'K', 'Y', 'G', 'P'}, GBA_CART_TILT, GBA_BACKUP_EEPROM },
{{'B', 'L', 'J', 'J'}, GBA_CART_RTC, GBA_BACKUP_FLASH_64K },
{{'B', 'L', 'J', 'K'}, GBA_CART_RTC, GBA_BACKUP_FLASH_64K },
{{'B', 'L', 'V', 'J'}, GBA_CART_RTC, GBA_BACKUP_FLASH_64K },
{{'A', 'X', 'V', 'J'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'V', 'E'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'V', 'P'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'V', 'I'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'V', 'S'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'V', 'D'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'V', 'F'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'P', 'J'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'P', 'E'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'P', 'P'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'P', 'I'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'P', 'S'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'P', 'D'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'A', 'X', 'P', 'F'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'B', 'P', 'E', 'J'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'B', 'P', 'E', 'E'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'B', 'P', 'E', 'P'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'B', 'P', 'E', 'I'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'B', 'P', 'E', 'S'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'B', 'P', 'E', 'D'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'B', 'P', 'E', 'F'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
{{'B', 'R', '4', 'J'}, GBA_CART_RTC, GBA_BACKUP_FLASH_64K },
{{'B', 'K', 'A', 'J'}, GBA_CART_RTC, GBA_BACKUP_FLASH_128K},
};
static const GbaCartridgeProfile *GbaFindCartridgeProfile(const UINT8 *rom, size_t romSize)
{
if (rom == NULL || romSize < 0xb3 || rom[0xb2] != 0x96)
return NULL;
for (UINT32 i = 0; i < sizeof(GbaCartridgeProfiles) / sizeof(GbaCartridgeProfiles[0]); i++) {
if (memcmp(rom + 0xac, GbaCartridgeProfiles[i].gameCode, 4) == 0) {
return &GbaCartridgeProfiles[i];
}
}
return NULL;
}
static UINT32 GbaDetectCartridgeFeatures(const UINT8 *rom, size_t romSize)
{
const GbaCartridgeProfile *profile = GbaFindCartridgeProfile(rom, romSize);
return profile ? profile->features : 0;
}
static UINT8 GbaDetectCartridgeBackupType(const UINT8 *rom, size_t romSize)
{
const GbaCartridgeProfile *profile = GbaFindCartridgeProfile(rom, romSize);
return profile ? profile->backupType : 0;
}
static void GbaCoreClearPresentation(GbaCore *core)
{
if (core == NULL)
return;
core->host.audio_ring_buff.read_ptr = 0;
core->host.audio_ring_buff.write_ptr = 0;
}
static void GbaCoreApplyCartridgeFeatures(GbaCore *core)
{
core->state.cart.features = core->cartridgeFeatures;
if (core->cartridgeBackupType != GBA_BACKUP_NONE) {
core->state.cart.backup_type = core->cartridgeBackupType;
gba_setup_flash_id(&core->state);
}
gba_gpio_update_rumble(&core->state);
core->host.joy.rumble = core->state.cart.gpio.rumble;
}
static void GbaCoreApplyInput(GbaCore *core, const GbaInput *input)
{
memset(core->host.joy.inputs, 0, sizeof(core->host.joy.inputs));
core->host.joy.gyro_z = 0;
core->host.joy.tilt_x = 0;
core->host.joy.tilt_y = 0;
if (input == NULL)
return;
core->host.joy.inputs[SE_KEY_A ] = (input->buttons >> GBA_BUTTON_A ) & 1;
core->host.joy.inputs[SE_KEY_B ] = (input->buttons >> GBA_BUTTON_B ) & 1;
core->host.joy.inputs[SE_KEY_SELECT] = (input->buttons >> GBA_BUTTON_SELECT) & 1;
core->host.joy.inputs[SE_KEY_START ] = (input->buttons >> GBA_BUTTON_START ) & 1;
core->host.joy.inputs[SE_KEY_RIGHT ] = (input->buttons >> GBA_BUTTON_RIGHT ) & 1;
core->host.joy.inputs[SE_KEY_LEFT ] = (input->buttons >> GBA_BUTTON_LEFT ) & 1;
core->host.joy.inputs[SE_KEY_UP ] = (input->buttons >> GBA_BUTTON_UP ) & 1;
core->host.joy.inputs[SE_KEY_DOWN ] = (input->buttons >> GBA_BUTTON_DOWN ) & 1;
core->host.joy.inputs[SE_KEY_R ] = (input->buttons >> GBA_BUTTON_R ) & 1;
core->host.joy.inputs[SE_KEY_L ] = (input->buttons >> GBA_BUTTON_L ) & 1;
core->host.joy.solar_sensor = input->solar / 255.0f;
core->host.joy.gyro_z = input->gyroZ;
core->host.joy.tilt_x = input->tiltX;
core->host.joy.tilt_y = input->tiltY;
}
INT32 GbaCoreInit(GbaCore **core)
{
if (core == NULL)
return 1;
*core = (GbaCore *)BurnMalloc(sizeof(GbaCore));
if (*core == NULL)
return 1;
memset(*core, 0, sizeof(GbaCore));
(*core)->host.render_frame = true;
(*core)->host.capture_audio = true;
return 0;
}
void GbaCoreExit(GbaCore **core)
{
if (core == NULL || *core == NULL)
return;
gba_unload(&(*core)->state, &(*core)->scratch);
if ((*core)->ownsRom)
BurnFree((*core)->rom);
BurnFree(*core);
}
INT32 GbaCoreLoadRom(GbaCore *core, const UINT8 *rom, size_t romSize, const GbaRtcSeed *rtcSeed)
{
if (core == NULL || rom == NULL || romSize == 0 || romSize > 32 * 1024 * 1024)
return 1;
const size_t allocSize = romSize < 0x100 ? 0x100 : romSize;
UINT8 *romCopy = (UINT8 *)BurnMalloc((INT32)allocSize);
if (romCopy == NULL)
return 1;
memset(romCopy, 0xff, allocSize);
memcpy(romCopy, rom, romSize);
if (core->ownsRom)
BurnFree(core->rom);
core->rom = romCopy;
core->romSize = romSize;
core->ownsRom = true;
core->cartridgeFeatures = GbaDetectCartridgeFeatures(core->rom, core->romSize);
core->cartridgeBackupType = GbaDetectCartridgeBackupType(core->rom, core->romSize);
rom = core->rom;
core->host.rom_data = core->rom;
core->host.rom_size = romSize;
core->host.bios_data = core->externalBiosLoaded ? core->externalBios : NULL;
core->host.bios_size = core->externalBiosLoaded ? sizeof(core->externalBios) : 0;
core->host.rom_loaded = true;
strcpy(core->host.rom_path, "fbneo.gba");
gba_host_loading = &core->host;
const bool loaded = gba_load_rom(&core->host, &core->state, &core->scratch);
gba_host_loading = NULL;
if (!loaded)
return 1;
gba_rtc_civil_t seed;
memset(&seed, 0, sizeof(seed));
if (rtcSeed) {
seed.year = rtcSeed->year;
seed.month = rtcSeed->month;
seed.day = rtcSeed->day;
seed.weekday = rtcSeed->weekday;
seed.hour = rtcSeed->hour;
seed.minute = rtcSeed->minute;
seed.second = rtcSeed->second;
}
gba_rtc_cold_init(&core->state.rtc, rtcSeed ? &seed : NULL);
GbaCoreApplyCartridgeFeatures(core);
GbaCoreRebind(core);
GbaCoreClearPresentation(core);
return 0;
}
INT32 GbaCoreLoadBios(GbaCore *core, const UINT8 *bios, size_t biosSize)
{
if (core == NULL || bios == NULL || biosSize != sizeof(core->externalBios))
return 1;
memcpy(core->externalBios, bios, sizeof(core->externalBios));
core->externalBiosLoaded = true;
return 0;
}
INT32 GbaCoreReset(GbaCore *core)
{
if (core == NULL || core->rom == NULL)
return 1;
UINT8 battery[GBA_BATTERY_CAPACITY];
INT64 rtcSeconds = core->state.rtc.rtc_seconds;
INT64 rtcHostSeconds = core->state.rtc.host_seconds;
UINT8 rtcStatus = core->state.rtc.status;
memcpy(battery, core->state.mem.cart_backup, sizeof(battery));
core->host.rom_data = core->rom;
core->host.rom_size = core->romSize;
core->host.bios_data = core->externalBiosLoaded ? core->externalBios : NULL;
core->host.bios_size = core->externalBiosLoaded ? sizeof(core->externalBios) : 0;
gba_host_loading = &core->host;
const bool loaded = gba_load_rom(&core->host, &core->state, &core->scratch);
gba_host_loading = NULL;
if (!loaded)
return 1;
memcpy(core->state.mem.cart_backup, battery, sizeof(battery));
core->state.rtc.rtc_seconds = rtcSeconds;
core->state.rtc.host_seconds = rtcHostSeconds;
core->state.rtc.status = rtcStatus;
gba_rtc_transport_reset(&core->state.rtc);
core->state.rtc.last_pins = 0;
GbaCoreApplyCartridgeFeatures(core);
GbaCoreRebind(core);
GbaCoreClearAudio(core);
return 0;
}
void GbaCoreSetInput(GbaCore *core, const GbaInput *input)
{
if (core != NULL)
GbaCoreApplyInput(core, input);
}
INT32 GbaCoreConfigureAudio(GbaCore *core, double sourceRate, INT32 outputFrames, INT32 captureAudio)
{
if (core == NULL)
return 1;
if (sourceRate < 0.0 || outputFrames < 0)
return 1;
if ((sourceRate <= 0.0) != (outputFrames <= 0))
return 1;
core->host.capture_audio = captureAudio != 0;
if (sourceRate != core->sourceRate || outputFrames != core->outputFrames) {
core->sourceRate = sourceRate;
core->outputFrames = outputFrames;
core->host.audio_sample_rate = sourceRate;
GbaCoreClearPresentation(core);
}
return 0;
}
INT32 GbaCoreRunFrame(GbaCore *core)
{
if (core == NULL || core->rom == NULL)
return 1;
core->host.render_frame = true;
gba_tick(&core->host, &core->state, &core->scratch);
return 0;
}
UINT32 GbaCoreGetCartridgeFeatures(const GbaCore *core)
{
return core == NULL ? 0 : core->cartridgeFeatures;
}
UINT8 GbaCoreGetRumbleOutput(const GbaCore *core)
{
if (core == NULL || !(core->state.cart.features & GBA_CART_RUMBLE))
return 0;
return core->state.cart.gpio.rumble;
}
const UINT32 *GbaCoreGetFramebuffer(const GbaCore *core)
{
return core == NULL ? NULL : (const UINT32 *)core->scratch.framebuffer;
}
UINT32 GbaCoreGetFramebufferPitch()
{
return GBA_WIDTH * sizeof(UINT32);
}
static INT32 GbaCoreSourceFramesAvailable(GbaCore *core)
{
return (INT32)(sb_ring_buffer_size(&core->host.audio_ring_buff) / 2);
}
INT32 GbaCoreRenderAudio(GbaCore *core, INT16 *stereo, INT32 frames)
{
if (core == NULL || frames <= 0)
return 0;
if (core->sourceRate <= 0.0) {
if (stereo != NULL)
memset(stereo, 0, frames * 2 * sizeof(INT16));
return frames;
}
sb_ring_buffer_t *ring = &core->host.audio_ring_buff;
INT32 available = GbaCoreSourceFramesAvailable(core);
INT32 produced = available < frames ? available : frames;
for (INT32 i = 0; i < produced; i++) {
UINT32 left = ring->read_ptr++ % SB_AUDIO_RING_BUFFER_SIZE;
UINT32 right = ring->read_ptr++ % SB_AUDIO_RING_BUFFER_SIZE;
if (stereo != NULL) {
stereo[i * 2 + 0] = ring->data[left];
stereo[i * 2 + 1] = ring->data[right];
}
}
if (produced < frames) {
INT32 missing = frames - produced;
if (stereo != NULL)
memset(stereo + produced * 2, 0, missing * 2 * sizeof(INT16));
ring->read_ptr += (UINT32)missing * 2;
ring->write_ptr += (UINT32)missing * 2;
}
return frames;
}
void GbaCoreClearAudio(GbaCore *core)
{
GbaCoreClearPresentation(core);
}
UINT8 *GbaCoreGetBatteryData(GbaCore *core)
{
return core == NULL ? NULL : core->state.mem.cart_backup;
}
const UINT8 *GbaCoreGetBatteryDataConst(const GbaCore *core)
{
return core == NULL ? NULL : core->state.mem.cart_backup;
}
size_t GbaCoreGetBatteryCapacity()
{
return GBA_BATTERY_CAPACITY;
}
size_t GbaCoreGetBatterySize(const GbaCore *core)
{
if (core == NULL) return 0;
switch (core->state.cart.backup_type) {
case GBA_BACKUP_EEPROM_512B: return 512;
case GBA_BACKUP_EEPROM:
case GBA_BACKUP_EEPROM_8KB: return 8 * 1024;
case GBA_BACKUP_SRAM: return 32 * 1024;
case GBA_BACKUP_FLASH_64K: return 64 * 1024;
case GBA_BACKUP_FLASH_128K: return 128 * 1024;
default: return 0;
}
}
INT32 GbaCoreLoadBattery(GbaCore *core, const UINT8 *data, size_t size)
{
if (core == NULL || data == NULL || size > GBA_BATTERY_CAPACITY)
return 1;
memset(core->state.mem.cart_backup, 0xff, GBA_BATTERY_CAPACITY);
memcpy(core->state.mem.cart_backup, data, size);
core->state.cart.backup_is_dirty = false;
return 0;
}
INT32 GbaCoreBatteryDirty(const GbaCore *core)
{
return core != NULL && core->state.cart.backup_is_dirty;
}
void GbaCoreClearBatteryDirty(GbaCore *core)
{
if (core != NULL) core->state.cart.backup_is_dirty = false;
}
size_t GbaCoreStateSize()
{
return sizeof(gba_t);
}
INT32 GbaCoreSaveState(const GbaCore *core, void *data, size_t size)
{
if (core == NULL || data == NULL || size < sizeof(gba_t))
return 1;
memcpy(data, &core->state, sizeof(gba_t));
UINT8 *state = (UINT8 *)data;
#define GBA_CLEAR_STATE_FIELD(type, base, field) memset(state + (base) + offsetof(type, field), 0, sizeof(((type *)0)->field))
const size_t mem = offsetof(gba_t, mem);
const size_t cpu = offsetof(gba_t, cpu);
GBA_CLEAR_STATE_FIELD(gba_mem_t, mem, bios);
GBA_CLEAR_STATE_FIELD(gba_mem_t, mem, cart_rom);
GBA_CLEAR_STATE_FIELD(gba_mem_t, mem, cart_backup);
GBA_CLEAR_STATE_FIELD(gba_t, 0, framebuffer);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, user_data);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, log_cmp_file);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, read8);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, read16);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, read32);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, read16_seq);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, read32_seq);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, write8);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, write16);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, write32);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, coprocessor_read);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, coprocessor_write);
GBA_CLEAR_STATE_FIELD(arm7_t, cpu, trigger_breakpoint);
#undef GBA_CLEAR_STATE_FIELD
return 0;
}
INT32 GbaCoreLoadState(GbaCore *core, const void *data, size_t size, INT32 preserveAudio)
{
if (core == NULL || data == NULL || size < sizeof(gba_t) || core->rom == NULL)
return 1;
UINT8 battery[GBA_BATTERY_CAPACITY];
memcpy(battery, core->state.mem.cart_backup, sizeof(battery));
memcpy(&core->state, data, sizeof(gba_t));
memcpy(core->state.mem.cart_backup, battery, sizeof(battery));
GbaCoreApplyCartridgeFeatures(core);
GbaCoreRebind(core);
if (!preserveAudio)
GbaCoreClearAudio(core);
return 0;
}
void GbaCoreRebind(GbaCore *core)
{
if (core == NULL)
return;
core->host.rom_data = core->rom;
core->host.rom_size = core->romSize;
core->host.bios_data = core->externalBiosLoaded ? core->externalBios : NULL;
core->host.bios_size = core->externalBiosLoaded ? sizeof(core->externalBios) : 0;
gba_ptrs_init(&core->state, &core->scratch, core->rom);
core->state.cpu.trigger_breakpoint = gba_cpu_trigger_breakpoint;
}
+104
View File
@@ -0,0 +1,104 @@
// FBNeo GBA core host API.
// Core implementation derived from SkyEmu/Cult-of-GBA; see license.txt.
#pragma once
#ifndef GBA_CORE_H
#define GBA_CORE_H
#ifndef GBA_STANDALONE_TYPES
#include "burn.h"
#else
#include <stdint.h>
typedef uint8_t UINT8;
typedef int8_t INT8;
typedef int16_t INT16;
typedef uint16_t UINT16;
typedef int32_t INT32;
typedef uint32_t UINT32;
typedef int64_t INT64;
typedef uint64_t UINT64;
#endif
#include <stddef.h>
#define GBA_WIDTH 240
#define GBA_HEIGHT 160
#define GBA_MASTER_CLOCK 16777216
#define GBA_BATTERY_CAPACITY (128 * 1024)
#define GBA_SOLAR_LEVEL_MAX 10
struct GbaCore;
enum GbaButton {
GBA_BUTTON_A = 0,
GBA_BUTTON_B,
GBA_BUTTON_SELECT,
GBA_BUTTON_START,
GBA_BUTTON_RIGHT,
GBA_BUTTON_LEFT,
GBA_BUTTON_UP,
GBA_BUTTON_DOWN,
GBA_BUTTON_R,
GBA_BUTTON_L,
};
enum GbaCartridgeFeature {
GBA_CART_RTC = 1 << 0,
GBA_CART_SOLAR = 1 << 1,
GBA_CART_RUMBLE = 1 << 2,
GBA_CART_GYRO = 1 << 3,
GBA_CART_TILT = 1 << 4,
};
struct GbaInput {
UINT16 buttons;
UINT8 solar;
INT32 gyroZ;
INT32 tiltX;
INT32 tiltY;
};
INT32 GbaMotionAxisToInput(UINT16 axis);
UINT8 GbaSolarLevelToInput(UINT8 level);
UINT8 GbaSolarLegacyToLevel(UINT16 legacy);
struct GbaRtcSeed {
UINT16 year;
UINT8 month;
UINT8 day;
UINT8 weekday;
UINT8 hour;
UINT8 minute;
UINT8 second;
};
INT32 GbaCoreInit(GbaCore **core);
void GbaCoreExit(GbaCore **core);
INT32 GbaCoreLoadRom(GbaCore *core, const UINT8 *rom, size_t romSize, const GbaRtcSeed *rtcSeed);
INT32 GbaCoreLoadBios(GbaCore *core, const UINT8 *bios, size_t biosSize);
INT32 GbaCoreReset(GbaCore *core);
void GbaCoreSetInput(GbaCore *core, const GbaInput *input);
INT32 GbaCoreConfigureAudio(GbaCore *core, double sourceRate, INT32 outputFrames, INT32 captureAudio);
INT32 GbaCoreRunFrame(GbaCore *core);
UINT32 GbaCoreGetCartridgeFeatures(const GbaCore *core);
UINT8 GbaCoreGetRumbleOutput(const GbaCore *core);
const UINT32* GbaCoreGetFramebuffer(const GbaCore* core);
UINT32 GbaCoreGetFramebufferPitch();
INT32 GbaCoreRenderAudio(GbaCore *core, INT16 *stereo, INT32 frames);
void GbaCoreClearAudio(GbaCore *core);
UINT8* GbaCoreGetBatteryData(GbaCore* core);
const UINT8* GbaCoreGetBatteryDataConst(const GbaCore* core);
size_t GbaCoreGetBatteryCapacity();
size_t GbaCoreGetBatterySize(const GbaCore *core);
INT32 GbaCoreLoadBattery(GbaCore *core, const UINT8 *data, size_t size);
INT32 GbaCoreBatteryDirty(const GbaCore *core);
void GbaCoreClearBatteryDirty(GbaCore *core);
size_t GbaCoreStateSize();
INT32 GbaCoreSaveState(const GbaCore *core, void *data, size_t size);
INT32 GbaCoreLoadState(GbaCore *core, const void *data, size_t size, INT32 preserveAudio = 0);
void GbaCoreRebind(GbaCore *core);
#endif
File diff suppressed because it is too large. Load diff
+162
View File
@@ -0,0 +1,162 @@
#pragma once
#ifndef GBA_HOST_H
#define GBA_HOST_H
#ifndef GBA_STANDALONE_TYPES
#include "burn.h"
#else
#include "gba.h"
#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#if defined(__GNUC__) || defined(__clang__)
#define FORCE_INLINE inline __attribute__((always_inline))
#define SB_UNLIKELY(x) __builtin_expect(!!(x), 0)
#define SB_LIKELY(x) __builtin_expect(!!(x), 1)
#elif defined(_MSC_VER)
#define FORCE_INLINE __forceinline
#define SB_UNLIKELY(x) (x)
#define SB_LIKELY(x) (x)
#else
#define FORCE_INLINE inline
#define SB_UNLIKELY(x) (x)
#define SB_LIKELY(x) (x)
#endif
#define SB_FILE_PATH_SIZE 1024
#define SB_BFE(VALUE, BITOFFSET, SIZE) (((VALUE) >> (BITOFFSET)) & ((1llu << (SIZE)) - 1))
#define SB_AUDIO_RING_BUFFER_SIZE (2048 * 8)
#define SE_NUM_KEYBINDS 36
#define SE_KEY_A 0
#define SE_KEY_B 1
#define SE_KEY_X 2
#define SE_KEY_Y 3
#define SE_KEY_UP 4
#define SE_KEY_DOWN 5
#define SE_KEY_LEFT 6
#define SE_KEY_RIGHT 7
#define SE_KEY_L 8
#define SE_KEY_R 9
#define SE_KEY_START 10
#define SE_KEY_SELECT 11
#define SB_MODE_PAUSE 0
typedef struct {
float inputs[SE_NUM_KEYBINDS];
float touch_pos[2];
float rumble;
float solar_sensor;
INT32 gyro_z;
INT32 tilt_x;
INT32 tilt_y;
} sb_joy_t;
typedef struct {
INT16 data[SB_AUDIO_RING_BUFFER_SIZE];
UINT32 read_ptr;
UINT32 write_ptr;
} sb_ring_buffer_t;
static FORCE_INLINE UINT32 sb_ring_buffer_size(sb_ring_buffer_t* buff)
{
if (buff->read_ptr > SB_AUDIO_RING_BUFFER_SIZE) {
buff->write_ptr -= SB_AUDIO_RING_BUFFER_SIZE;
buff->read_ptr -= SB_AUDIO_RING_BUFFER_SIZE;
}
return (buff->write_ptr - buff->read_ptr) % SB_AUDIO_RING_BUFFER_SIZE;
}
typedef struct {
INT32 run_mode;
INT32 step_instructions;
INT32 step_frames;
bool rom_loaded;
INT32 system;
sb_joy_t joy;
sb_joy_t prev_frame_joy;
INT32 frame;
bool render_frame;
bool capture_audio;
double audio_sample_rate;
sb_ring_buffer_t audio_ring_buff;
UINT32 frames_since_rewind_push;
char save_file_path[SB_FILE_PATH_SIZE];
float screen_ghosting_strength;
size_t rom_size;
UINT8* rom_data;
const UINT8* bios_data;
size_t bios_size;
char rom_path[SB_FILE_PATH_SIZE];
} sb_emu_state_t;
typedef struct {
bool read_since_reset;
bool read_in_tick;
bool write_since_reset;
bool write_in_tick;
bool trigger_breakpoint;
} sb_debug_mmio_access_t;
typedef struct {
UINT32 addr;
const char* name;
struct {
UINT8 start;
UINT8 size;
const char* name;
} bits[32];
} mmio_reg_t;
static inline bool sb_path_has_file_ext(const char* path, const char* ext)
{
if (ext[0] == '*')
ext++;
if (ext[0] == '.')
ext++;
if (ext[0] == '*')
return true;
const size_t extLen = strlen(ext);
const size_t pathLen = strlen(path);
if (pathLen < extLen)
return false;
for (size_t i = 0; i < extLen; i++) {
if (tolower((unsigned char)path[pathLen - extLen + i]) != tolower((unsigned char)ext[i]))
return false;
}
return true;
}
static UINT8* sb_load_file_data(const char*, size_t* fileSize)
{
if (fileSize)
*fileSize = 0;
return NULL;
}
static void sb_free_file_data(UINT8 *data)
{
free(data);
}
static sb_emu_state_t *gba_host_loading;
static bool se_load_bios_file(const char*, const char*, const char*, UINT8* data, size_t dataSize)
{
if (gba_host_loading == NULL || gba_host_loading->bios_data == NULL || gba_host_loading->bios_size != dataSize)
return false;
memcpy(data, gba_host_loading->bios_data, dataSize);
return true;
}
static FILE* se_load_log_file(const char*, const char*)
{
return NULL;
}
#endif
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Skyler "Sky" Saleh
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+9
View File
@@ -0,0 +1,9 @@
# Nintendo Game Boy Advance drivers
group_desc = 'Nintendo Game Boy Advance drivers'
group_srcs = [
'gba.cpp',
]
drivers = {
'd_gba.cpp': [],
}
+366
View File
@@ -0,0 +1,366 @@
#pragma once
#ifndef GBA_RTC_H
#define GBA_RTC_H
#include <time.h>
#define GBA_RTC_DAYS_1970_TO_2000 10957
#define GBA_RTC_STATUS_MASK 0x6a
#if defined(GBA_STANDALONE)
extern INT64 gba_rtc_test_now;
#define GBA_RTC_NOW_SECONDS() (gba_rtc_test_now)
#else
#define GBA_RTC_NOW_SECONDS() ((INT64)time(NULL))
#endif
enum gba_rtc_phase {
GBA_RTC_IDLE = 0,
GBA_RTC_COMMAND,
GBA_RTC_RECEIVE,
GBA_RTC_SEND,
GBA_RTC_COMPLETE,
};
enum gba_rtc_register {
GBA_RTC_RESET = 0,
GBA_RTC_UNUSED = 1,
GBA_RTC_DATE_TIME = 2,
GBA_RTC_FORCE_IRQ = 3,
GBA_RTC_STATUS = 4,
GBA_RTC_UNUSED2 = 5,
GBA_RTC_TIME = 6,
GBA_RTC_UNUSED3 = 7,
};
typedef struct {
UINT16 year;
UINT8 month;
UINT8 day;
UINT8 weekday;
UINT8 hour;
UINT8 minute;
UINT8 second;
} gba_rtc_civil_t;
typedef struct {
INT64 rtc_seconds;
INT64 host_seconds;
UINT8 status;
UINT8 phase;
UINT8 command;
UINT8 command_register;
UINT8 command_read;
UINT8 bit_index;
UINT8 byte_index;
UINT8 byte_count;
UINT8 buffer[7];
UINT8 last_pins;
UINT8 sio_out;
} gba_rtc_t;
// Howard Hinnant's days_from_civil / civil_from_days (public domain). Proleptic
// Gregorian, handles any date including 2100 (not a leap year).
static FORCE_INLINE INT32 gba_rtc_days_from_civil(INT32 y, UINT32 m, UINT32 d)
{
y -= (m <= 2);
INT32 era = (y >= 0 ? y : y - 399) / 400;
UINT32 yoe = (UINT32)(y - era * 400);
UINT32 doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;
UINT32 doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
return era * 146097 + (INT32)doe - 719468;
}
static FORCE_INLINE void gba_rtc_civil_from_days(INT32 z, INT32 *y, UINT32 *m, UINT32 *d)
{
z += 719468;
INT32 era = (z >= 0 ? z : z - 146096) / 146097;
UINT32 doe = (UINT32)(z - era * 146097);
UINT32 yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
UINT32 y0 = yoe + (UINT32)era * 400;
UINT32 doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
UINT32 mp = (5 * doy + 2) / 153;
*d = doy - (153 * mp + 2) / 5 + 1;
*m = mp + (mp < 10 ? 3 : -9);
*y = (INT32)y0 + (*m <= 2);
}
static FORCE_INLINE INT64 gba_rtc_civil_to_seconds(const gba_rtc_civil_t *c)
{
INT32 days = gba_rtc_days_from_civil((INT32)c->year, c->month, c->day) - GBA_RTC_DAYS_1970_TO_2000;
return (INT64)days * 86400 + c->hour * 3600 + c->minute * 60 + c->second;
}
static FORCE_INLINE void gba_rtc_seconds_to_civil(INT64 sec, gba_rtc_civil_t *c)
{
INT64 day = sec / 86400;
INT32 into_day = (INT32)(sec - day * 86400);
if (into_day < 0) { into_day += 86400; day -= 1; }
INT32 y;
UINT32 m, d;
gba_rtc_civil_from_days((INT32)day + GBA_RTC_DAYS_1970_TO_2000, &y, &m, &d);
if (y < 2000) y = 2000 + ((y - 2000) % 100 + 100) % 100;
else if (y > 2099) y = 2000 + ((y - 2000) % 100 + 100) % 100;
c->year = (UINT16)y;
c->month = (UINT8)m;
c->day = (UINT8)d;
c->weekday = (UINT8)(((day % 7) + 7 + 6) % 7); // 2000-01-01 = Saturday (6, 0=Sun)
c->hour = (UINT8)(into_day / 3600);
c->minute = (UINT8)((into_day % 3600) / 60);
c->second = (UINT8)(into_day % 60);
}
static FORCE_INLINE INT64 gba_rtc_current_seconds(const gba_rtc_t *rtc)
{
return rtc->rtc_seconds + (GBA_RTC_NOW_SECONDS() - rtc->host_seconds);
}
static FORCE_INLINE UINT8 gba_rtc_bcd_encode(UINT8 value)
{
return (value % 10) | ((value / 10) << 4);
}
static FORCE_INLINE INT32 gba_rtc_bcd_decode(UINT8 value, UINT8 maximum, UINT8 *result)
{
UINT8 low = value & 0x0f;
UINT8 high = (value >> 4) & 0x0f;
if (low > 9 || high > 9) return 1;
UINT8 decoded = high * 10 + low;
if (decoded > maximum) return 1;
*result = decoded;
return 0;
}
static FORCE_INLINE UINT8 gba_rtc_hour_encode(UINT8 hour_24, UINT8 status)
{
if (status & 0x40) return gba_rtc_bcd_encode(hour_24);
return gba_rtc_bcd_encode(hour_24 % 12) | (hour_24 >= 12 ? 0x80 : 0);
}
static FORCE_INLINE INT32 gba_rtc_hour_decode(UINT8 status, UINT8 value, UINT8 *hour)
{
if (status & 0x40) {
if (value & 0xc0) return 1;
return gba_rtc_bcd_decode(value, 23, hour);
}
UINT8 decoded;
if (gba_rtc_bcd_decode(value & 0x3f, 11, &decoded)) return 1;
*hour = decoded + ((value & 0x80) ? 12 : 0);
return 0;
}
static FORCE_INLINE void gba_rtc_transport_reset(gba_rtc_t *rtc)
{
rtc->phase = GBA_RTC_IDLE;
rtc->command = 0;
rtc->command_register = 0;
rtc->command_read = 0;
rtc->bit_index = 0;
rtc->byte_index = 0;
rtc->byte_count = 0;
memset(rtc->buffer, 0, sizeof(rtc->buffer));
rtc->sio_out = 1;
}
static FORCE_INLINE void gba_rtc_cold_init(gba_rtc_t *rtc, const gba_rtc_civil_t *seed)
{
memset(rtc, 0, sizeof(*rtc));
gba_rtc_civil_t fallback = { 2000, 1, 1, 0, 0, 0, 0 };
const gba_rtc_civil_t *s = (seed && seed->year >= 2000 && seed->year <= 2099 &&
seed->month >= 1 && seed->month <= 12 && seed->day >= 1 &&
seed->day <= 31 && seed->hour <= 23 && seed->minute <= 59 && seed->second <= 59) ? seed : &fallback;
rtc->rtc_seconds = gba_rtc_civil_to_seconds(s);
rtc->host_seconds = GBA_RTC_NOW_SECONDS();
rtc->status = 0x40;
gba_rtc_transport_reset(rtc);
}
static FORCE_INLINE void gba_rtc_reanchor(gba_rtc_t *rtc, INT64 rtc_seconds)
{
rtc->rtc_seconds = rtc_seconds;
rtc->host_seconds = GBA_RTC_NOW_SECONDS();
}
static FORCE_INLINE void gba_rtc_latch_read(gba_rtc_t *rtc)
{
memset(rtc->buffer, 0xff, sizeof(rtc->buffer));
switch (rtc->command_register) {
case GBA_RTC_STATUS:
rtc->byte_count = 1;
rtc->buffer[0] = rtc->status;
break;
case GBA_RTC_DATE_TIME: {
gba_rtc_civil_t c;
gba_rtc_seconds_to_civil(gba_rtc_current_seconds(rtc), &c);
rtc->byte_count = 7;
rtc->buffer[0] = gba_rtc_bcd_encode((UINT8)(c.year % 100));
rtc->buffer[1] = gba_rtc_bcd_encode(c.month);
rtc->buffer[2] = gba_rtc_bcd_encode(c.day);
rtc->buffer[3] = gba_rtc_bcd_encode(c.weekday);
rtc->buffer[4] = gba_rtc_hour_encode(c.hour, rtc->status);
rtc->buffer[5] = gba_rtc_bcd_encode(c.minute);
rtc->buffer[6] = gba_rtc_bcd_encode(c.second);
break;
}
case GBA_RTC_TIME: {
gba_rtc_civil_t c;
gba_rtc_seconds_to_civil(gba_rtc_current_seconds(rtc), &c);
rtc->byte_count = 3;
rtc->buffer[0] = gba_rtc_hour_encode(c.hour, rtc->status);
rtc->buffer[1] = gba_rtc_bcd_encode(c.minute);
rtc->buffer[2] = gba_rtc_bcd_encode(c.second);
break;
}
default:
rtc->byte_count = 0;
break;
}
}
static FORCE_INLINE INT32 gba_rtc_commit_datetime(gba_rtc_t *rtc)
{
gba_rtc_civil_t c;
gba_rtc_seconds_to_civil(gba_rtc_current_seconds(rtc), &c);
UINT8 year;
if (gba_rtc_bcd_decode(rtc->buffer[0], 99, &year)) return 1;
c.year = 2000 + year;
if (gba_rtc_bcd_decode(rtc->buffer[1], 12, &c.month) || c.month == 0) return 1;
if (gba_rtc_bcd_decode(rtc->buffer[2], 31, &c.day) || c.day == 0) return 1;
if (gba_rtc_bcd_decode(rtc->buffer[3], 6, &c.weekday)) return 1;
if (gba_rtc_hour_decode(rtc->status, rtc->buffer[4], &c.hour)) return 1;
if (gba_rtc_bcd_decode(rtc->buffer[5], 59, &c.minute)) return 1;
if (gba_rtc_bcd_decode(rtc->buffer[6], 59, &c.second)) return 1;
if (c.year < 2000 || c.year > 2099 || c.month < 1 || c.month > 12 ||
c.day < 1 || c.day > 31 || c.hour > 23) return 1;
gba_rtc_reanchor(rtc, gba_rtc_civil_to_seconds(&c));
return 0;
}
static FORCE_INLINE INT32 gba_rtc_commit_time(gba_rtc_t *rtc)
{
gba_rtc_civil_t c;
gba_rtc_seconds_to_civil(gba_rtc_current_seconds(rtc), &c);
if (gba_rtc_hour_decode(rtc->status, rtc->buffer[0], &c.hour)) return 1;
if (gba_rtc_bcd_decode(rtc->buffer[1], 59, &c.minute)) return 1;
if (gba_rtc_bcd_decode(rtc->buffer[2], 59, &c.second)) return 1;
gba_rtc_reanchor(rtc, gba_rtc_civil_to_seconds(&c));
return 0;
}
static FORCE_INLINE void gba_rtc_commit_write(gba_rtc_t *rtc)
{
switch (rtc->command_register) {
case GBA_RTC_STATUS:
rtc->status = rtc->buffer[0] & GBA_RTC_STATUS_MASK;
break;
case GBA_RTC_DATE_TIME:
gba_rtc_commit_datetime(rtc);
break;
case GBA_RTC_TIME:
gba_rtc_commit_time(rtc);
break;
}
}
static FORCE_INLINE UINT8 gba_rtc_reverse8(UINT8 value)
{
value = (value >> 4) | (value << 4);
value = ((value & 0x33) << 2) | ((value & 0xcc) >> 2);
return ((value & 0x55) << 1) | ((value & 0xaa) >> 1);
}
static FORCE_INLINE void gba_rtc_decode_command(gba_rtc_t *rtc)
{
UINT8 command = rtc->command;
if ((command & 0x0f) != 0x06 && (command & 0xf0) == 0x60) command = gba_rtc_reverse8(command);
if ((command & 0x0f) != 0x06) {
rtc->phase = GBA_RTC_COMPLETE;
return;
}
rtc->command = command;
rtc->command_register = (command >> 4) & 7;
rtc->command_read = (command >> 7) & 1;
rtc->bit_index = 0;
rtc->byte_index = 0;
memset(rtc->buffer, 0, sizeof(rtc->buffer));
if (rtc->command_register == GBA_RTC_RESET) {
if (!rtc->command_read) rtc->status = 0;
rtc->phase = GBA_RTC_COMPLETE;
return;
}
if (rtc->command_register == GBA_RTC_FORCE_IRQ || rtc->command_register == GBA_RTC_UNUSED ||
rtc->command_register == GBA_RTC_UNUSED2 || rtc->command_register == GBA_RTC_UNUSED3) {
rtc->phase = GBA_RTC_COMPLETE;
return;
}
if (rtc->command_read) {
gba_rtc_latch_read(rtc);
rtc->phase = rtc->byte_count ? GBA_RTC_SEND : GBA_RTC_COMPLETE;
} else {
rtc->byte_count = rtc->command_register == GBA_RTC_STATUS ? 1 :
rtc->command_register == GBA_RTC_DATE_TIME ? 7 :
rtc->command_register == GBA_RTC_TIME ? 3 : 0;
rtc->phase = rtc->byte_count ? GBA_RTC_RECEIVE : GBA_RTC_COMPLETE;
}
}
static FORCE_INLINE void gba_rtc_sample_input(gba_rtc_t *rtc, UINT8 sio)
{
if (rtc->phase == GBA_RTC_COMMAND) {
rtc->command |= (sio & 1) << rtc->bit_index;
if (++rtc->bit_index == 8) gba_rtc_decode_command(rtc);
return;
}
if (rtc->phase != GBA_RTC_RECEIVE) return;
rtc->buffer[rtc->byte_index] |= (sio & 1) << rtc->bit_index;
if (++rtc->bit_index < 8) return;
rtc->bit_index = 0;
if (++rtc->byte_index < rtc->byte_count) return;
gba_rtc_commit_write(rtc);
rtc->phase = GBA_RTC_COMPLETE;
}
static FORCE_INLINE void gba_rtc_shift_output(gba_rtc_t *rtc)
{
if (rtc->phase != GBA_RTC_SEND) {
rtc->sio_out = 1;
return;
}
rtc->sio_out = (rtc->buffer[rtc->byte_index] >> rtc->bit_index) & 1;
if (++rtc->bit_index < 8) return;
rtc->bit_index = 0;
if (++rtc->byte_index < rtc->byte_count) return;
rtc->phase = GBA_RTC_COMPLETE;
}
static FORCE_INLINE UINT8 gba_rtc_update_pins(gba_rtc_t *rtc, UINT8 pins)
{
UINT8 old = rtc->last_pins;
UINT8 cs = (pins >> 2) & 1;
UINT8 old_cs = (old >> 2) & 1;
UINT8 sck = pins & 1;
UINT8 old_sck = old & 1;
if (!cs) {
gba_rtc_transport_reset(rtc);
rtc->last_pins = pins;
return rtc->sio_out;
}
if (!old_cs) {
gba_rtc_transport_reset(rtc);
rtc->phase = GBA_RTC_COMMAND;
rtc->last_pins = pins;
return rtc->sio_out;
}
if (!old_sck && sck) gba_rtc_sample_input(rtc, (old >> 1) & 1);
if (old_sck && !sck) gba_rtc_shift_output(rtc);
rtc->last_pins = pins;
return rtc->sio_out;
}
#endif
+1 -1
View File
@@ -8,5 +8,5 @@ perl cave_tile_func.pl -o ../../../projectfiles/visualstudio-2010/generated/cave
perl neo_sprite_func.pl -o ../../../projectfiles/visualstudio-2010/generated/neo_sprite_func.h
perl psikyo_tile_func.pl -o ../../../projectfiles/visualstudio-2010/generated/psikyo_tile_func.h
perl toa_gp9001_func.pl -o ../../../projectfiles/visualstudio-2010/generated/toa_gp9001_func.h
perl gamelist.pl -o ../../../projectfiles/visualstudio-2010/generated/driverlist.h -l ../../../projectfiles/visualstudio-2010/generated/gamelist.txt ../../burn/drv/atari ../../burn/drv/capcom ../../burn/drv/cave ../../burn/drv/coleco ../../burn/drv/cps3 ../../burn/drv/dataeast ../../burn/drv/galaxian ../../burn/drv/irem ../../burn/drv/konami ../../burn/drv/megadrive ../../burn/drv/midway ../../burn/drv/msx ../../burn/drv/neogeo ../../burn/drv/pce ../../burn/drv/pgm ../../burn/drv/pst90s ../../burn/drv/pre90s ../../burn/drv/psikyo ../../burn/drv/sega ../../burn/drv/sg1000 ../../burn/drv/spectrum ../../burn/drv/taito ../../burn/drv/toaplan ../../burn/drv/sms ../../burn/drv/nes ../../burn/drv/snes ../../burn/drv
perl gamelist.pl -o ../../../projectfiles/visualstudio-2010/generated/driverlist.h -l ../../../projectfiles/visualstudio-2010/generated/gamelist.txt ../../burn/drv/atari ../../burn/drv/capcom ../../burn/drv/cave ../../burn/drv/coleco ../../burn/drv/cps3 ../../burn/drv/dataeast ../../burn/drv/galaxian ../../burn/drv/gba ../../burn/drv/irem ../../burn/drv/konami ../../burn/drv/megadrive ../../burn/drv/midway ../../burn/drv/msx ../../burn/drv/neogeo ../../burn/drv/pce ../../burn/drv/pgm ../../burn/drv/pst90s ../../burn/drv/pre90s ../../burn/drv/psikyo ../../burn/drv/sega ../../burn/drv/sg1000 ../../burn/drv/spectrum ../../burn/drv/taito ../../burn/drv/toaplan ../../burn/drv/sms ../../burn/drv/nes ../../burn/drv/snes ../../burn/drv
+1 -1
View File
@@ -8,4 +8,4 @@ perl cave_tile_func.pl -o ../../../projectfiles/visualstudio-2015/generated/cave
perl neo_sprite_func.pl -o ../../../projectfiles/visualstudio-2015/generated/neo_sprite_func.h
perl psikyo_tile_func.pl -o ../../../projectfiles/visualstudio-2015/generated/psikyo_tile_func.h
perl toa_gp9001_func.pl -o ../../../projectfiles/visualstudio-2015/generated/toa_gp9001_func.h
perl gamelist.pl -o ../../../projectfiles/visualstudio-2015/generated/driverlist.h -l ../../../projectfiles/visualstudio-2015/generated/gamelist.txt ../../burn/drv/atari ../../burn/drv/capcom ../../burn/drv/cave ../../burn/drv/coleco ../../burn/drv/cps3 ../../burn/drv/dataeast ../../burn/drv/galaxian ../../burn/drv/irem ../../burn/drv/konami ../../burn/drv/megadrive ../../burn/drv/midway ../../burn/drv/msx ../../burn/drv/neogeo ../../burn/drv/pce ../../burn/drv/pgm ../../burn/drv/pgm2 ../../burn/drv/pst90s ../../burn/drv/pre90s ../../burn/drv/psikyo ../../burn/drv/sega ../../burn/drv/sg1000 ../../burn/drv/spectrum ../../burn/drv/taito ../../burn/drv/toaplan ../../burn/drv/sms ../../burn/drv/nes ../../burn/drv/snes ../../burn/drv/channelf ../../burn/drv
perl gamelist.pl -o ../../../projectfiles/visualstudio-2015/generated/driverlist.h -l ../../../projectfiles/visualstudio-2015/generated/gamelist.txt ../../burn/drv/atari ../../burn/drv/capcom ../../burn/drv/cave ../../burn/drv/coleco ../../burn/drv/cps3 ../../burn/drv/dataeast ../../burn/drv/galaxian ../../burn/drv/gba ../../burn/drv/irem ../../burn/drv/konami ../../burn/drv/megadrive ../../burn/drv/midway ../../burn/drv/msx ../../burn/drv/neogeo ../../burn/drv/pce ../../burn/drv/pgm ../../burn/drv/pgm2 ../../burn/drv/pst90s ../../burn/drv/pre90s ../../burn/drv/psikyo ../../burn/drv/sega ../../burn/drv/sg1000 ../../burn/drv/spectrum ../../burn/drv/taito ../../burn/drv/toaplan ../../burn/drv/sms ../../burn/drv/nes ../../burn/drv/snes ../../burn/drv/channelf ../../burn/drv
+1 -1
View File
@@ -8,4 +8,4 @@ perl cave_tile_func.pl -o ../../../projectfiles/visualstudio-2019/generated/cave
perl neo_sprite_func.pl -o ../../../projectfiles/visualstudio-2019/generated/neo_sprite_func.h
perl psikyo_tile_func.pl -o ../../../projectfiles/visualstudio-2019/generated/psikyo_tile_func.h
perl toa_gp9001_func.pl -o ../../../projectfiles/visualstudio-2019/generated/toa_gp9001_func.h
perl gamelist.pl -o ../../../projectfiles/visualstudio-2019/generated/driverlist.h -l ../../../projectfiles/visualstudio-2019/generated/gamelist.txt ../../burn/drv/atari ../../burn/drv/capcom ../../burn/drv/cave ../../burn/drv/coleco ../../burn/drv/cps3 ../../burn/drv/dataeast ../../burn/drv/galaxian ../../burn/drv/irem ../../burn/drv/konami ../../burn/drv/megadrive ../../burn/drv/midway ../../burn/drv/msx ../../burn/drv/neogeo ../../burn/drv/pce ../../burn/drv/pgm ../../burn/drv/pgm2 ../../burn/drv/pst90s ../../burn/drv/pre90s ../../burn/drv/psikyo ../../burn/drv/sega ../../burn/drv/sg1000 ../../burn/drv/spectrum ../../burn/drv/taito ../../burn/drv/toaplan ../../burn/drv/sms ../../burn/drv/nes ../../burn/drv/snes ../../burn/drv/channelf ../../burn/drv
perl gamelist.pl -o ../../../projectfiles/visualstudio-2019/generated/driverlist.h -l ../../../projectfiles/visualstudio-2019/generated/gamelist.txt ../../burn/drv/atari ../../burn/drv/capcom ../../burn/drv/cave ../../burn/drv/coleco ../../burn/drv/cps3 ../../burn/drv/dataeast ../../burn/drv/galaxian ../../burn/drv/gba ../../burn/drv/irem ../../burn/drv/konami ../../burn/drv/megadrive ../../burn/drv/midway ../../burn/drv/msx ../../burn/drv/neogeo ../../burn/drv/pce ../../burn/drv/pgm ../../burn/drv/pgm2 ../../burn/drv/pst90s ../../burn/drv/pre90s ../../burn/drv/psikyo ../../burn/drv/sega ../../burn/drv/sg1000 ../../burn/drv/spectrum ../../burn/drv/taito ../../burn/drv/toaplan ../../burn/drv/sms ../../burn/drv/nes ../../burn/drv/snes ../../burn/drv/channelf ../../burn/drv
+1 -1
View File
@@ -8,4 +8,4 @@ perl cave_tile_func.pl -o ../../../projectfiles/visualstudio-2022/generated/cave
perl neo_sprite_func.pl -o ../../../projectfiles/visualstudio-2022/generated/neo_sprite_func.h
perl psikyo_tile_func.pl -o ../../../projectfiles/visualstudio-2022/generated/psikyo_tile_func.h
perl toa_gp9001_func.pl -o ../../../projectfiles/visualstudio-2022/generated/toa_gp9001_func.h
perl gamelist.pl -o ../../../projectfiles/visualstudio-2022/generated/driverlist.h -l ../../../projectfiles/visualstudio-2022/generated/gamelist.txt ../../burn/drv/atari ../../burn/drv/capcom ../../burn/drv/cave ../../burn/drv/coleco ../../burn/drv/cps3 ../../burn/drv/dataeast ../../burn/drv/galaxian ../../burn/drv/irem ../../burn/drv/konami ../../burn/drv/megadrive ../../burn/drv/midway ../../burn/drv/msx ../../burn/drv/neogeo ../../burn/drv/pce ../../burn/drv/pgm ../../burn/drv/pgm2 ../../burn/drv/pst90s ../../burn/drv/pre90s ../../burn/drv/psikyo ../../burn/drv/sega ../../burn/drv/sg1000 ../../burn/drv/spectrum ../../burn/drv/taito ../../burn/drv/toaplan ../../burn/drv/sms ../../burn/drv/nes ../../burn/drv/snes ../../burn/drv/channelf ../../burn/drv
perl gamelist.pl -o ../../../projectfiles/visualstudio-2022/generated/driverlist.h -l ../../../projectfiles/visualstudio-2022/generated/gamelist.txt ../../burn/drv/atari ../../burn/drv/capcom ../../burn/drv/cave ../../burn/drv/coleco ../../burn/drv/cps3 ../../burn/drv/dataeast ../../burn/drv/galaxian ../../burn/drv/gba ../../burn/drv/irem ../../burn/drv/konami ../../burn/drv/megadrive ../../burn/drv/midway ../../burn/drv/msx ../../burn/drv/neogeo ../../burn/drv/pce ../../burn/drv/pgm ../../burn/drv/pgm2 ../../burn/drv/pst90s ../../burn/drv/pre90s ../../burn/drv/psikyo ../../burn/drv/sega ../../burn/drv/sg1000 ../../burn/drv/spectrum ../../burn/drv/taito ../../burn/drv/toaplan ../../burn/drv/sms ../../burn/drv/nes ../../burn/drv/snes ../../burn/drv/channelf ../../burn/drv
+1 -1
View File
@@ -8,4 +8,4 @@ perl cave_tile_func.pl -o ../../../projectfiles/visualstudio-2026/generated/cave
perl neo_sprite_func.pl -o ../../../projectfiles/visualstudio-2026/generated/neo_sprite_func.h
perl psikyo_tile_func.pl -o ../../../projectfiles/visualstudio-2026/generated/psikyo_tile_func.h
perl toa_gp9001_func.pl -o ../../../projectfiles/visualstudio-2026/generated/toa_gp9001_func.h
perl gamelist.pl -o ../../../projectfiles/visualstudio-2026/generated/driverlist.h -l ../../../projectfiles/visualstudio-2026/generated/gamelist.txt ../../burn/drv/atari ../../burn/drv/capcom ../../burn/drv/cave ../../burn/drv/coleco ../../burn/drv/cps3 ../../burn/drv/dataeast ../../burn/drv/galaxian ../../burn/drv/irem ../../burn/drv/konami ../../burn/drv/megadrive ../../burn/drv/midway ../../burn/drv/msx ../../burn/drv/neogeo ../../burn/drv/pce ../../burn/drv/pgm ../../burn/drv/pgm2 ../../burn/drv/pst90s ../../burn/drv/pre90s ../../burn/drv/psikyo ../../burn/drv/sega ../../burn/drv/sg1000 ../../burn/drv/spectrum ../../burn/drv/taito ../../burn/drv/toaplan ../../burn/drv/sms ../../burn/drv/nes ../../burn/drv/snes ../../burn/drv/channelf ../../burn/drv
perl gamelist.pl -o ../../../projectfiles/visualstudio-2026/generated/driverlist.h -l ../../../projectfiles/visualstudio-2026/generated/gamelist.txt ../../burn/drv/atari ../../burn/drv/capcom ../../burn/drv/cave ../../burn/drv/coleco ../../burn/drv/cps3 ../../burn/drv/dataeast ../../burn/drv/galaxian ../../burn/drv/gba ../../burn/drv/irem ../../burn/drv/konami ../../burn/drv/megadrive ../../burn/drv/midway ../../burn/drv/msx ../../burn/drv/neogeo ../../burn/drv/pce ../../burn/drv/pgm ../../burn/drv/pgm2 ../../burn/drv/pst90s ../../burn/drv/pre90s ../../burn/drv/psikyo ../../burn/drv/sega ../../burn/drv/sg1000 ../../burn/drv/spectrum ../../burn/drv/taito ../../burn/drv/toaplan ../../burn/drv/sms ../../burn/drv/nes ../../burn/drv/snes ../../burn/drv/channelf ../../burn/drv