Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2020-06-17 22:32:17 -07:00
commit 393d4b4606
37 changed files with 759 additions and 559 deletions

19
CHANGES
View File

@ -25,8 +25,16 @@ Features:
Emulation fixes:
- ARM: Fix ALU reading PC after shifting
- ARM: Fix STR storing PC after address calculation
- ARM: Fix timing on Thumb shift instructions
- GB: Fix GBC game registers after skipping BIOS
- GB MBC: Support 4MB MBC30 ROMs (fixes mgba.io/i/1713)
- GB Video: Fix state after skipping BIOS (fixes mgba.io/i/1715 and mgba.io/i/1716)
- GB Video: Fix BGPS value after skipping BIOS (fixes mgba.io/i/1717)
- GBA: Add missing RTC overrides for Legendz games
- GBA: Fix timing advancing too quickly in rare cases
- GBA BIOS: Implement dummy sound driver calls
- GBA BIOS: Improve HLE BIOS timing
- GBA BIOS: Reset renderer when RegisterRamReset called (fixes mgba.io/i/1756)
- GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320)
- GBA Memory: Improve gamepak prefetch timing
- GBA SIO: Fix Multiplayer busy bit
@ -35,7 +43,14 @@ Emulation fixes:
- GBA Timers: Fix deserializing count-up timers
- GBA Video: Latch scanline at end of Hblank (fixes mgba.io/i/1319)
- GBA Video: Fix Hblank timing
- GBA Video: Fix mosaic objects drawing past the end (fixes mgba.io/i/1702)
- GBA Video: Fix disabling OBJWIN in GL renderer (fixes mgba.io/i/1759)
- GBA Video: Add missing parts of 256-color mode 0 mosaic (fixes mgba.io/1701)
- GBA Video: Fix double-size OBJ wrapping in GL renderer (fixes mgba.io/1712)
Other fixes:
- All: Improve export headers (fixes mgba.io/i/1738)
- ARM Debugger: Clear low bit on breakpoint addresses (fixes mgba.io/i/1764)
- CMake: Always use devkitPro toolchain when applicable (fixes mgba.io/i/1755)
- Core: Ensure ELF regions can be written before trying
- Core: Fix ELF loading regression (fixes mgba.io/i/1669)
- Core: Fix crash modifying hash table entry (fixes mgba.io/i/1673)
@ -44,8 +59,12 @@ Other fixes:
- Debugger: Don't skip undefined instructions when debugger attached
- Qt: Force OpenGL paint engine creation thread (fixes mgba.io/i/1642)
- Qt: Fix OpenGL 2.1 support (fixes mgba.io/i/1678)
- Qt: Fix static compilation in MinGW (fixes mgba.io/i/1769)
Misc:
- 3DS: Clean up legacy initialization (fixes mgba.io/i/1768)
- Debugger: Keep track of global cycle count
- FFmpeg: Add looping option for GIF/APNG
- GBA Serialize: Only flunk BIOS check if official BIOS was expected
- Qt: Renderer can be changed while a game is running
- Qt: Add hex index to palette view
- Qt: Add transformation matrix info to sprite view

View File

@ -9,14 +9,17 @@ if(POLICY CMP0072)
endif()
project(medusa)
set(BINARY_NAME medusa-emu CACHE INTERNAL "Name of output binaries")
set(CMAKE_C_STANDARD 99)
if(NOT MSVC)
set(GCC_STD "c99")
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
if(SWITCH)
set(GCC_STD "gnu11")
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_COMPILER_VERSION VERSION_LESS "4.3")
set(GCC_STD "gnu99")
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_EXTENSIONS ON)
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.3")
set(CMAKE_C_EXTENSIONS ON)
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-missing-field-initializers -std=${GCC_STD}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-missing-field-initializers")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS /wd4003 /wd4244 /wd4146")
endif()
@ -174,9 +177,9 @@ endif()
if(WIN32)
set(WIN32_VERSION "${LIB_VERSION_MAJOR},${LIB_VERSION_MINOR},${LIB_VERSION_PATCH}")
add_definitions(-D_WIN32_WINNT=0x0600)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
if(MSVC)
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
add_definitions(-D_UNICODE -DUNICODE)
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -municode")
@ -848,6 +851,7 @@ if(NOT SKIP_LIBRARY)
if(BUILD_SHARED)
add_library(${BINARY_NAME} SHARED ${SRC} ${VFS_SRC})
set(EXPORT_DEFINES MGBA_DLL)
if(BUILD_STATIC)
add_library(${BINARY_NAME}-static STATIC ${SRC})
target_include_directories(${BINARY_NAME}-static BEFORE PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/include)
@ -861,12 +865,10 @@ if(NOT SKIP_LIBRARY)
endif()
target_include_directories(${BINARY_NAME} BEFORE PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/include)
set_target_properties(${BINARY_NAME} PROPERTIES VERSION ${LIB_VERSION_STRING} SOVERSION ${LIB_VERSION_ABI} COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}" COMPILE_OPTIONS "${FEATURE_FLAGS}")
set_target_properties(${BINARY_NAME} PROPERTIES VERSION ${LIB_VERSION_STRING} SOVERSION ${LIB_VERSION_ABI} COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES};${EXPORT_DEFINES}" COMPILE_OPTIONS "${FEATURE_FLAGS}")
add_dependencies(${BINARY_NAME} version-info)
include(GenerateExportHeader)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/mgba-util)
generate_export_header(${BINARY_NAME} BASE_NAME MGBA STATIC_DEFINE BUILD_STATIC EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/include/mgba-util/dllexports.h)
target_link_libraries(${BINARY_NAME} ${DEBUGGER_LIB} ${DEPENDENCY_LIB} ${OS_LIB})
install(TARGETS ${BINARY_NAME} LIBRARY DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME} NAMELINK_SKIP ARCHIVE DESTINATION ${LIBDIR} RUNTIME DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME})

View File

@ -144,6 +144,8 @@ This will produce a `build-win32` directory with the build products. Replace `mg
- mgba/ubuntu:bionic
- mgba/ubuntu:cosmic
- mgba/ubuntu:disco
- mgba/ubuntu:eoan
- mgba/ubuntu:focal
- mgba/vita
- mgba/wii
- mgba/windows:w32

View File

@ -126,6 +126,8 @@ Dieser Befehl erzeugt ein Verzeichnis `build-win32` mit den erzeugten Programmda
- mgba/ubuntu:bionic
- mgba/ubuntu:cosmic
- mgba/ubuntu:disco
- mgba/ubuntu:eoan
- mgba/ubuntu:focal
- mgba/vita
- mgba/wii
- mgba/windows:w32

View File

@ -65,12 +65,7 @@ typedef intptr_t ssize_t;
#include <sys/syslimits.h>
#endif
#ifndef MGBA_STANDALONE
#include <mgba-util/dllexports.h>
#else
#define MGBA_EXPORT
#define MGBA_NO_EXPORT
#endif
#ifndef SSIZE_MAX
#define SSIZE_MAX ((ssize_t) (SIZE_MAX >> 1))

View File

@ -0,0 +1,19 @@
/* Copyright (c) 2013-2020 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MGBA_EXPORT_H
#define MGBA_EXPORT_H
#if defined(BUILD_STATIC) || !defined(_MSC_VER) || defined(MGBA_STANDALONE)
#define MGBA_EXPORT
#else
#ifdef MGBA_DLL
#define MGBA_EXPORT __declspec(dllexport)
#else
#define MGBA_EXPORT __declspec(dllimport)
#endif
#endif
#endif

View File

@ -25,6 +25,7 @@ struct mTiming {
struct mTimingEvent* root;
struct mTimingEvent* reroot;
uint64_t globalCycles;
uint32_t masterCycles;
int32_t* relativeCycles;
int32_t* nextEvent;
@ -38,6 +39,7 @@ void mTimingDeschedule(struct mTiming* timing, struct mTimingEvent*);
bool mTimingIsScheduled(const struct mTiming* timing, const struct mTimingEvent*);
int32_t mTimingTick(struct mTiming* timing, int32_t cycles);
int32_t mTimingCurrentTime(const struct mTiming* timing);
uint64_t mTimingGlobalTime(const struct mTiming* timing);
int32_t mTimingNextEvent(struct mTiming* timing);
int32_t mTimingUntil(const struct mTiming* timing, const struct mTimingEvent*);

View File

@ -10,11 +10,7 @@
extern "C" {
#endif
#ifdef MGBA_STANDALONE
#define MGBA_EXPORT
#else
#include <mgba-util/dllexports.h>
#endif
extern MGBA_EXPORT const char* const gitCommit;
extern MGBA_EXPORT const char* const gitCommitShort;

View File

@ -70,7 +70,7 @@ struct ARMCore;
union PSR {
struct {
#if defined(__POWERPC__) || defined(__PPC__)
#if defined(__BIG_ENDIAN__)
unsigned n : 1;
unsigned z : 1;
unsigned c : 1;

View File

@ -84,7 +84,7 @@ enum GBIORegisters {
REG_WX = 0x4B,
// CGB
REG_UNK4C = 0x4C,
REG_KEY0 = 0x4C,
REG_KEY1 = 0x4D,
REG_VBK = 0x4F,
REG_HDMA1 = 0x51,
@ -97,7 +97,7 @@ enum GBIORegisters {
REG_BCPD = 0x69,
REG_OCPS = 0x6A,
REG_OCPD = 0x6B,
REG_UNK6C = 0x6C,
REG_OPRI = 0x6C,
REG_SVBK = 0x70,
REG_UNK72 = 0x72,
REG_UNK73 = 0x73,

View File

@ -155,7 +155,8 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
* | bit 4: Is HDMA active?
* | bits 5 - 7: Active RTC register
* | 0x00196 - 0x00197: Reserved (leave zero)
* 0x00198 - 0x0025F: Reserved (leave zero)
* 0x00198 - 0x0019F: Global cycle counter
* 0x001A0 - 0x0025F: Reserved (leave zero)
* 0x00260 - 0x002FF: OAM
* 0x00300 - 0x0037F: I/O memory
* 0x00380 - 0x003FE: HRAM
@ -388,7 +389,9 @@ struct GBSerializedState {
uint16_t reserved;
} memory;
uint32_t reserved[50];
uint64_t globalCycles;
uint32_t reserved[48];
uint8_t oam[GB_SIZE_OAM];

View File

@ -161,6 +161,7 @@ void GBVideoInit(struct GBVideo* video);
void GBVideoReset(struct GBVideo* video);
void GBVideoDeinit(struct GBVideo* video);
void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer);
void GBVideoSkipBIOS(struct GBVideo* video);
void GBVideoProcessDots(struct GBVideo* video, uint32_t cyclesLate);
void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value);

View File

@ -193,7 +193,8 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
* | 0x002F4 - 0x002F7: GBA BIOS bus prefetch
* | 0x002F8 - 0x002FB: CPU prefecth (decode slot)
* | 0x002FC - 0x002FF: CPU prefetch (fetch slot)
* 0x00300 - 0x00317: Reserved (leave zero)
* 0x00300 - 0x0030F: Reserved (leave zero)
* 0x00310 - 0x00317: Global cycle counter
* 0x00318 - 0x0031B: Last prefetched program counter
* 0x0031C - 0x0031F: Miscellaneous flags
* | bit 0: Is CPU halted?
@ -326,8 +327,9 @@ struct GBASerializedState {
uint32_t biosPrefetch;
uint32_t cpuPrefetch[2];
uint32_t reservedCpu[6];
uint32_t reservedCpu[4];
uint64_t globalCycles;
uint32_t lastPrefetchedPc;
GBASerializedMiscFlags miscFlags;
uint32_t nextIrq;

View File

@ -6,6 +6,7 @@
#include <mgba/internal/arm/debugger/cli-debugger.h>
#include <mgba/core/core.h>
#include <mgba/core/timing.h>
#include <mgba/internal/arm/debugger/debugger.h>
#include <mgba/internal/arm/debugger/memory-debugger.h>
#include <mgba/internal/arm/decoder.h>
@ -138,6 +139,7 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
}
be->printf(be, "cpsr: ");
_printPSR(be, cpu->cpsr);
be->printf(be, "Cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.core->timing));
int instructionLength;
enum ExecutionMode mode = cpu->cpsr.t;
if (mode == MODE_ARM) {

View File

@ -171,7 +171,7 @@ ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t a
ssize_t id = debugger->nextId;
++debugger->nextId;
breakpoint->d.id = id;
breakpoint->d.address = address;
breakpoint->d.address = address & ~1; // Clear Thumb bit since it's not part of a valid address
breakpoint->d.segment = -1;
breakpoint->d.condition = NULL;
breakpoint->d.type = BREAKPOINT_SOFTWARE;
@ -187,6 +187,7 @@ static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struc
ssize_t id = debugger->nextId;
++debugger->nextId;
breakpoint->d = *info;
breakpoint->d.address &= ~1; // Clear Thumb bit since it's not part of a valid address
breakpoint->d.id = id;
if (info->type == BREAKPOINT_SOFTWARE) {
// TODO

View File

@ -157,6 +157,7 @@ DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(LSL2,
cpu->gprs[rd] = 0;
}
}
++currentCycles;
THUMB_NEUTRAL_S( , , cpu->gprs[rd]))
DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(LSR2,
@ -174,6 +175,7 @@ DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(LSR2,
cpu->gprs[rd] = 0;
}
}
++currentCycles;
THUMB_NEUTRAL_S( , , cpu->gprs[rd]))
DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ASR2,
@ -191,6 +193,7 @@ DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ASR2,
}
}
}
++currentCycles;
THUMB_NEUTRAL_S( , , cpu->gprs[rd]))
DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ADC,
@ -215,6 +218,7 @@ DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ROR,
cpu->cpsr.c = ARM_SIGN(cpu->gprs[rd]);
}
}
++currentCycles;
THUMB_NEUTRAL_S( , , cpu->gprs[rd]);)
DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(TST, int32_t aluOut = cpu->gprs[rd] & cpu->gprs[rn]; THUMB_NEUTRAL_S(cpu->gprs[rd], cpu->gprs[rn], aluOut))
DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(NEG, THUMB_SUBTRACTION(cpu->gprs[rd], 0, cpu->gprs[rn]))

View File

@ -8,6 +8,7 @@
void mTimingInit(struct mTiming* timing, int32_t* relativeCycles, int32_t* nextEvent) {
timing->root = NULL;
timing->reroot = NULL;
timing->globalCycles = 0;
timing->masterCycles = 0;
timing->relativeCycles = relativeCycles;
timing->nextEvent = nextEvent;
@ -20,6 +21,7 @@ void mTimingDeinit(struct mTiming* timing) {
void mTimingClear(struct mTiming* timing) {
timing->root = NULL;
timing->reroot = NULL;
timing->globalCycles = 0;
timing->masterCycles = 0;
}
@ -103,6 +105,10 @@ int32_t mTimingCurrentTime(const struct mTiming* timing) {
return timing->masterCycles + *timing->relativeCycles;
}
uint64_t mTimingGlobalTime(const struct mTiming* timing) {
return timing->globalCycles + *timing->relativeCycles;
}
int32_t mTimingNextEvent(struct mTiming* timing) {
struct mTimingEvent* next = timing->root;
if (!next) {

View File

@ -460,13 +460,13 @@ void GBReset(struct SM83Core* cpu) {
GBVideoReset(&gb->video);
GBTimerReset(&gb->timer);
GBIOReset(gb);
if (!gb->biosVf) {
GBSkipBIOS(gb);
} else {
mTimingSchedule(&gb->timing, &gb->timer.event, 0);
}
GBIOReset(gb);
GBAudioReset(&gb->audio);
GBSIOReset(&gb->sio);
@ -478,6 +478,7 @@ void GBReset(struct SM83Core* cpu) {
void GBSkipBIOS(struct GB* gb) {
struct SM83Core* cpu = gb->cpu;
const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
int nextDiv = 0;
switch (gb->model) {
@ -539,9 +540,15 @@ void GBSkipBIOS(struct GB* gb) {
cpu->a = 0x11;
cpu->f.packed = 0x80;
cpu->c = 0;
cpu->e = 0x08;
cpu->h = 0;
if (cart->cgb & 0x80) {
cpu->d = 0xFF;
cpu->e = 0x56;
cpu->l = 0x0D;
} else {
cpu->e = 0x08;
cpu->l = 0x7C;
}
gb->timer.internalDiv = 0x1EA;
nextDiv = 0xC;
break;
@ -554,6 +561,7 @@ void GBSkipBIOS(struct GB* gb) {
mTimingSchedule(&gb->timing, &gb->timer.event, 0);
GBIOWrite(gb, REG_LCDC, 0x91);
GBVideoSkipBIOS(&gb->video);
if (gb->biosVf) {
GBUnmapBIOS(gb);
@ -666,6 +674,9 @@ void GBProcessEvents(struct SM83Core* cpu) {
int32_t nextEvent;
cpu->cycles = 0;
#ifdef USE_DEBUGGERS
gb->timing.globalCycles += cycles;
#endif
cpu->nextEvent = INT_MAX;
nextEvent = cycles;

View File

@ -53,6 +53,7 @@ MGBA_EXPORT const char* const GBIORegisterNames[] = {
[REG_OBP1] = "OBP1",
[REG_WY] = "WY",
[REG_WX] = "WX",
[REG_KEY0] = "KEY0",
[REG_KEY1] = "KEY1",
[REG_VBK] = "VBK",
[REG_HDMA1] = "HDMA1",
@ -65,6 +66,7 @@ MGBA_EXPORT const char* const GBIORegisterNames[] = {
[REG_BCPD] = "BCPD",
[REG_OCPS] = "OCPS",
[REG_OCPD] = "OCPD",
[REG_OPRI] = "OPRI",
[REG_SVBK] = "SVBK",
[REG_IE] = "IE",
};
@ -99,7 +101,7 @@ static const uint8_t _registerMask[] = {
[REG_VBK] = 0xFE,
[REG_OCPS] = 0x40,
[REG_BCPS] = 0x40,
[REG_UNK6C] = 0xFE,
[REG_OPRI] = 0xFE,
[REG_SVBK] = 0xF8,
[REG_IE] = 0xE0,
};
@ -200,10 +202,10 @@ void GBIOReset(struct GB* gb) {
GBIOWrite(gb, REG_WY, 0x00);
GBIOWrite(gb, REG_WX, 0x00);
if (gb->model & GB_MODEL_CGB) {
GBIOWrite(gb, REG_UNK4C, 0);
GBIOWrite(gb, REG_KEY0, 0);
GBIOWrite(gb, REG_JOYP, 0xFF);
GBIOWrite(gb, REG_VBK, 0);
GBIOWrite(gb, REG_BCPS, 0);
GBIOWrite(gb, REG_BCPS, 0x80);
GBIOWrite(gb, REG_OCPS, 0);
GBIOWrite(gb, REG_SVBK, 1);
GBIOWrite(gb, REG_HDMA1, 0xFF);
@ -462,7 +464,7 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
break;
}
GBUnmapBIOS(gb);
if (gb->model >= GB_MODEL_CGB && gb->memory.io[REG_UNK4C] < 0x80) {
if (gb->model >= GB_MODEL_CGB && gb->memory.io[REG_KEY0] < 0x80) {
gb->model = GB_MODEL_DMG;
GBVideoDisableCGB(&gb->video);
}
@ -474,7 +476,7 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
default:
if (gb->model >= GB_MODEL_CGB) {
switch (address) {
case REG_UNK4C:
case REG_KEY0:
break;
case REG_KEY1:
value &= 0x1;

View File

@ -518,7 +518,7 @@ static uint8_t _GBMBC2Read(struct GBMemory* memory, uint16_t address) {
void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
int bank = value & 0x7F;
int bank = value;
switch (address >> 13) {
case 0x0:
switch (value) {
@ -536,6 +536,9 @@ void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) {
}
break;
case 0x1:
if (gb->memory.romSize < GB_SIZE_CART_BANK0 * 0x80) {
bank &= 0x7F;
}
if (!bank) {
++bank;
}

View File

@ -23,6 +23,7 @@ void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic);
STORE_32LE(gb->romCrc32, 0, &state->romCrc32);
STORE_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
STORE_64LE(gb->timing.globalCycles, 0, &state->globalCycles);
if (gb->memory.rom) {
memcpy(state->title, ((struct GBCartridge*) &gb->memory.rom[0x100])->titleLong, sizeof(state->title));
@ -150,6 +151,7 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
}
mTimingClear(&gb->timing);
LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
LOAD_64LE(gb->timing.globalCycles, 0, &state->globalCycles);
gb->cpu->a = state->cpu.a;
gb->cpu->f.packed = state->cpu.f;

View File

@ -214,6 +214,30 @@ static bool _statIRQAsserted(GBRegisterSTAT stat) {
return false;
}
void GBVideoSkipBIOS(struct GBVideo* video) {
video->mode = 1;
video->modeEvent.callback = _endMode1;
int32_t next;
if (video->p->model == GB_MODEL_CGB) {
video->ly = GB_VIDEO_VERTICAL_PIXELS;
video->p->memory.io[REG_LY] = video->ly;
video->stat = GBRegisterSTATClearLYC(video->stat);
next = 20;
} else {
video->ly = GB_VIDEO_VERTICAL_TOTAL_PIXELS;
video->p->memory.io[REG_LY] = 0;
next = 56;
}
video->stat = GBRegisterSTATSetMode(video->stat, video->mode);
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_VBLANK);
GBUpdateIRQs(video->p);
video->p->memory.io[REG_STAT] = video->stat;
mTimingDeschedule(&video->p->timing, &video->modeEvent);
mTimingSchedule(&video->p->timing, &video->modeEvent, next);
}
void _endMode0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
struct GBVideo* video = context;
if (video->frameskipCounter <= 0) {

View File

@ -177,6 +177,9 @@ static void _RegisterRamReset(struct GBA* gba) {
cpu->memory.store16(cpu, BASE_IO | 0x204, 0, 0);
cpu->memory.store16(cpu, BASE_IO | 0x208, 0, 0);
}
if (registers & 0x9C) {
gba->video.renderer->reset(gba->video.renderer);
}
}
static void _BgAffineSet(struct GBA* gba) {

View File

@ -277,12 +277,15 @@ static void GBAProcessEvents(struct ARMCore* cpu) {
do {
int32_t cycles = cpu->cycles;
cpu->cycles = 0;
#ifdef USE_DEBUGGERS
gba->timing.globalCycles += cycles;
#endif
#ifndef NDEBUG
if (cycles < 0) {
mLOG(GBA, FATAL, "Negative cycles passed: %i", cycles);
}
#endif
nextEvent = mTimingTick(&gba->timing, nextEvent + cycles);
nextEvent = mTimingTick(&gba->timing, cycles < nextEvent ? nextEvent : cycles);
} while (gba->cpuBlocked);
cpu->nextEvent = nextEvent;

View File

@ -71,6 +71,13 @@ static const struct GBACartridgeOverride _overrides[] = {
// Koro Koro Puzzle - Happy Panechu!
{ "KHPJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
// Legendz - Yomigaeru Shiren no Shima
{ "BLJJ", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false },
{ "BLJK", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false },
// Legendz - Sign of Nekuromu
{ "BLVJ", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false },
// Mega Man Battle Network
{ "AREE", SAVEDATA_SRAM, HW_NONE, 0x800032E, false },

View File

@ -1640,10 +1640,6 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB
unsigned charBase = (BASE_TILE >> 1) + (GBAObjAttributesCGetTile(sprite->c) & ~align) * 0x10;
int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x20 >> GBAObjAttributesAGet256Color(sprite->a));
if (spriteY + height >= 256) {
spriteY -= 256;
}
int totalWidth = width;
int totalHeight = height;
if (GBAObjAttributesAIsTransformed(sprite->a) && GBAObjAttributesAIsDoubleSize(sprite->a)) {
@ -1651,6 +1647,10 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB
totalHeight <<= 1;
}
if (spriteY + totalHeight >= 256) {
spriteY -= 256;
}
const struct GBAVideoGLShader* shader = &renderer->objShader[GBAObjAttributesAGet256Color(sprite->a)];
const GLuint* uniforms = shader->uniforms;
glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]);
@ -1710,7 +1710,9 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB
glUniform4i(uniforms[GBA_GL_OBJ_MOSAIC], 0, 0, 0, 0);
}
glStencilFunc(GL_ALWAYS, 1, 1);
if (GBAObjAttributesAGetMode(sprite->a) != OBJ_MODE_OBJWIN || GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt)) {
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
shader = &renderer->objShader[2];
uniforms = shader->uniforms;

View File

@ -473,8 +473,57 @@
}
#define DRAW_BACKGROUND_MODE_0_MOSAIC_256EXT(BLEND, OBJWIN) \
x = inX & 7; \
if (mosaicWait) { \
int baseX = x - (mosaicH - mosaicWait); \
if (baseX < 0) { \
int disturbX = (16 + baseX) >> 3; \
inX -= disturbX << 3; \
localX = tileX * 8 + inX; \
for (; tileX < tileEnd; ++tileX) { \
BACKGROUND_TEXT_SELECT_CHARACTER; \
localY = inY & 0x7; \
if (GBA_TEXT_MAP_VFLIP(mapData)) { \
localY = 7 - localY; \
} \
baseX -= disturbX << 3; \
inX += disturbX << 3; \
} else { \
localX = tileX * 8 + inX; \
BACKGROUND_TEXT_SELECT_CHARACTER; \
localY = inY & 0x7; \
if (GBA_TEXT_MAP_VFLIP(mapData)) { \
localY = 7 - localY; \
} \
} \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
if (UNLIKELY(charBase >= 0x10000)) { \
carryData = 0; \
} else { \
vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
LOAD_32(tileData, charBase, vram); \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
if (x >= 4) { \
LOAD_32(tileData, charBase + 4, vram); \
tileData >>= (x - 4) * 8; \
} else { \
LOAD_32(tileData, charBase, vram); \
tileData >>= x * 8; \
} \
} else { \
if (x >= 4) { \
LOAD_32(tileData, charBase, vram); \
tileData >>= (7 - x) * 8; \
} else { \
LOAD_32(tileData, charBase + 4, vram); \
tileData >>= (3 - x) * 8; \
} \
} \
tileData &= 0xFF; \
carryData = tileData; \
} \
} \
localX = tileX * 8 + inX; \
for (; length; ++tileX) { \
mapData = background->mapCache[(localX >> 3) & 0x3F]; \
localX += 8; \
localY = inY & 0x7; \
@ -484,7 +533,7 @@
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
tileData = carryData; \
for (x = 0; x < 8; ++x) { \
for (x = 0; x < 8 && length; ++x, --length) { \
if (!mosaicWait) { \
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \
palette = &mainPalette[paletteData]; \

View File

@ -326,7 +326,7 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re
int mosaicH = 1;
if (GBAObjAttributesAIsMosaic(sprite->a)) {
mosaicH = GBAMosaicControlGetObjH(renderer->mosaic) + 1;
if (condition % mosaicH) {
if (condition != end && condition % mosaicH) {
condition += mosaicH - (condition % mosaicH);
}
}

View File

@ -6,6 +6,7 @@
#include <mgba/internal/gba/serialize.h>
#include <mgba/internal/arm/macros.h>
#include <mgba/internal/gba/bios.h>
#include <mgba/internal/gba/io.h>
#include <mgba-util/memory.h>
@ -28,6 +29,7 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
STORE_32(gba->biosChecksum, 0, &state->biosChecksum);
STORE_32(gba->romCrc32, 0, &state->romCrc32);
STORE_32(gba->timing.masterCycles, 0, &state->masterCycles);
STORE_64LE(gba->timing.globalCycles, 0, &state->globalCycles);
if (gba->memory.rom) {
state->id = ((struct GBACartridge*) gba->memory.rom)->id;
@ -93,7 +95,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
mLOG(GBA_STATE, WARN, "Savestate created using a different version of the BIOS: expected %08X, got %08X", gba->biosChecksum, ucheck);
uint32_t pc;
LOAD_32(pc, ARM_PC * sizeof(state->cpu.gprs[0]), state->cpu.gprs);
if (pc < SIZE_BIOS && pc >= 0x20) {
if ((ucheck == GBA_BIOS_CHECKSUM || gba->biosChecksum == GBA_BIOS_CHECKSUM) && pc < SIZE_BIOS && pc >= 0x20) {
error = true;
}
}
@ -128,6 +130,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
}
mTimingClear(&gba->timing);
LOAD_32(gba->timing.masterCycles, 0, &state->masterCycles);
LOAD_64LE(gba->timing.globalCycles, 0, &state->globalCycles);
size_t i;
for (i = 0; i < 16; ++i) {

View File

@ -7,7 +7,7 @@ find_program(BANNERTOOL bannertool)
find_program(MAKEROM makerom)
find_program(PICASSO picasso)
find_program(RAW2C raw2c)
find_program(STRIP ${cross_prefix}strip)
set(STRIP "${cross_prefix_path}strip" CACHE INTERNAL "symbol stripper")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format" PARENT_SCOPE)
set(OS_DEFINES COLOR_16_BIT COLOR_5_6_5 IOAPI_NO_64)

View File

@ -1,92 +1,31 @@
/* This code is mostly from ctrulib, which contains the following license:
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
* The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in
a product, an acknowledgment in the product documentation would be
appreciated but is not required.
* Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
* This notice may not be removed or altered from any source distribution.
*/
#include <3ds/types.h>
#include <3ds/srv.h>
#include <3ds/gfx.h>
#include <3ds/sdmc.h>
#include <3ds/services/apt.h>
#include <3ds/services/fs.h>
#include <3ds/services/hid.h>
#include <3ds/svc.h>
/* Copyright (c) 2013-2020 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <3ds/archive.h>
#include <mgba-util/common.h>
extern char* fake_heap_start;
extern char* fake_heap_end;
extern u32 __ctru_linear_heap;
extern u32 __ctru_heap;
extern u32 __ctru_heap_size;
extern u32 __ctru_linear_heap_size;
static u32 __custom_heap_size = 0x02400000;
static u32 __custom_linear_heap_size = 0x01400000;
u32 __ctru_heap_size = 0x02400000;
u32 __ctru_linear_heap_size = 0x01400000;
uint32_t* romBuffer = NULL;
size_t romBufferSize;
FS_Archive sdmcArchive;
bool allocateRomBuffer(void) {
if (romBuffer) {
return true;
}
__attribute__((constructor)) static void init(void) {
FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""));
romBuffer = malloc(0x02000000);
if (romBuffer) {
romBufferSize = 0x02000000;
return true;
return;
}
romBuffer = malloc(0x01000000);
if (romBuffer) {
romBufferSize = 0x01000000;
return true;
return;
}
return false;
}
void __system_allocateHeaps() {
u32 tmp=0;
__ctru_heap_size = __custom_heap_size;
__ctru_linear_heap_size = __custom_linear_heap_size;
// Allocate the application heap
__ctru_heap = 0x08000000;
svcControlMemory(&tmp, __ctru_heap, 0x0, __ctru_heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE);
// Allocate the linear heap
svcControlMemory(&__ctru_linear_heap, 0x0, 0x0, __ctru_linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE);
// Set up newlib heap
fake_heap_start = (char*)__ctru_heap;
fake_heap_end = fake_heap_start + __ctru_heap_size;
}
void __appInit(void) {
// Initialize services
srvInit();
aptInit();
hidInit();
fsInit();
sdmcInit();
FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""));
allocateRomBuffer();
}

View File

@ -109,8 +109,6 @@ static bool sgbCrop = false;
static aptHookCookie cookie;
static bool core2;
extern bool allocateRomBuffer(void);
static bool _initGpu(void) {
if (!C3D_Init(C3D_DEFAULT_CMDBUF_SIZE)) {
return false;
@ -124,7 +122,7 @@ static bool _initGpu(void) {
return false;
}
if (!C3D_TexInitVRAM(&upscaleBufferTex, 512, 512, GPU_RB_RGB8)) {
if (!C3D_TexInitVRAM(&upscaleBufferTex, 512, 512, GPU_RGB8)) {
return false;
}
upscaleBuffer = C3D_RenderTargetCreateFromTex(&upscaleBufferTex, GPU_TEXFACE_2D, 0, 0);
@ -810,10 +808,6 @@ int main() {
camera.bufferSize = 0;
camera.cam = SELECT_IN1;
if (!allocateRomBuffer()) {
return 1;
}
aptHook(&cookie, _aptHook, 0);
ptmuInit();

View File

@ -8,24 +8,27 @@ set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name")
function(create_devkit DEVKIT)
if(DEFINED ENV{DEVKIT${DEVKIT}})
set(DEVKIT${DEVKIT} $ENV{DEVKIT${DEVKIT}} PARENT_SCOPE)
set(DEVKIT${DEVKIT} $ENV{DEVKIT${DEVKIT}})
else()
set(DEVKIT${DEVKIT} ${DEVKITPRO}/devkit${DEVKIT} PARENT_SCOPE)
set(DEVKIT${DEVKIT} ${DEVKITPRO}/devkit${DEVKIT})
endif()
set(DEVKIT${DEVKIT} "${DEVKIT${DEVKIT}}" PARENT_SCOPE)
set(CMAKE_PROGRAM_PATH ${DEVKIT${DEVKIT}}/bin CACHE INTERNAL "program path")
set(CMAKE_PROGRAM_PATH "${DEVKIT${DEVKIT}}/bin" CACHE INTERNAL "program path")
set(cross_prefix_path "${CMAKE_PROGRAM_PATH}/${cross_prefix}")
set(cross_prefix_path "${cross_prefix_path}" PARENT_SCOPE)
set(extension)
if (CMAKE_HOST_WIN32)
set(extension .exe)
endif()
find_program(CMAKE_AR ${cross_prefix}gcc-ar${extension})
find_program(CMAKE_RANLIB ${cross_prefix}gcc-ranlib${extension})
find_program(CMAKE_C_COMPILER ${cross_prefix}gcc${extension})
find_program(CMAKE_CXX_COMPILER ${cross_prefix}g++${extension})
find_program(CMAKE_ASM_COMPILER ${cross_prefix}gcc${extension})
find_program(CMAKE_LINKER ${cross_prefix}ld${extension})
set(CMAKE_AR "${cross_prefix_path}gcc-ar${extension}" CACHE INTERNAL "archiver")
set(CMAKE_RANLIB "${cross_prefix_path}gcc-ranlib${extension}" CACHE INTERNAL "archiver")
set(CMAKE_C_COMPILER "${cross_prefix_path}gcc${extension}" CACHE INTERNAL "c compiler")
set(CMAKE_CXX_COMPILER "${cross_prefix_path}g++${extension}" CACHE INTERNAL "cxx compiler")
set(CMAKE_ASM_COMPILER "${cross_prefix_path}gcc${extension}" CACHE INTERNAL "assembler")
set(CMAKE_LINKER "${cross_prefix_path}ld${extension}" CACHE INTERNAL "linker")
set(CMAKE_C_FLAGS ${inc_flags} CACHE INTERNAL "c compiler flags")
set(CMAKE_ASM_FLAGS ${inc_flags} CACHE INTERNAL "assembler flags")
set(CMAKE_CXX_FLAGS ${inc_flags} CACHE INTERNAL "cxx compiler flags")

View File

@ -292,7 +292,10 @@ endif()
if(QT_STATIC)
find_library(QTPCRE NAMES qtpcre2 qtpcre)
if(WIN32)
list(APPEND QT_LIBRARIES qwindows dwmapi imm32 uxtheme Qt5EventDispatcherSupport Qt5FontDatabaseSupport Qt5ThemeSupport Qt5WindowsUIAutomationSupport)
if(CMAKE_CROSSCOMPILING)
set(QWINDOWS_DEPS Qt5EventDispatcherSupport Qt5FontDatabaseSupport Qt5ThemeSupport Qt5WindowsUIAutomationSupport)
endif()
list(APPEND QT_LIBRARIES Qt5::QWindowsIntegrationPlugin ${QWINDOWS_DEPS} dwmapi uxtheme imm32 -static-libgcc -static-libstdc++)
set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE};version;winmm;ssl;crypto;ws2_32;iphlpapi;crypt32;userenv;netapi32;wtsapi32")
set_target_properties(Qt5::Gui PROPERTIES INTERFACE_LINK_LIBRARIES ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY})
elseif(APPLE)

File diff suppressed because it is too large Load Diff

View File

@ -58,10 +58,6 @@ struct PerfOpts {
bool server;
};
#ifdef _3DS
extern bool allocateRomBuffer(void);
FS_Archive sdmcArchive;
#endif
#ifdef __SWITCH__
TimeType __nx_time_type = TimeType_LocalSystemClock;
#endif
@ -85,9 +81,6 @@ int main(int argc, char** argv) {
gfxInitDefault();
osSetSpeedupEnable(true);
consoleInit(GFX_BOTTOM, NULL);
if (!allocateRomBuffer()) {
return 1;
}
#elif defined(__SWITCH__)
UNUSED(_mPerfShutdown);
consoleInit(NULL);

View File

@ -6,6 +6,7 @@
#include <mgba/internal/sm83/debugger/cli-debugger.h>
#include <mgba/core/core.h>
#include <mgba/core/timing.h>
#include <mgba/internal/debugger/cli-debugger.h>
#include <mgba/internal/sm83/decoder.h>
#include <mgba/internal/sm83/debugger/debugger.h>
@ -88,6 +89,7 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
be->printf(be, "H: %02X L: %02X (HL: %04X)\n", cpu->h, cpu->l, cpu->hl);
be->printf(be, "PC: %04X SP: %04X\n", cpu->pc, cpu->sp);
_printFlags(be, cpu->f);
be->printf(be, "T-cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.core->timing));
struct SM83Debugger* platDebugger = (struct SM83Debugger*) debugger->p->d.platform;
size_t i;