Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2021-06-29 20:33:01 -07:00
commit d026a5af75
35 changed files with 883 additions and 529 deletions

View File

@ -46,6 +46,7 @@ Other fixes:
- GBA e-Reader: Fix bitmap short strip scanning
- GBA Video: Fix mode 5 frame 1 caching (fixes mgba.io/i/2075)
- GBA Video: Don't attempt to copy invalid registers when switching renderer
- Qt: Fix crash when switching from high-resolution OpenGL renderer to software
Misc:
- Core: Truncate preloading ROMs that slightly exceed max size (fixes mgba.io/i/2093)
- GBA: Default-enable VBA bug compat for Ruby and Emerald ROM hacks

View File

@ -573,7 +573,7 @@ if(USE_FFMPEG)
endif()
include_directories(AFTER ${FFMPEG_INCLUDE_DIRS} ${LIBAVCODEC_INCLUDE_DIRS} ${LIBAVFILTER_INCLUDE_DIRS} ${LIBAVFORMAT_INCLUDE_DIRS} ${LIBAVRESAMPLE_INCLUDE_DIRS} ${LIBAVUTIL_INCLUDE_DIRS} ${LIBSWRESAMPLE_INCLUDE_DIRS} ${LIBSWSCALE_INCLUDE_DIRS})
link_directories(${FFMPEG_LIBRARY_DIRS} ${LIBAVCODEC_LIBRARY_DIRS} ${LIBAVFILTER_LIBRARY_DIRS} ${LIBAVFORMAT_LIBRARY_DIRS} ${LIBAVRESAMPLE_LIBRARY_DIRS} ${LIBAVUTIL_LIBRARY_DIRS} ${LIBSWRESAMPLE_LIBRARY_DIRS} ${LIBSWSCALE_LIBRARY_DIRS})
list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-encoder.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-decoder.c")
list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-encoder.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-decoder.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-scale.c")
list(APPEND DEPENDENCY_LIB ${FFMPEG_LIBRARIES} ${LIBAVCODEC_LIBRARIES} ${LIBAVFILTER_LIBRARIES} ${LIBAVFORMAT_LIBRARIES} ${LIBAVRESAMPLE_LIBRARIES} ${LIBAVUTIL_LIBRARIES} ${LIBSWSCALE_LIBRARIES} ${LIBSWRESAMPLE_LIBRARIES})
if(WIN32 AND NOT DEFINED VCPKG_TARGET_TRIPLET)
list(APPEND DEPENDENCY_LIB bcrypt)

View File

@ -0,0 +1,32 @@
/* Copyright (c) 2013-2021 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 CONVOLVE_H
#define CONVOLVE_H
#include <mgba-util/common.h>
CXX_GUARD_START
struct ConvolutionKernel {
float* kernel;
size_t* dims;
size_t rank;
};
void ConvolutionKernelCreate(struct ConvolutionKernel* kernel, size_t rank, size_t* dims);
void ConvolutionKernelDestroy(struct ConvolutionKernel* kernel);
void ConvolutionKernelFillRadial(struct ConvolutionKernel* kernel, bool normalize);
void ConvolutionKernelFillCircle(struct ConvolutionKernel* kernel, bool normalize);
// TODO: Make image container struct?
void Convolve1DPad0PackedS32(const int32_t* restrict src, int32_t* restrict dst, size_t length, const struct ConvolutionKernel* restrict kernel);
void Convolve2DClampPacked8(const uint8_t* restrict src, uint8_t* restrict dst, size_t width, size_t height, size_t stride, const struct ConvolutionKernel* restrict kernel);
CXX_GUARD_END
#endif

View File

@ -164,6 +164,7 @@ enum mColorFormat {
mCOLOR_BGRA5 = 0x08000,
mCOLOR_RGB8 = 0x10000,
mCOLOR_BGR8 = 0x20000,
mCOLOR_L8 = 0x40000,
mCOLOR_ANY = -1
};

View File

@ -98,7 +98,7 @@ struct GBASIOBattlechipGate {
void GBASIOBattlechipGateCreate(struct GBASIOBattlechipGate*);
void GBAEReaderQueueCard(struct GBA* gba, const void* data, size_t size);
void GBACartEReaderQueueCard(struct GBA* gba, const void* data, size_t size);
CXX_GUARD_END

View File

@ -20,7 +20,7 @@ CXX_GUARD_START
#include <mgba/internal/ds/timer.h>
#include <mgba/internal/ds/video.h>
#include <mgba/internal/ds/wifi.h>
#include <mgba/internal/gba/hardware.h>
#include <mgba/internal/gba/cart/gpio.h>
extern const uint32_t DS_ARM946ES_FREQUENCY;
extern const uint32_t DS_ARM7TDMI_FREQUENCY;

View File

@ -0,0 +1,90 @@
/* Copyright (c) 2013-2015 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 GBA_EREADER_H
#define GBA_EREADER_H
#include <mgba-util/common.h>
CXX_GUARD_START
struct GBACartridgeHardware;
#define EREADER_DOTCODE_STRIDE 1420
#define EREADER_DOTCODE_SIZE (EREADER_DOTCODE_STRIDE * 40)
#define EREADER_CARDS_MAX 16
DECL_BITFIELD(EReaderControl0, uint8_t);
DECL_BIT(EReaderControl0, Data, 0);
DECL_BIT(EReaderControl0, Clock, 1);
DECL_BIT(EReaderControl0, Direction, 2);
DECL_BIT(EReaderControl0, LedEnable, 3);
DECL_BIT(EReaderControl0, Scan, 4);
DECL_BIT(EReaderControl0, Phi, 5);
DECL_BIT(EReaderControl0, PowerEnable, 6);
DECL_BITFIELD(EReaderControl1, uint8_t);
DECL_BIT(EReaderControl1, Scanline, 1);
DECL_BIT(EReaderControl1, Unk1, 4);
DECL_BIT(EReaderControl1, Voltage, 5);
enum EReaderStateMachine {
EREADER_SERIAL_INACTIVE = 0,
EREADER_SERIAL_STARTING,
EREADER_SERIAL_BIT_0,
EREADER_SERIAL_BIT_1,
EREADER_SERIAL_BIT_2,
EREADER_SERIAL_BIT_3,
EREADER_SERIAL_BIT_4,
EREADER_SERIAL_BIT_5,
EREADER_SERIAL_BIT_6,
EREADER_SERIAL_BIT_7,
EREADER_SERIAL_END_BIT,
};
enum EReaderCommand {
EREADER_COMMAND_IDLE = 0, // TODO: Verify on hardware
EREADER_COMMAND_WRITE_DATA = 1,
EREADER_COMMAND_SET_INDEX = 0x22,
EREADER_COMMAND_READ_DATA = 0x23,
};
struct EReaderCard {
void* data;
size_t size;
};
struct GBA;
struct GBACartEReader {
struct GBA* p;
uint16_t data[44];
uint8_t serial[92];
uint16_t registerUnk;
uint16_t registerReset;
EReaderControl0 registerControl0;
EReaderControl1 registerControl1;
uint16_t registerLed;
// TODO: Serialize these
enum EReaderStateMachine state;
enum EReaderCommand command;
uint8_t activeRegister;
uint8_t byte;
int scanX;
int scanY;
uint8_t* dots;
struct EReaderCard cards[EREADER_CARDS_MAX];
};
void GBACartEReaderInit(struct GBACartEReader* ereader);
void GBACartEReaderDeinit(struct GBACartEReader* ereader);
void GBACartEReaderWrite(struct GBACartEReader* ereader, uint32_t address, uint16_t value);
void GBACartEReaderWriteFlash(struct GBACartEReader* ereader, uint32_t address, uint8_t value);
uint16_t GBACartEReaderRead(struct GBACartEReader* ereader, uint32_t address);
uint8_t GBACartEReaderReadFlash(struct GBACartEReader* ereader, uint32_t address);
void GBACartEReaderScan(struct GBACartEReader* ereader, const void* data, size_t size);
CXX_GUARD_END
#endif

View File

@ -16,10 +16,6 @@ CXX_GUARD_START
mLOG_DECLARE_CATEGORY(GBA_HW);
#define EREADER_DOTCODE_STRIDE 1420
#define EREADER_DOTCODE_SIZE (EREADER_DOTCODE_STRIDE * 40)
#define EREADER_CARDS_MAX 16
#define IS_GPIO_REGISTER(reg) ((reg) == GPIO_REG_DATA || (reg) == GPIO_REG_DIRECTION || (reg) == GPIO_REG_CONTROL)
struct GBARTCGenericSource {
@ -99,57 +95,8 @@ struct GBARTC {
uint8_t time[7];
};
struct GBAGBPKeyCallback {
struct mKeyCallback d;
struct GBACartridgeHardware* p;
};
struct GBAGBPSIODriver {
struct GBASIODriver d;
struct GBACartridgeHardware* p;
};
DECL_BITFIELD(GPIOPin, uint16_t);
DECL_BITFIELD(EReaderControl0, uint8_t);
DECL_BIT(EReaderControl0, Data, 0);
DECL_BIT(EReaderControl0, Clock, 1);
DECL_BIT(EReaderControl0, Direction, 2);
DECL_BIT(EReaderControl0, LedEnable, 3);
DECL_BIT(EReaderControl0, Scan, 4);
DECL_BIT(EReaderControl0, Phi, 5);
DECL_BIT(EReaderControl0, PowerEnable, 6);
DECL_BITFIELD(EReaderControl1, uint8_t);
DECL_BIT(EReaderControl1, Scanline, 1);
DECL_BIT(EReaderControl1, Unk1, 4);
DECL_BIT(EReaderControl1, Voltage, 5);
enum EReaderStateMachine {
EREADER_SERIAL_INACTIVE = 0,
EREADER_SERIAL_STARTING,
EREADER_SERIAL_BIT_0,
EREADER_SERIAL_BIT_1,
EREADER_SERIAL_BIT_2,
EREADER_SERIAL_BIT_3,
EREADER_SERIAL_BIT_4,
EREADER_SERIAL_BIT_5,
EREADER_SERIAL_BIT_6,
EREADER_SERIAL_BIT_7,
EREADER_SERIAL_END_BIT,
};
enum EReaderCommand {
EREADER_COMMAND_IDLE = 0, // TODO: Verify on hardware
EREADER_COMMAND_WRITE_DATA = 1,
EREADER_COMMAND_SET_INDEX = 0x22,
EREADER_COMMAND_READ_DATA = 0x23,
};
struct EReaderCard {
void* data;
size_t size;
};
struct GBACartridgeHardware {
struct GBA* p;
uint32_t devices;
@ -171,30 +118,6 @@ struct GBACartridgeHardware {
uint16_t tiltX;
uint16_t tiltY;
int tiltState;
unsigned gbpInputsPosted;
int gbpTxPosition;
struct mTimingEvent gbpNextEvent;
struct GBAGBPKeyCallback gbpCallback;
struct GBAGBPSIODriver gbpDriver;
uint16_t eReaderData[44];
uint8_t eReaderSerial[92];
uint16_t eReaderRegisterUnk;
uint16_t eReaderRegisterReset;
EReaderControl0 eReaderRegisterControl0;
EReaderControl1 eReaderRegisterControl1;
uint16_t eReaderRegisterLed;
// TODO: Serialize these
enum EReaderStateMachine eReaderState;
enum EReaderCommand eReaderCommand;
uint8_t eReaderActiveRegister;
uint8_t eReaderByte;
int eReaderX;
int eReaderY;
uint8_t* eReaderDots;
struct EReaderCard eReaderCards[EREADER_CARDS_MAX];
};
void GBAHardwareInit(struct GBACartridgeHardware* gpio, uint16_t* gpioBase);
@ -213,16 +136,7 @@ void GBAHardwareGPIOWrite(struct GBACartridgeHardware* gpio, uint32_t address, u
void GBAHardwareTiltWrite(struct GBACartridgeHardware* gpio, uint32_t address, uint8_t value);
uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* gpio, uint32_t address);
struct GBAVideo;
void GBAHardwarePlayerUpdate(struct GBA* gba);
bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video);
void GBAHardwareInitEReader(struct GBACartridgeHardware* hw);
void GBAHardwareEReaderWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value);
void GBAHardwareEReaderWriteFlash(struct GBACartridgeHardware* hw, uint32_t address, uint8_t value);
uint16_t GBAHardwareEReaderRead(struct GBACartridgeHardware* hw, uint32_t address);
uint8_t GBAHardwareEReaderReadFlash(struct GBACartridgeHardware* hw, uint32_t address);
void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, size_t size);
void GBARTCGenericSourceInit(struct GBARTCGenericSource* rtc, struct GBA* gba);
struct GBASerializedState;
void GBAHardwareSerialize(const struct GBACartridgeHardware* gpio, struct GBASerializedState* state);

View File

@ -14,10 +14,11 @@ CXX_GUARD_START
#include <mgba/internal/arm/arm.h>
#include <mgba/internal/gba/dma.h>
#include <mgba/internal/gba/hardware.h>
#include <mgba/internal/gba/savedata.h>
#include <mgba/internal/gba/vfame.h>
#include <mgba/internal/gba/matrix.h>
#include <mgba/internal/gba/cart/ereader.h>
#include <mgba/internal/gba/cart/gpio.h>
#include <mgba/internal/gba/cart/matrix.h>
#include <mgba/internal/gba/cart/vfame.h>
mLOG_DECLARE_CATEGORY(GBA_MEM);
@ -108,6 +109,7 @@ struct GBAMemory {
struct GBASavedata savedata;
struct GBAVFameCart vfame;
struct GBAMatrix matrix;
struct GBACartEReader ereader;
size_t romSize;
uint32_t romMask;
uint16_t romID;

View File

@ -10,8 +10,9 @@
CXX_GUARD_START
#include <mgba/gba/interface.h>
#include <mgba/core/log.h>
#include <mgba/gba/interface.h>
#include <mgba/internal/gba/sio/gbp.h>
#define MAX_GBAS 4
@ -69,6 +70,8 @@ struct GBASIO {
uint16_t rcnt;
uint16_t siocnt;
struct GBASIOPlayer gbp;
};
void GBASIOInit(struct GBASIO* sio);

View File

@ -0,0 +1,37 @@
/* Copyright (c) 2013-2021 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 GBA_GBP_H
#define GBA_GBP_H
#include <mgba-util/common.h>
CXX_GUARD_START
struct GBASIOPlayer;
struct GBASIOPlayerKeyCallback {
struct mKeyCallback d;
struct GBASIOPlayer* p;
};
struct GBASIOPlayer {
struct GBASIODriver d;
struct GBA* p;
unsigned inputsPosted;
int txPosition;
struct mTimingEvent event;
struct GBASIOPlayerKeyCallback callback;
};
void GBASIOPlayerInit(struct GBASIOPlayer* gbp);
void GBASIOPlayerReset(struct GBASIOPlayer* gbp);
struct GBAVideo;
void GBASIOPlayerUpdate(struct GBA* gba);
bool GBASIOPlayerCheckScreen(const struct GBAVideo* video);
CXX_GUARD_END
#endif

View File

@ -10,6 +10,8 @@
CXX_GUARD_START
#include <mgba/core/interface.h>
#include <libavformat/avformat.h>
#include <libavcodec/version.h>
@ -32,6 +34,54 @@ CXX_GUARD_START
#define FFMPEG_USE_PACKET_UNREF
#endif
static inline enum AVPixelFormat mColorFormatToFFmpegPixFmt(enum mColorFormat format) {
switch (format) {
#ifndef USE_LIBAV
case mCOLOR_XRGB8:
return AV_PIX_FMT_0RGB;
case mCOLOR_XBGR8:
return AV_PIX_FMT_0BGR;
case mCOLOR_RGBX8:
return AV_PIX_FMT_RGB0;
case mCOLOR_BGRX8:
return AV_PIX_FMT_BGR0;
#else
case mCOLOR_XRGB8:
return AV_PIX_FMT_ARGB;
case mCOLOR_XBGR8:
return AV_PIX_FMT_ABGR;
case mCOLOR_RGBX8:
return AV_PIX_FMT_RGBA;
case mCOLOR_BGRX8:
return AV_PIX_FMT_BGRA;
#endif
case mCOLOR_ARGB8:
return AV_PIX_FMT_ARGB;
case mCOLOR_ABGR8:
return AV_PIX_FMT_ABGR;
case mCOLOR_RGBA8:
return AV_PIX_FMT_RGBA;
case mCOLOR_BGRA8:
return AV_PIX_FMT_BGRA;
case mCOLOR_RGB5:
return AV_PIX_FMT_RGB555;
case mCOLOR_BGR5:
return AV_PIX_FMT_BGR555;
case mCOLOR_RGB565:
return AV_PIX_FMT_RGB565;
case mCOLOR_BGR565:
return AV_PIX_FMT_BGR565;
case mCOLOR_RGB8:
return AV_PIX_FMT_RGB24;
case mCOLOR_BGR8:
return AV_PIX_FMT_BGR24;
case mCOLOR_L8:
return AV_PIX_FMT_GRAY8;
default:
return AV_PIX_FMT_NONE;
}
}
CXX_GUARD_END
#endif

View File

@ -0,0 +1,36 @@
/* Copyright (c) 2013-2021 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 "ffmpeg-scale.h"
#include <libswscale/swscale.h>
static const int _qualityToFlags[] = {
SWS_POINT,
SWS_FAST_BILINEAR,
SWS_BILINEAR,
SWS_BICUBIC,
SWS_LANCZOS,
SWS_SINC,
};
void FFmpegScale(const void* input, int iwidth, int iheight, unsigned istride,
void* output, int owidth, int oheight, unsigned ostride,
enum mColorFormat format, int quality) {
enum AVPixelFormat pixFormat = mColorFormatToFFmpegPixFmt(format);
int flags;
if (quality < 0) {
quality = 0;
} else if ((unsigned) quality >= sizeof(_qualityToFlags) / sizeof(_qualityToFlags[0])) {
quality = sizeof(_qualityToFlags) / sizeof(_qualityToFlags[0]) - 1;
}
flags = _qualityToFlags[quality];
struct SwsContext* scaleContext = sws_getContext(iwidth, iheight, pixFormat,
owidth, oheight, pixFormat,
flags, 0, 0, 0);
sws_scale(scaleContext, (const uint8_t* const*) &input, (const int*) &istride, 0, iheight, (uint8_t* const*) &output, (const int*) &ostride);
sws_freeContext(scaleContext);
}

View File

@ -0,0 +1,21 @@
/* Copyright (c) 2013-2021 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 FFMPEG_SCALE
#define FFMPEG_SCALE
#include <mgba-util/common.h>
CXX_GUARD_START
#include "feature/ffmpeg/ffmpeg-common.h"
void FFmpegScale(const void* input, int iwidth, int iheight, unsigned istride,
void* output, int owidth, int oheight, unsigned ostride,
enum mColorFormat format, int quality);
CXX_GUARD_END
#endif

View File

@ -12,7 +12,7 @@ CXX_GUARD_START
#include <mgba/core/config.h>
#include "feature/gui/remap.h"
#include <mgba/internal/gba/hardware.h>
#include <mgba/gba/interface.h>
#include <mgba-util/circle-buffer.h>
#include <mgba-util/gui.h>
#include <mgba-util/threading.h>

View File

@ -3,19 +3,20 @@ set(SOURCE_FILES
../gb/audio.c
audio.c
bios.c
cart/ereader.c
cart/gpio.c
cart/matrix.c
cart/vfame.c
cheats.c
cheats/codebreaker.c
cheats/gameshark.c
cheats/parv3.c
core.c
dma.c
ereader.c
gba.c
hardware.c
hle-bios.c
input.c
io.c
matrix.c
memory.c
overrides.c
renderers/cache-set.c
@ -29,13 +30,13 @@ set(SOURCE_FILES
serialize.c
sharkport.c
sio.c
sio/gbp.c
sio/joybus.c
timer.c
vfame.c
video.c)
set(SIO_FILES
sio/dolphin.c
sio/joybus.c
sio/lockstep.c)
set(EXTRA_FILES

View File

@ -4,7 +4,7 @@
* 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 <mgba/internal/gba/hardware.h>
#include <mgba/internal/gba/cart/ereader.h>
#include <mgba/internal/arm/macros.h>
#include <mgba/internal/gba/gba.h>
@ -12,11 +12,12 @@
#define EREADER_BLOCK_SIZE 40
static void _eReaderReset(struct GBACartridgeHardware* hw);
static void _eReaderWriteControl0(struct GBACartridgeHardware* hw, uint8_t value);
static void _eReaderWriteControl1(struct GBACartridgeHardware* hw, uint8_t value);
static void _eReaderReadData(struct GBACartridgeHardware* hw);
static void _eReaderReset(struct GBACartEReader* ereader);
static void _eReaderWriteControl0(struct GBACartEReader* ereader, uint8_t value);
static void _eReaderWriteControl1(struct GBACartEReader* ereader, uint8_t value);
static void _eReaderReadData(struct GBACartEReader* ereader);
static void _eReaderReedSolomon(const uint8_t* input, uint8_t* output);
static void _eReaderScanCard(struct GBACartEReader* ereader);
const int EREADER_NYBBLE_5BIT[16][5] = {
{ 0, 0, 0, 0, 0 },
@ -161,30 +162,46 @@ static const uint8_t RS_GG[] = {
};
void GBAHardwareInitEReader(struct GBACartridgeHardware* hw) {
hw->devices |= HW_EREADER;
_eReaderReset(hw);
void GBACartEReaderInit(struct GBACartEReader* ereader) {
ereader->p->memory.hw.devices |= HW_EREADER;
_eReaderReset(ereader);
if (hw->p->memory.savedata.data[0xD000] == 0xFF) {
memset(&hw->p->memory.savedata.data[0xD000], 0, 0x1000);
memcpy(&hw->p->memory.savedata.data[0xD000], EREADER_CALIBRATION_TEMPLATE, sizeof(EREADER_CALIBRATION_TEMPLATE));
if (ereader->p->memory.savedata.data[0xD000] == 0xFF) {
memset(&ereader->p->memory.savedata.data[0xD000], 0, 0x1000);
memcpy(&ereader->p->memory.savedata.data[0xD000], EREADER_CALIBRATION_TEMPLATE, sizeof(EREADER_CALIBRATION_TEMPLATE));
}
if (hw->p->memory.savedata.data[0xE000] == 0xFF) {
memset(&hw->p->memory.savedata.data[0xE000], 0, 0x1000);
memcpy(&hw->p->memory.savedata.data[0xE000], EREADER_CALIBRATION_TEMPLATE, sizeof(EREADER_CALIBRATION_TEMPLATE));
if (ereader->p->memory.savedata.data[0xE000] == 0xFF) {
memset(&ereader->p->memory.savedata.data[0xE000], 0, 0x1000);
memcpy(&ereader->p->memory.savedata.data[0xE000], EREADER_CALIBRATION_TEMPLATE, sizeof(EREADER_CALIBRATION_TEMPLATE));
}
}
void GBAHardwareEReaderWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value) {
void GBACartEReaderDeinit(struct GBACartEReader* ereader) {
if (ereader->dots) {
mappedMemoryFree(ereader->dots, EREADER_DOTCODE_SIZE);
ereader->dots = NULL;
}
int i;
for (i = 0; i < EREADER_CARDS_MAX; ++i) {
if (!ereader->cards[i].data) {
continue;
}
free(ereader->cards[i].data);
ereader->cards[i].data = NULL;
ereader->cards[i].size = 0;
}
}
void GBACartEReaderWrite(struct GBACartEReader* ereader, uint32_t address, uint16_t value) {
address &= 0x700FF;
switch (address >> 17) {
case 0:
hw->eReaderRegisterUnk = value & 0xF;
ereader->registerUnk = value & 0xF;
break;
case 1:
hw->eReaderRegisterReset = (value & 0x8A) | 4;
ereader->registerReset = (value & 0x8A) | 4;
if (value & 2) {
_eReaderReset(hw);
_eReaderReset(ereader);
}
break;
case 2:
@ -195,54 +212,54 @@ void GBAHardwareEReaderWrite(struct GBACartridgeHardware* hw, uint32_t address,
}
}
void GBAHardwareEReaderWriteFlash(struct GBACartridgeHardware* hw, uint32_t address, uint8_t value) {
void GBACartEReaderWriteFlash(struct GBACartEReader* ereader, uint32_t address, uint8_t value) {
address &= 0xFFFF;
switch (address) {
case 0xFFB0:
_eReaderWriteControl0(hw, value);
_eReaderWriteControl0(ereader, value);
break;
case 0xFFB1:
_eReaderWriteControl1(hw, value);
_eReaderWriteControl1(ereader, value);
break;
case 0xFFB2:
hw->eReaderRegisterLed &= 0xFF00;
hw->eReaderRegisterLed |= value;
ereader->registerLed &= 0xFF00;
ereader->registerLed |= value;
break;
case 0xFFB3:
hw->eReaderRegisterLed &= 0x00FF;
hw->eReaderRegisterLed |= value << 8;
ereader->registerLed &= 0x00FF;
ereader->registerLed |= value << 8;
break;
default:
mLOG(GBA_HW, STUB, "Unimplemented e-Reader write to flash: %04X:%02X", address, value);
}
}
uint16_t GBAHardwareEReaderRead(struct GBACartridgeHardware* hw, uint32_t address) {
uint16_t GBACartEReaderRead(struct GBACartEReader* ereader, uint32_t address) {
address &= 0x700FF;
uint16_t value;
switch (address >> 17) {
case 0:
return hw->eReaderRegisterUnk;
return ereader->registerUnk;
case 1:
return hw->eReaderRegisterReset;
return ereader->registerReset;
case 2:
if (address > 0x40088) {
return 0;
}
LOAD_16(value, address & 0xFE, hw->eReaderData);
LOAD_16(value, address & 0xFE, ereader->data);
return value;
}
mLOG(GBA_HW, STUB, "Unimplemented e-Reader read: %05X", address);
return 0;
}
uint8_t GBAHardwareEReaderReadFlash(struct GBACartridgeHardware* hw, uint32_t address) {
uint8_t GBACartEReaderReadFlash(struct GBACartEReader* ereader, uint32_t address) {
address &= 0xFFFF;
switch (address) {
case 0xFFB0:
return hw->eReaderRegisterControl0;
return ereader->registerControl0;
case 0xFFB1:
return hw->eReaderRegisterControl1;
return ereader->registerControl1;
default:
mLOG(GBA_HW, STUB, "Unimplemented e-Reader read from flash: %04X", address);
return 0;
@ -329,12 +346,12 @@ static void _eReaderReedSolomon(const uint8_t* input, uint8_t* output) {
}
}
void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, size_t size) {
if (!hw->eReaderDots) {
hw->eReaderDots = anonymousMemoryMap(EREADER_DOTCODE_SIZE);
void GBACartEReaderScan(struct GBACartEReader* ereader, const void* data, size_t size) {
if (!ereader->dots) {
ereader->dots = anonymousMemoryMap(EREADER_DOTCODE_SIZE);
}
hw->eReaderX = -24;
memset(hw->eReaderDots, 0, EREADER_DOTCODE_SIZE);
ereader->scanX = -24;
memset(ereader->dots, 0, EREADER_DOTCODE_SIZE);
uint8_t blockRS[44][0x10];
uint8_t block0[0x30];
@ -386,7 +403,7 @@ void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, s
size_t x;
for (i = 0; i < 40; ++i) {
const uint8_t* line = &cdata[(i + 2) * blocks];
uint8_t* origin = &hw->eReaderDots[EREADER_DOTCODE_STRIDE * i + 200];
uint8_t* origin = &ereader->dots[EREADER_DOTCODE_STRIDE * i + 200];
for (x = 0; x < blocks; ++x) {
uint8_t byte = line[x];
if (x == 123) {
@ -406,7 +423,7 @@ void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, s
}
for (i = 0; i < blocks + 1; ++i) {
uint8_t* origin = &hw->eReaderDots[35 * i + 200];
uint8_t* origin = &ereader->dots[35 * i + 200];
_eReaderAnchor(&origin[EREADER_DOTCODE_STRIDE * 0]);
_eReaderAnchor(&origin[EREADER_DOTCODE_STRIDE * 35]);
_eReaderAddress(origin, base + i);
@ -461,7 +478,7 @@ void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, s
size_t byteOffset = 0;
for (i = 0; i < blocks; ++i) {
uint8_t block[1040];
uint8_t* origin = &hw->eReaderDots[35 * i + 200];
uint8_t* origin = &ereader->dots[35 * i + 200];
_eReaderAlignment(&origin[EREADER_DOTCODE_STRIDE * 2]);
_eReaderAlignment(&origin[EREADER_DOTCODE_STRIDE * 37]);
@ -532,155 +549,132 @@ void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, s
}
}
void _eReaderReset(struct GBACartridgeHardware* hw) {
memset(hw->eReaderData, 0, sizeof(hw->eReaderData));
hw->eReaderRegisterUnk = 0;
hw->eReaderRegisterReset = 4;
hw->eReaderRegisterControl0 = 0;
hw->eReaderRegisterControl1 = 0x80;
hw->eReaderRegisterLed = 0;
hw->eReaderState = 0;
hw->eReaderActiveRegister = 0;
void _eReaderReset(struct GBACartEReader* ereader) {
memset(ereader->data, 0, sizeof(ereader->data));
ereader->registerUnk = 0;
ereader->registerReset = 4;
ereader->registerControl0 = 0;
ereader->registerControl1 = 0x80;
ereader->registerLed = 0;
ereader->state = 0;
ereader->activeRegister = 0;
}
void _eReaderWriteControl0(struct GBACartridgeHardware* hw, uint8_t value) {
void _eReaderWriteControl0(struct GBACartEReader* ereader, uint8_t value) {
EReaderControl0 control = value & 0x7F;
EReaderControl0 oldControl = hw->eReaderRegisterControl0;
if (hw->eReaderState == EREADER_SERIAL_INACTIVE) {
EReaderControl0 oldControl = ereader->registerControl0;
if (ereader->state == EREADER_SERIAL_INACTIVE) {
if (EReaderControl0IsClock(oldControl) && EReaderControl0IsData(oldControl) && !EReaderControl0IsData(control)) {
hw->eReaderState = EREADER_SERIAL_STARTING;
ereader->state = EREADER_SERIAL_STARTING;
}
} else if (EReaderControl0IsClock(oldControl) && !EReaderControl0IsData(oldControl) && EReaderControl0IsData(control)) {
hw->eReaderState = EREADER_SERIAL_INACTIVE;
ereader->state = EREADER_SERIAL_INACTIVE;
} else if (hw->eReaderState == EREADER_SERIAL_STARTING) {
} else if (ereader->state == EREADER_SERIAL_STARTING) {
if (EReaderControl0IsClock(oldControl) && !EReaderControl0IsData(oldControl) && !EReaderControl0IsClock(control)) {
hw->eReaderState = EREADER_SERIAL_BIT_0;
hw->eReaderCommand = EREADER_COMMAND_IDLE;
ereader->state = EREADER_SERIAL_BIT_0;
ereader->command = EREADER_COMMAND_IDLE;
}
} else if (EReaderControl0IsClock(oldControl) && !EReaderControl0IsClock(control)) {
mLOG(GBA_HW, DEBUG, "[e-Reader] Serial falling edge: %c %i", EReaderControl0IsDirection(control) ? '>' : '<', EReaderControl0GetData(control));
// TODO: Improve direction control
if (EReaderControl0IsDirection(control)) {
hw->eReaderByte |= EReaderControl0GetData(control) << (7 - (hw->eReaderState - EREADER_SERIAL_BIT_0));
++hw->eReaderState;
if (hw->eReaderState == EREADER_SERIAL_END_BIT) {
mLOG(GBA_HW, DEBUG, "[e-Reader] Wrote serial byte: %02x", hw->eReaderByte);
switch (hw->eReaderCommand) {
ereader->byte |= EReaderControl0GetData(control) << (7 - (ereader->state - EREADER_SERIAL_BIT_0));
++ereader->state;
if (ereader->state == EREADER_SERIAL_END_BIT) {
mLOG(GBA_HW, DEBUG, "[e-Reader] Wrote serial byte: %02x", ereader->byte);
switch (ereader->command) {
case EREADER_COMMAND_IDLE:
hw->eReaderCommand = hw->eReaderByte;
ereader->command = ereader->byte;
break;
case EREADER_COMMAND_SET_INDEX:
hw->eReaderActiveRegister = hw->eReaderByte;
hw->eReaderCommand = EREADER_COMMAND_WRITE_DATA;
ereader->activeRegister = ereader->byte;
ereader->command = EREADER_COMMAND_WRITE_DATA;
break;
case EREADER_COMMAND_WRITE_DATA:
switch (hw->eReaderActiveRegister & 0x7F) {
switch (ereader->activeRegister & 0x7F) {
case 0:
case 0x57:
case 0x58:
case 0x59:
case 0x5A:
// Read-only
mLOG(GBA_HW, GAME_ERROR, "Writing to read-only e-Reader serial register: %02X", hw->eReaderActiveRegister);
mLOG(GBA_HW, GAME_ERROR, "Writing to read-only e-Reader serial register: %02X", ereader->activeRegister);
break;
default:
if ((hw->eReaderActiveRegister & 0x7F) > 0x5A) {
mLOG(GBA_HW, GAME_ERROR, "Writing to non-existent e-Reader serial register: %02X", hw->eReaderActiveRegister);
if ((ereader->activeRegister & 0x7F) > 0x5A) {
mLOG(GBA_HW, GAME_ERROR, "Writing to non-existent e-Reader serial register: %02X", ereader->activeRegister);
break;
}
hw->eReaderSerial[hw->eReaderActiveRegister & 0x7F] = hw->eReaderByte;
ereader->serial[ereader->activeRegister & 0x7F] = ereader->byte;
break;
}
++hw->eReaderActiveRegister;
++ereader->activeRegister;
break;
default:
mLOG(GBA_HW, ERROR, "Hit undefined state %02X in e-Reader state machine", hw->eReaderCommand);
mLOG(GBA_HW, ERROR, "Hit undefined state %02X in e-Reader state machine", ereader->command);
break;
}
hw->eReaderState = EREADER_SERIAL_BIT_0;
hw->eReaderByte = 0;
ereader->state = EREADER_SERIAL_BIT_0;
ereader->byte = 0;
}
} else if (hw->eReaderCommand == EREADER_COMMAND_READ_DATA) {
int bit = hw->eReaderSerial[hw->eReaderActiveRegister & 0x7F] >> (7 - (hw->eReaderState - EREADER_SERIAL_BIT_0));
} else if (ereader->command == EREADER_COMMAND_READ_DATA) {
int bit = ereader->serial[ereader->activeRegister & 0x7F] >> (7 - (ereader->state - EREADER_SERIAL_BIT_0));
control = EReaderControl0SetData(control, bit);
++hw->eReaderState;
if (hw->eReaderState == EREADER_SERIAL_END_BIT) {
++hw->eReaderActiveRegister;
mLOG(GBA_HW, DEBUG, "[e-Reader] Read serial byte: %02x", hw->eReaderSerial[hw->eReaderActiveRegister & 0x7F]);
++ereader->state;
if (ereader->state == EREADER_SERIAL_END_BIT) {
++ereader->activeRegister;
mLOG(GBA_HW, DEBUG, "[e-Reader] Read serial byte: %02x", ereader->serial[ereader->activeRegister & 0x7F]);
}
}
} else if (!EReaderControl0IsDirection(control)) {
// Clear the error bit
control = EReaderControl0ClearData(control);
}
hw->eReaderRegisterControl0 = control;
ereader->registerControl0 = control;
if (!EReaderControl0IsScan(oldControl) && EReaderControl0IsScan(control)) {
if (hw->eReaderX > 1000) {
if (hw->eReaderDots) {
memset(hw->eReaderDots, 0, EREADER_DOTCODE_SIZE);
}
int i;
for (i = 0; i < EREADER_CARDS_MAX; ++i) {
if (!hw->eReaderCards[i].data) {
continue;
}
GBAHardwareEReaderScan(hw, hw->eReaderCards[i].data, hw->eReaderCards[i].size);
free(hw->eReaderCards[i].data);
hw->eReaderCards[i].data = NULL;
hw->eReaderCards[i].size = 0;
break;
}
if (ereader->scanX > 1000) {
_eReaderScanCard(ereader);
}
hw->eReaderX = 0;
hw->eReaderY = 0;
} else if (EReaderControl0IsLedEnable(control) && EReaderControl0IsScan(control) && !EReaderControl1IsScanline(hw->eReaderRegisterControl1)) {
_eReaderReadData(hw);
ereader->scanX = 0;
ereader->scanY = 0;
} else if (EReaderControl0IsLedEnable(control) && EReaderControl0IsScan(control) && !EReaderControl1IsScanline(ereader->registerControl1)) {
_eReaderReadData(ereader);
}
mLOG(GBA_HW, STUB, "Unimplemented e-Reader Control0 write: %02X", value);
}
void _eReaderWriteControl1(struct GBACartridgeHardware* hw, uint8_t value) {
void _eReaderWriteControl1(struct GBACartEReader* ereader, uint8_t value) {
EReaderControl1 control = (value & 0x32) | 0x80;
hw->eReaderRegisterControl1 = control;
if (EReaderControl0IsScan(hw->eReaderRegisterControl0) && !EReaderControl1IsScanline(control)) {
++hw->eReaderY;
if (hw->eReaderY == (hw->eReaderSerial[0x15] | (hw->eReaderSerial[0x14] << 8))) {
hw->eReaderY = 0;
if (hw->eReaderX < 3400) {
hw->eReaderX += 210;
ereader->registerControl1 = control;
if (EReaderControl0IsScan(ereader->registerControl0) && !EReaderControl1IsScanline(control)) {
++ereader->scanY;
if (ereader->scanY == (ereader->serial[0x15] | (ereader->serial[0x14] << 8))) {
ereader->scanY = 0;
if (ereader->scanX < 3400) {
ereader->scanX += 210;
}
}
_eReaderReadData(hw);
_eReaderReadData(ereader);
}
mLOG(GBA_HW, STUB, "Unimplemented e-Reader Control1 write: %02X", value);
}
void _eReaderReadData(struct GBACartridgeHardware* hw) {
memset(hw->eReaderData, 0, EREADER_BLOCK_SIZE);
if (!hw->eReaderDots) {
int i;
for (i = 0; i < EREADER_CARDS_MAX; ++i) {
if (!hw->eReaderCards[i].data) {
continue;
}
GBAHardwareEReaderScan(hw, hw->eReaderCards[i].data, hw->eReaderCards[i].size);
free(hw->eReaderCards[i].data);
hw->eReaderCards[i].data = NULL;
hw->eReaderCards[i].size = 0;
break;
}
void _eReaderReadData(struct GBACartEReader* ereader) {
memset(ereader->data, 0, EREADER_BLOCK_SIZE);
if (!ereader->dots) {
_eReaderScanCard(ereader);
}
if (hw->eReaderDots) {
int y = hw->eReaderY - 10;
if (ereader->dots) {
int y = ereader->scanY - 10;
if (y < 0 || y >= 120) {
memset(hw->eReaderData, 0, EREADER_BLOCK_SIZE);
memset(ereader->data, 0, EREADER_BLOCK_SIZE);
} else {
int i;
uint8_t* origin = &hw->eReaderDots[EREADER_DOTCODE_STRIDE * (y / 3) + 16];
uint8_t* origin = &ereader->dots[EREADER_DOTCODE_STRIDE * (y / 3) + 16];
for (i = 0; i < 20; ++i) {
uint16_t word = 0;
int x = hw->eReaderX + i * 16;
int x = ereader->scanX + i * 16;
word |= origin[(x + 0) / 3] << 8;
word |= origin[(x + 1) / 3] << 9;
word |= origin[(x + 2) / 3] << 10;
@ -697,29 +691,48 @@ void _eReaderReadData(struct GBACartridgeHardware* hw) {
word |= origin[(x + 13) / 3] << 5;
word |= origin[(x + 14) / 3] << 6;
word |= origin[(x + 15) / 3] << 7;
STORE_16(word, (19 - i) << 1, hw->eReaderData);
STORE_16(word, (19 - i) << 1, ereader->data);
}
}
}
hw->eReaderRegisterControl1 = EReaderControl1FillScanline(hw->eReaderRegisterControl1);
if (EReaderControl0IsLedEnable(hw->eReaderRegisterControl0)) {
uint16_t led = hw->eReaderRegisterLed * 2;
ereader->registerControl1 = EReaderControl1FillScanline(ereader->registerControl1);
if (EReaderControl0IsLedEnable(ereader->registerControl0)) {
uint16_t led = ereader->registerLed * 2;
if (led > 0x4000) {
led = 0x4000;
}
GBARaiseIRQ(hw->p, IRQ_GAMEPAK, -led);
GBARaiseIRQ(ereader->p, IRQ_GAMEPAK, -led);
}
}
void GBAEReaderQueueCard(struct GBA* gba, const void* data, size_t size) {
void _eReaderScanCard(struct GBACartEReader* ereader) {
if (ereader->dots) {
memset(ereader->dots, 0, EREADER_DOTCODE_SIZE);
}
int i;
for (i = 0; i < EREADER_CARDS_MAX; ++i) {
if (gba->memory.hw.eReaderCards[i].data) {
if (!ereader->cards[i].data) {
continue;
}
gba->memory.hw.eReaderCards[i].data = malloc(size);
memcpy(gba->memory.hw.eReaderCards[i].data, data, size);
gba->memory.hw.eReaderCards[i].size = size;
GBACartEReaderScan(ereader, ereader->cards[i].data, ereader->cards[i].size);
free(ereader->cards[i].data);
ereader->cards[i].data = NULL;
ereader->cards[i].size = 0;
break;
}
}
void GBACartEReaderQueueCard(struct GBA* gba, const void* data, size_t size) {
struct GBACartEReader* ereader = &gba->memory.ereader;
int i;
for (i = 0; i < EREADER_CARDS_MAX; ++i) {
if (ereader->cards[i].data) {
continue;
}
ereader->cards[i].data = malloc(size);
memcpy(ereader->cards[i].data, data, size);
ereader->cards[i].size = size;
return;
}
}

View File

@ -1,9 +1,9 @@
/* Copyright (c) 2013-2015 Jeffrey Pfau
/* Copyright (c) 2013-2021 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 <mgba/internal/gba/hardware.h>
#include <mgba/internal/gba/cart/gpio.h>
#include <mgba/internal/arm/macros.h>
#include <mgba/internal/gba/io.h>
@ -29,10 +29,6 @@ static void _rumbleReadPins(struct GBACartridgeHardware* hw);
static void _lightReadPins(struct GBACartridgeHardware* hw);
static uint16_t _gbpRead(struct mKeyCallback*);
static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate);
static const int RTC_BYTES[8] = {
1, // Status register 1
1, // Duty/alarm 1
@ -46,22 +42,7 @@ static const int RTC_BYTES[8] = {
void GBAHardwareInit(struct GBACartridgeHardware* hw, uint16_t* base) {
hw->gpioBase = base;
hw->eReaderDots = NULL;
memset(hw->eReaderCards, 0, sizeof(hw->eReaderCards));
GBAHardwareClear(hw);
hw->gbpCallback.d.readKeys = _gbpRead;
hw->gbpCallback.p = hw;
hw->gbpDriver.d.init = 0;
hw->gbpDriver.d.deinit = 0;
hw->gbpDriver.d.load = 0;
hw->gbpDriver.d.unload = 0;
hw->gbpDriver.d.writeRegister = _gbpSioWriteRegister;
hw->gbpDriver.p = hw;
hw->gbpNextEvent.context = &hw->gbpDriver;
hw->gbpNextEvent.name = "GBA SIO Game Boy Player";
hw->gbpNextEvent.callback = _gbpSioProcessEvents;
hw->gbpNextEvent.priority = 0x80;
}
void GBAHardwareClear(struct GBACartridgeHardware* hw) {
@ -69,24 +50,6 @@ void GBAHardwareClear(struct GBACartridgeHardware* hw) {
hw->readWrite = GPIO_WRITE_ONLY;
hw->pinState = 0;
hw->direction = 0;
if (hw->eReaderDots) {
mappedMemoryFree(hw->eReaderDots, EREADER_DOTCODE_SIZE);
hw->eReaderDots = NULL;
}
int i;
for (i = 0; i < EREADER_CARDS_MAX; ++i) {
if (!hw->eReaderCards[i].data) {
continue;
}
free(hw->eReaderCards[i].data);
hw->eReaderCards[i].data = NULL;
hw->eReaderCards[i].size = 0;
}
if (hw->p->sio.drivers.normal == &hw->gbpDriver.d) {
GBASIOSetDriver(&hw->p->sio, 0, SIO_NORMAL_32);
}
}
void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value) {
@ -497,124 +460,10 @@ uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* hw, uint32_t address) {
return 0xFF;
}
// == Game Boy Player
static const uint8_t _logoPalette[] = {
0xDF, 0xFF, 0x0C, 0x64, 0x0C, 0xE4, 0x2D, 0xE4, 0x4E, 0x64, 0x4E, 0xE4, 0x6E, 0xE4, 0xAF, 0x68,
0xB0, 0xE8, 0xD0, 0x68, 0xF0, 0x68, 0x11, 0x69, 0x11, 0xE9, 0x32, 0x6D, 0x32, 0xED, 0x73, 0xED,
0x93, 0x6D, 0x94, 0xED, 0xB4, 0x6D, 0xD5, 0xF1, 0xF5, 0x71, 0xF6, 0xF1, 0x16, 0x72, 0x57, 0x72,
0x57, 0xF6, 0x78, 0x76, 0x78, 0xF6, 0x99, 0xF6, 0xB9, 0xF6, 0xD9, 0x76, 0xDA, 0xF6, 0x1B, 0x7B,
0x1B, 0xFB, 0x3C, 0xFB, 0x5C, 0x7B, 0x7D, 0x7B, 0x7D, 0xFF, 0x9D, 0x7F, 0xBE, 0x7F, 0xFF, 0x7F,
0x2D, 0x64, 0x8E, 0x64, 0x8F, 0xE8, 0xF1, 0xE8, 0x52, 0x6D, 0x73, 0x6D, 0xB4, 0xF1, 0x16, 0xF2,
0x37, 0x72, 0x98, 0x76, 0xFA, 0x7A, 0xFA, 0xFA, 0x5C, 0xFB, 0xBE, 0xFF, 0xDE, 0x7F, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const uint32_t _logoHash = 0xEEDA6963;
static const uint32_t _gbpTxData[] = {
0x0000494E, 0x0000494E,
0xB6B1494E, 0xB6B1544E,
0xABB1544E, 0xABB14E45,
0xB1BA4E45, 0xB1BA4F44,
0xB0BB4F44, 0xB0BB8002,
0x10000010, 0x20000013,
0x30000003
};
bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video) {
if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) {
return false;
}
uint32_t hash = hash32(&video->vram[0x4000], 0x4000, 0);
return hash == _logoHash;
}
void GBAHardwarePlayerUpdate(struct GBA* gba) {
if (gba->memory.hw.devices & HW_GB_PLAYER) {
if (GBAHardwarePlayerCheckScreen(&gba->video)) {
++gba->memory.hw.gbpInputsPosted;
gba->memory.hw.gbpInputsPosted %= 3;
gba->keyCallback = &gba->memory.hw.gbpCallback.d;
} else {
// TODO: Save and restore
gba->keyCallback = 0;
}
gba->memory.hw.gbpTxPosition = 0;
return;
}
if (gba->keyCallback) {
return;
}
if (GBAHardwarePlayerCheckScreen(&gba->video)) {
gba->memory.hw.devices |= HW_GB_PLAYER;
gba->memory.hw.gbpInputsPosted = 0;
gba->keyCallback = &gba->memory.hw.gbpCallback.d;
// TODO: Check if the SIO driver is actually used first
GBASIOSetDriver(&gba->sio, &gba->memory.hw.gbpDriver.d, SIO_NORMAL_32);
}
}
uint16_t _gbpRead(struct mKeyCallback* callback) {
struct GBAGBPKeyCallback* gbpCallback = (struct GBAGBPKeyCallback*) callback;
if (gbpCallback->p->gbpInputsPosted == 2) {
return 0xF0;
}
return 0;
}
uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
struct GBAGBPSIODriver* gbp = (struct GBAGBPSIODriver*) driver;
if (address == REG_SIOCNT) {
if (value & 0x0080) {
uint32_t rx = gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] << 16);
if (gbp->p->gbpTxPosition < 12 && gbp->p->gbpTxPosition > 0) {
// TODO: Check expected
} else if (gbp->p->gbpTxPosition >= 12) {
uint32_t mask = 0x33;
// 0x00 = Stop
// 0x11 = Hard Stop
// 0x22 = Start
if (gbp->p->p->rumble) {
gbp->p->p->rumble->setRumble(gbp->p->p->rumble, (rx & mask) == 0x22);
}
}
mTimingDeschedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent);
mTimingSchedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent, 2048);
}
value &= 0x78FB;
}
return value;
}
void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) {
UNUSED(timing);
UNUSED(cyclesLate);
struct GBAGBPSIODriver* gbp = user;
uint32_t tx = 0;
int txPosition = gbp->p->gbpTxPosition;
if (txPosition > 16) {
gbp->p->gbpTxPosition = 0;
txPosition = 0;
} else if (txPosition > 12) {
txPosition = 12;
}
tx = _gbpTxData[txPosition];
++gbp->p->gbpTxPosition;
gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] = tx;
gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16;
if (GBASIONormalIsIrq(gbp->d.p->siocnt)) {
GBARaiseIRQ(gbp->p->p, IRQ_SIO, cyclesLate);
}
gbp->d.p->siocnt = GBASIONormalClearStart(gbp->d.p->siocnt);
gbp->p->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080;
}
// == Serialization
void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) {
GBASerializedHWFlags1 flags1 = 0;
GBASerializedHWFlags2 flags2 = 0;
flags1 = GBASerializedHWFlags1SetReadWrite(flags1, hw->readWrite);
STORE_16(hw->pinState, 0, &state->hw.pinState);
STORE_16(hw->direction, 0, &state->hw.pinDirection);
@ -633,14 +482,19 @@ void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASeria
flags1 = GBASerializedHWFlags1SetGyroEdge(flags1, hw->gyroEdge);
STORE_16(hw->tiltX, 0, &state->hw.tiltSampleX);
STORE_16(hw->tiltY, 0, &state->hw.tiltSampleY);
flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState);
flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter);
state->hw.lightSample = hw->lightSample;
flags1 = GBASerializedHWFlags1SetLightEdge(flags1, hw->lightEdge);
flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->gbpInputsPosted);
flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->gbpTxPosition);
STORE_32(hw->gbpNextEvent.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent);
STORE_16(flags1, 0, &state->hw.flags1);
GBASerializedHWFlags2 flags2 = 0;
flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState);
flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter);
// GBP stuff is only here for legacy reasons
flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->p->sio.gbp.inputsPosted);
flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->p->sio.gbp.txPosition);
STORE_32(hw->p->sio.gbp.event.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent);
state->hw.flags2 = flags2;
}
@ -669,15 +523,17 @@ void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASer
hw->lightCounter = GBASerializedHWFlags1GetLightCounter(flags1);
hw->lightSample = state->hw.lightSample;
hw->lightEdge = GBASerializedHWFlags1GetLightEdge(flags1);
hw->gbpInputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2);
hw->gbpTxPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2);
// GBP stuff is only here for legacy reasons
hw->p->sio.gbp.inputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2);
hw->p->sio.gbp.txPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2);
uint32_t when;
LOAD_32(when, 0, &state->hw.gbpNextEvent);
if (hw->devices & HW_GB_PLAYER) {
GBASIOSetDriver(&hw->p->sio, &hw->gbpDriver.d, SIO_NORMAL_32);
GBASIOSetDriver(&hw->p->sio, &hw->p->sio.gbp.d, SIO_NORMAL_32);
if (hw->p->memory.io[REG_SIOCNT >> 1] & 0x0080) {
mTimingSchedule(&hw->p->timing, &hw->gbpNextEvent, when);
mTimingSchedule(&hw->p->timing, &hw->p->sio.gbp.event, when);
}
}
}

View File

@ -3,7 +3,7 @@
* 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 <mgba/internal/gba/matrix.h>
#include <mgba/internal/gba/cart/matrix.h>
#include <mgba/internal/arm/macros.h>
#include <mgba/internal/gba/gba.h>

View File

@ -3,7 +3,7 @@
* 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 <mgba/internal/gba/vfame.h>
#include <mgba/internal/gba/cart/vfame.h>
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/memory.h>

View File

@ -219,7 +219,7 @@ void GBAReset(struct ARMCore* cpu) {
// GB Player SIO control should not be engaged before detection, even if we already know it's GBP
gba->memory.hw.devices &= ~HW_GB_PLAYER;
if (gba->sio.drivers.normal == &gba->memory.hw.gbpDriver.d) {
if (gba->sio.drivers.normal == &gba->sio.gbp.d) {
GBASIOSetDriver(&gba->sio, NULL, SIO_NORMAL_32);
}
@ -854,7 +854,7 @@ void GBAFrameEnded(struct GBA* gba) {
}
if (gba->memory.hw.devices & (HW_GB_PLAYER | HW_GB_PLAYER_DETECTION)) {
GBAHardwarePlayerUpdate(gba);
GBASIOPlayerUpdate(gba);
}
size_t c;

View File

@ -94,6 +94,10 @@ void GBAMemoryInit(struct GBA* gba) {
GBADMAInit(gba);
GBAVFameInit(&gba->memory.vfame);
gba->memory.ereader.p = gba;
gba->memory.ereader.dots = NULL;
memset(gba->memory.ereader.cards, 0, sizeof(gba->memory.ereader.cards));
}
void GBAMemoryDeinit(struct GBA* gba) {
@ -107,6 +111,8 @@ void GBAMemoryDeinit(struct GBA* gba) {
if (gba->memory.agbPrintBufferBackup) {
mappedMemoryFree(gba->memory.agbPrintBufferBackup, SIZE_AGB_PRINT);
}
GBACartEReaderDeinit(&gba->memory.ereader);
}
void GBAMemoryReset(struct GBA* gba) {
@ -588,7 +594,7 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
if (memory->savedata.type == SAVEDATA_EEPROM || memory->savedata.type == SAVEDATA_EEPROM512) {
value = GBASavedataReadEEPROM(&memory->savedata);
} else if ((address & 0x0DFC0000) >= 0x0DF80000 && memory->hw.devices & HW_EREADER) {
value = GBAHardwareEReaderRead(&memory->hw, address);
value = GBACartEReaderRead(&memory->ereader, address);
} else if ((address & (SIZE_CART0 - 1)) < memory->romSize) {
LOAD_16(value, address & (SIZE_CART0 - 2), memory->rom);
} else if (memory->mirroring && (address & memory->romMask) < memory->romSize) {
@ -704,7 +710,7 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
break;
}
if (memory->hw.devices & HW_EREADER && (address & 0xE00FF80) >= 0xE00FF80) {
value = GBAHardwareEReaderReadFlash(&memory->hw, address);
value = GBACartEReaderReadFlash(&memory->ereader, address);
} else if (memory->savedata.type == SAVEDATA_SRAM) {
value = memory->savedata.data[address & (SIZE_CART_SRAM - 1)];
} else if (memory->savedata.type == SAVEDATA_FLASH512 || memory->savedata.type == SAVEDATA_FLASH1M) {
@ -930,7 +936,6 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
if ((address & 0x00FFFFFF) >= AGB_PRINT_BASE) {
uint32_t agbPrintAddr = address & 0x00FFFFFF;
if (agbPrintAddr == AGB_PRINT_PROTECT) {
bool wasProtected = memory->agbPrintProtect != 0x20;
memory->agbPrintProtect = value;
if (!memory->agbPrintBuffer) {
@ -966,7 +971,7 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
break;
case REGION_CART2_EX:
if ((address & 0x0DFC0000) >= 0x0DF80000 && memory->hw.devices & HW_EREADER) {
GBAHardwareEReaderWrite(&memory->hw, address, value);
GBACartEReaderWrite(&memory->ereader, address, value);
break;
} else if (memory->savedata.type == SAVEDATA_AUTODETECT) {
mLOG(GBA_MEM, INFO, "Detected EEPROM savegame");
@ -1053,7 +1058,7 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
}
}
if (memory->hw.devices & HW_EREADER && (address & 0xE00FF80) >= 0xE00FF80) {
GBAHardwareEReaderWriteFlash(&memory->hw, address, value);
GBACartEReaderWriteFlash(&memory->ereader, address, value);
} else if (memory->savedata.type == SAVEDATA_FLASH512 || memory->savedata.type == SAVEDATA_FLASH1M) {
GBASavedataWriteFlash(&memory->savedata, address, value);
} else if (memory->savedata.type == SAVEDATA_SRAM) {

View File

@ -6,7 +6,8 @@
#include <mgba/internal/gba/overrides.h>
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/hardware.h>
#include <mgba/internal/gba/cart/ereader.h>
#include <mgba/internal/gba/cart/gpio.h>
#include <mgba-util/configuration.h>
@ -347,7 +348,7 @@ void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* overri
}
if (override->hardware & HW_EREADER) {
GBAHardwareInitEReader(&gba->memory.hw);
GBACartEReaderInit(&gba->memory.ereader);
}
if (override->hardware & HW_GB_PLAYER_DETECTION) {

View File

@ -7,6 +7,7 @@
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/io.h>
#include <mgba/internal/gba/sio/gbp.h>
mLOG_DEFINE_CATEGORY(GBA_SIO, "GBA Serial I/O", "gba.sio");
@ -76,6 +77,10 @@ void GBASIOInit(struct GBASIO* sio) {
sio->drivers.multiplayer = 0;
sio->drivers.joybus = 0;
sio->activeDriver = 0;
sio->gbp.p = sio->p;
GBASIOPlayerInit(&sio->gbp);
GBASIOReset(sio);
}
@ -103,6 +108,8 @@ void GBASIOReset(struct GBASIO* sio) {
sio->mode = -1;
sio->activeDriver = NULL;
_switchMode(sio);
GBASIOPlayerReset(&sio->gbp);
}
void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) {

148
src/gba/sio/gbp.c Normal file
View File

@ -0,0 +1,148 @@
/* Copyright (c) 2013-2021 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 <mgba/internal/gba/sio.h>
#include <mgba/internal/arm/macros.h>
#include <mgba/internal/gba/io.h>
#include <mgba/internal/gba/serialize.h>
#include <mgba-util/formatting.h>
#include <mgba-util/hash.h>
#include <mgba-util/memory.h>
static uint16_t _gbpRead(struct mKeyCallback*);
static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate);
static const uint8_t _logoPalette[] = {
0xDF, 0xFF, 0x0C, 0x64, 0x0C, 0xE4, 0x2D, 0xE4, 0x4E, 0x64, 0x4E, 0xE4, 0x6E, 0xE4, 0xAF, 0x68,
0xB0, 0xE8, 0xD0, 0x68, 0xF0, 0x68, 0x11, 0x69, 0x11, 0xE9, 0x32, 0x6D, 0x32, 0xED, 0x73, 0xED,
0x93, 0x6D, 0x94, 0xED, 0xB4, 0x6D, 0xD5, 0xF1, 0xF5, 0x71, 0xF6, 0xF1, 0x16, 0x72, 0x57, 0x72,
0x57, 0xF6, 0x78, 0x76, 0x78, 0xF6, 0x99, 0xF6, 0xB9, 0xF6, 0xD9, 0x76, 0xDA, 0xF6, 0x1B, 0x7B,
0x1B, 0xFB, 0x3C, 0xFB, 0x5C, 0x7B, 0x7D, 0x7B, 0x7D, 0xFF, 0x9D, 0x7F, 0xBE, 0x7F, 0xFF, 0x7F,
0x2D, 0x64, 0x8E, 0x64, 0x8F, 0xE8, 0xF1, 0xE8, 0x52, 0x6D, 0x73, 0x6D, 0xB4, 0xF1, 0x16, 0xF2,
0x37, 0x72, 0x98, 0x76, 0xFA, 0x7A, 0xFA, 0xFA, 0x5C, 0xFB, 0xBE, 0xFF, 0xDE, 0x7F, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const uint32_t _logoHash = 0xEEDA6963;
static const uint32_t _gbpTxData[] = {
0x0000494E, 0x0000494E,
0xB6B1494E, 0xB6B1544E,
0xABB1544E, 0xABB14E45,
0xB1BA4E45, 0xB1BA4F44,
0xB0BB4F44, 0xB0BB8002,
0x10000010, 0x20000013,
0x30000003
};
void GBASIOPlayerInit(struct GBASIOPlayer* gbp) {
gbp->callback.d.readKeys = _gbpRead;
gbp->callback.p = gbp;
gbp->d.init = 0;
gbp->d.deinit = 0;
gbp->d.load = 0;
gbp->d.unload = 0;
gbp->d.writeRegister = _gbpSioWriteRegister;
gbp->event.context = gbp;
gbp->event.name = "GBA SIO Game Boy Player";
gbp->event.callback = _gbpSioProcessEvents;
gbp->event.priority = 0x80;
}
void GBASIOPlayerReset(struct GBASIOPlayer* gbp) {
if (gbp->p->sio.drivers.normal == &gbp->d) {
GBASIOSetDriver(&gbp->p->sio, NULL, SIO_NORMAL_32);
}
}
bool GBASIOPlayerCheckScreen(const struct GBAVideo* video) {
if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) {
return false;
}
uint32_t hash = hash32(&video->vram[0x4000], 0x4000, 0);
return hash == _logoHash;
}
void GBASIOPlayerUpdate(struct GBA* gba) {
if (gba->memory.hw.devices & HW_GB_PLAYER) {
if (GBASIOPlayerCheckScreen(&gba->video)) {
++gba->sio.gbp.inputsPosted;
gba->sio.gbp.inputsPosted %= 3;
gba->keyCallback = &gba->sio.gbp.callback.d;
} else {
// TODO: Save and restore
gba->keyCallback = 0;
}
gba->sio.gbp.txPosition = 0;
return;
}
if (gba->keyCallback) {
return;
}
if (GBASIOPlayerCheckScreen(&gba->video)) {
gba->memory.hw.devices |= HW_GB_PLAYER;
gba->sio.gbp.inputsPosted = 0;
gba->keyCallback = &gba->sio.gbp.callback.d;
// TODO: Check if the SIO driver is actually used first
GBASIOSetDriver(&gba->sio, &gba->sio.gbp.d, SIO_NORMAL_32);
}
}
uint16_t _gbpRead(struct mKeyCallback* callback) {
struct GBASIOPlayerKeyCallback* gbpCallback = (struct GBASIOPlayerKeyCallback*) callback;
if (gbpCallback->p->inputsPosted == 2) {
return 0xF0;
}
return 0;
}
uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
struct GBASIOPlayer* gbp = (struct GBASIOPlayer*) driver;
if (address == REG_SIOCNT) {
if (value & 0x0080) {
uint32_t rx = gbp->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->memory.io[REG_SIODATA32_HI >> 1] << 16);
if (gbp->txPosition < 12 && gbp->txPosition > 0) {
// TODO: Check expected
} else if (gbp->txPosition >= 12) {
uint32_t mask = 0x33;
// 0x00 = Stop
// 0x11 = Hard Stop
// 0x22 = Start
if (gbp->p->rumble) {
gbp->p->rumble->setRumble(gbp->p->rumble, (rx & mask) == 0x22);
}
}
mTimingDeschedule(&gbp->p->timing, &gbp->event);
mTimingSchedule(&gbp->p->timing, &gbp->event, 2048);
}
value &= 0x78FB;
}
return value;
}
void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) {
UNUSED(timing);
UNUSED(cyclesLate);
struct GBASIOPlayer* gbp = user;
uint32_t tx = 0;
int txPosition = gbp->txPosition;
if (txPosition > 16) {
gbp->txPosition = 0;
txPosition = 0;
} else if (txPosition > 12) {
txPosition = 12;
}
tx = _gbpTxData[txPosition];
++gbp->txPosition;
gbp->p->memory.io[REG_SIODATA32_LO >> 1] = tx;
gbp->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16;
if (GBASIONormalIsIrq(gbp->d.p->siocnt)) {
GBARaiseIRQ(gbp->p, IRQ_SIO, cyclesLate);
}
gbp->d.p->siocnt = GBASIONormalClearStart(gbp->d.p->siocnt);
gbp->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080;
}

View File

@ -800,7 +800,7 @@ void CoreController::scanCard(const QString& path) {
mCoreThreadRunFunction(&m_threadContext, [](mCoreThread* thread) {
CoreController* controller = static_cast<CoreController*>(thread->userData);
GBAEReaderQueueCard(static_cast<GBA*>(thread->core->board), controller->m_eReaderData.constData(), controller->m_eReaderData.size());
GBACartEReaderQueueCard(static_cast<GBA*>(thread->core->board), controller->m_eReaderData.constData(), controller->m_eReaderData.size());
});
#endif
}

View File

@ -371,6 +371,10 @@ void PainterGL::resizeContext() {
m_interrupter.resume();
QSize size = m_context->screenDimensions();
if (m_dims == size) {
return;
}
dequeueAll();
m_backend->setDimensions(m_backend, size.width(), size.height());
}
@ -563,9 +567,6 @@ void PainterGL::dequeueAll() {
m_free.append(buffer);
}
}
if (buffer) {
m_backend->postFrame(m_backend, buffer);
}
if (m_buffer) {
m_free.append(m_buffer);
m_buffer = nullptr;

View File

@ -142,7 +142,7 @@ private:
QList<uint32_t*> m_free;
QQueue<uint32_t*> m_queue;
QAtomicInt m_lagging = 0;
uint32_t* m_buffer;
uint32_t* m_buffer = nullptr;
QPainter m_painter;
QMutex m_mutex;
QWindow* m_surface;
@ -158,6 +158,7 @@ private:
VideoShader m_shader{};
VideoBackend* m_backend = nullptr;
QSize m_size;
QSize m_dims;
MessagePainter* m_messagePainter = nullptr;
QElapsedTimer m_delayTimer;
std::shared_ptr<VideoProxy> m_videoProxy;

View File

@ -48,7 +48,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../AboutScreen.ui" line="41"/>
<source>Branch: &lt;tt&gt;{gitBranch}&lt;/tt&gt;&lt;br/&gt;Revision: &lt;tt&gt;{gitCommit}&lt;/tt&gt;</source>
<translation>Branch: &lt;tt&gt;{gitBranch}&lt;/tt&gt;&lt;br/&gt;Revision: &lt;tt&gt;{gitCommit}&lt;/tt&gt;</translation>
<translation>Zweig: &lt;tt&gt;{gitBranch}&lt;/tt&gt;&lt;br/&gt;Änderung: &lt;tt&gt;{gitCommit}&lt;/tt&gt;</translation>
</message>
</context>
<context>
@ -513,7 +513,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../LogView.ui" line="78"/>
<source>Fatal</source>
<translation>Fatal</translation>
<translation>Tödlich</translation>
</message>
<message>
<location filename="../LogView.ui" line="95"/>
@ -541,7 +541,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../MapView.ui" line="14"/>
<source>Maps</source>
<translation>Maps</translation>
<translation>Karten</translation>
</message>
<message>
<location filename="../MapView.ui" line="43"/>
@ -767,7 +767,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../MemoryView.ui" line="208"/>
<source>Signed Integer:</source>
<translation>Signed Integer:</translation>
<translation>Ganzzahl mit Vorzeichen:</translation>
</message>
<message>
<location filename="../MemoryView.ui" line="229"/>
@ -807,7 +807,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../MemoryView.ui" line="187"/>
<source>Unsigned Integer:</source>
<translation>Unsigned Integer:</translation>
<translation>Ganzzahl ohne Vorzeichen:</translation>
</message>
</context>
<context>
@ -840,7 +840,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../ObjView.ui" line="386"/>
<source>Transform</source>
<translation>Transform</translation>
<translation>Verwandeln</translation>
</message>
<message>
<location filename="../ObjView.ui" line="406"/>
@ -905,7 +905,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../ObjView.ui" line="576"/>
<source>Mosaic</source>
<translation>Mosaic</translation>
<translation>Mosaik</translation>
</message>
<message>
<location filename="../ObjView.ui" line="613"/>
@ -920,7 +920,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../ObjView.ui" line="682"/>
<source>Tile</source>
<translation></translation>
<translation>Kachel</translation>
</message>
<message>
<location filename="../ObjView.ui" line="137"/>
@ -1550,7 +1550,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="65"/>
<source>Swap green components</source>
<translation type="unfinished"></translation>
<translation>Grüne Komponenten tauschen</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="69"/>
@ -1680,7 +1680,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="211"/>
<location filename="../IOViewer.cpp" line="220"/>
<source>Fractional part</source>
<translation type="unfinished"></translation>
<translation>Bruchteil</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="154"/>
@ -1700,7 +1700,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="212"/>
<location filename="../IOViewer.cpp" line="221"/>
<source>Integer part (low)</source>
<translation type="unfinished"></translation>
<translation>Ganzzahl-Anteil (tief)</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="178"/>
@ -1708,7 +1708,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="216"/>
<location filename="../IOViewer.cpp" line="225"/>
<source>Integer part (high)</source>
<translation type="unfinished"></translation>
<translation>Ganzzahl-Anteil (hoch)</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="229"/>
@ -1978,19 +1978,19 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="328"/>
<location filename="../IOViewer.cpp" line="1099"/>
<source>Sweep shifts</source>
<translation type="unfinished"></translation>
<translation>Schwung-Verschiebungen</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="329"/>
<location filename="../IOViewer.cpp" line="1100"/>
<source>Sweep subtract</source>
<translation type="unfinished"></translation>
<translation>Schwung subtrahieren</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="330"/>
<location filename="../IOViewer.cpp" line="1101"/>
<source>Sweep time (in 1/128s)</source>
<translation type="unfinished"></translation>
<translation>Schwungzeit (in 1/128s)</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="334"/>
@ -2010,7 +2010,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="1106"/>
<location filename="../IOViewer.cpp" line="1129"/>
<source>Duty cycle</source>
<translation type="unfinished"></translation>
<translation>Auslastungsgrad</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="336"/>
@ -2020,7 +2020,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="1133"/>
<location filename="../IOViewer.cpp" line="1182"/>
<source>Envelope step time</source>
<translation type="unfinished"></translation>
<translation>Hüllkurve-Schrittzeit</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="337"/>
@ -2076,7 +2076,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="368"/>
<source>Double-size wave table</source>
<translation type="unfinished"></translation>
<translation>Doppelte Größe Wave-Table</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="369"/>
@ -2140,7 +2140,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="406"/>
<location filename="../IOViewer.cpp" line="1189"/>
<source>Register stages</source>
<translation type="unfinished"></translation>
<translation>Register-Stufen</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="407"/>
@ -2158,7 +2158,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="410"/>
<location filename="../IOViewer.cpp" line="1193"/>
<source>Shifter frequency</source>
<translation type="unfinished"></translation>
<translation>Shifter-Frequenz</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="418"/>
@ -2226,12 +2226,12 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="437"/>
<source>Loud channel A</source>
<translation type="unfinished"></translation>
<translation>Lautkanal A</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="438"/>
<source>Loud channel B</source>
<translation type="unfinished"></translation>
<translation>Lautkanal B</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="439"/>
@ -2325,7 +2325,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="466"/>
<source>Bias</source>
<translation type="unfinished"></translation>
<translation>Vorspannung</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="467"/>
@ -2406,7 +2406,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="1321"/>
<location filename="../IOViewer.cpp" line="1322"/>
<source>Sample</source>
<translation>Sample</translation>
<translation>Abtastwert</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="561"/>
@ -2568,7 +2568,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="685"/>
<location filename="../IOViewer.cpp" line="731"/>
<source>Start timing</source>
<translation type="unfinished"></translation>
<translation>Zeitpunkt des Starts</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="596"/>
@ -2635,7 +2635,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="689"/>
<location filename="../IOViewer.cpp" line="735"/>
<source>Audio FIFO</source>
<translation>Audio FIFO</translation>
<translation>Audio-FIFO</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="726"/>
@ -2931,7 +2931,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="1014"/>
<source>PHI terminal</source>
<translation type="unfinished"></translation>
<translation>PHI-Terminal</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1015"/>
@ -2942,17 +2942,17 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="1016"/>
<source>4.19MHz</source>
<translation>4,19&#xa0;MHz</translation>
<translation>4,19 MHz</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1017"/>
<source>8.38MHz</source>
<translation>8,38&#xa0;MHz</translation>
<translation>8,38 MHz</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1018"/>
<source>16.78MHz</source>
<translation>16,78&#xa0;MHz</translation>
<translation>16,78 MHz</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1020"/>
@ -3007,7 +3007,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="1049"/>
<source>Transfer active</source>
<translation type="unfinished"></translation>
<translation>Übertragung aktiv</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1067"/>
@ -3023,65 +3023,65 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="1092"/>
<location filename="../IOViewer.cpp" line="1553"/>
<source>LCD STAT</source>
<translation type="unfinished"></translation>
<translation>LCD STAT</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1093"/>
<location filename="../IOViewer.cpp" line="1554"/>
<source>Timer</source>
<translation type="unfinished"></translation>
<translation>Timer</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1094"/>
<location filename="../IOViewer.cpp" line="1555"/>
<source>Serial</source>
<translation type="unfinished"></translation>
<translation>Serial</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1095"/>
<location filename="../IOViewer.cpp" line="1556"/>
<source>Joypad</source>
<translation type="unfinished"></translation>
<translation>Gamepad</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1202"/>
<source>Volume right</source>
<translation type="unfinished"></translation>
<translation>Lautstärke rechts</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1203"/>
<source>Output right</source>
<translation type="unfinished"></translation>
<translation>Ausgabe rechts</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1204"/>
<source>Volume left</source>
<translation type="unfinished"></translation>
<translation>Lautstärke links</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1205"/>
<source>Output left</source>
<translation type="unfinished"></translation>
<translation>Ausgabe links</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1326"/>
<source>Background enable/priority</source>
<translation type="unfinished"></translation>
<translation>Hintergrund aktivieren/Priorität</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1327"/>
<source>Enable sprites</source>
<translation type="unfinished"></translation>
<translation>Sprites aktivieren</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1328"/>
<source>Double-height sprites</source>
<translation type="unfinished"></translation>
<translation>Doppelte Höhe Sprites</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1329"/>
<source>Background tile map</source>
<translation type="unfinished"></translation>
<translation>Hintergrundkachelkarte</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1330"/>
@ -3098,7 +3098,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="1333"/>
<source>Background tile data</source>
<translation type="unfinished"></translation>
<translation>Hintergrundkacheldaten</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1334"/>
@ -3113,12 +3113,12 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="1337"/>
<source>Enable window</source>
<translation type="unfinished"></translation>
<translation>Fenster aktivieren</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1338"/>
<source>Window tile map</source>
<translation type="unfinished"></translation>
<translation>Fensterkachelkarte</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1342"/>
@ -3133,7 +3133,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="1347"/>
<source>0: HBlank</source>
<translation>HBlank</translation>
<translation>0: HBlank</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1348"/>
@ -3143,7 +3143,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="1349"/>
<source>2: OAM scan</source>
<translation>2: OAM scan</translation>
<translation>2: OAM-Überprüfung</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1350"/>
@ -3153,75 +3153,75 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="1352"/>
<source>In LYC</source>
<translation type="unfinished"></translation>
<translation>In LYC</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1353"/>
<source>Enable HBlank (mode 0) IRQ</source>
<translation type="unfinished"></translation>
<translation>HBlank aktivieren (Modus 0) IRQ</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1354"/>
<source>Enable VBlank (mode 1) IRQ</source>
<translation type="unfinished"></translation>
<translation>VBlank aktivieren (Modus 1) IRQ</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1355"/>
<source>Enable OAM (mode 2) IRQ</source>
<translation type="unfinished"></translation>
<translation>OAM aktivieren (Modus 2) IRQ</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1356"/>
<source>Enable LYC IRQ</source>
<translation type="unfinished"></translation>
<translation>LYC aktivieren IRQ</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1368"/>
<source>Current Y coordinate</source>
<translation type="unfinished"></translation>
<translation>Aktuelle Y-Koordinate</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1372"/>
<source>Comparison Y coordinate</source>
<translation type="unfinished"></translation>
<translation>Vergleich Y-Koordinate</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1376"/>
<source>Start upper byte</source>
<translation type="unfinished"></translation>
<translation>Oberes Byte starten</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1380"/>
<location filename="../IOViewer.cpp" line="1387"/>
<location filename="../IOViewer.cpp" line="1394"/>
<source>Color 0 shade</source>
<translation type="unfinished"></translation>
<translation>Farbe 0 Farbton</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1381"/>
<location filename="../IOViewer.cpp" line="1388"/>
<location filename="../IOViewer.cpp" line="1395"/>
<source>Color 1 shade</source>
<translation type="unfinished"></translation>
<translation>Farbe 1 Farbton</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1382"/>
<location filename="../IOViewer.cpp" line="1389"/>
<location filename="../IOViewer.cpp" line="1396"/>
<source>Color 2 shade</source>
<translation type="unfinished"></translation>
<translation>Farbe 2 Farbton</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1383"/>
<location filename="../IOViewer.cpp" line="1390"/>
<location filename="../IOViewer.cpp" line="1397"/>
<source>Color 3 shade</source>
<translation type="unfinished"></translation>
<translation>Farbe 3 Farbton</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1411"/>
<source>Prepare to switch speed</source>
<translation type="unfinished"></translation>
<translation>Zu Geschwindigkeit wechseln vorbereiten</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1412"/>
@ -3236,22 +3236,22 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="1440"/>
<source>Length</source>
<translation type="unfinished"></translation>
<translation>Länge</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1441"/>
<source>Timing</source>
<translation type="unfinished"></translation>
<translation>Timing</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1448"/>
<source>Write bit</source>
<translation type="unfinished"></translation>
<translation>Bit schreiben</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1449"/>
<source>Read bit</source>
<translation type="unfinished"></translation>
<translation>Bit lesen</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1452"/>
@ -3263,7 +3263,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<location filename="../IOViewer.cpp" line="1493"/>
<location filename="../IOViewer.cpp" line="1505"/>
<source>Current index</source>
<translation type="unfinished"></translation>
<translation>Aktueller Index</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1494"/>
@ -3286,17 +3286,17 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../IOViewer.cpp" line="1517"/>
<source>Sprite ordering</source>
<translation type="unfinished"></translation>
<translation>Sprite-Anordnung</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1518"/>
<source>OAM order</source>
<translation type="unfinished"></translation>
<translation>OAM-Anordnung</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1519"/>
<source>x coordinate sorting</source>
<translation type="unfinished"></translation>
<translation>X-Koordinatensortierung</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1530"/>
@ -4087,7 +4087,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../Window.cpp" line="410"/>
<source>Patches (*.ips *.ups *.bps)</source>
<translation>Patches (*.ips *.ups *.bps)</translation>
<translation>Korrekturen (*.ips *.ups *.bps)</translation>
</message>
<message>
<location filename="../Window.cpp" line="434"/>
@ -4980,12 +4980,12 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../SaveConverter.cpp" line="401"/>
<source>little endian</source>
<translation>little endian</translation>
<translation>little-endian</translation>
</message>
<message>
<location filename="../SaveConverter.cpp" line="404"/>
<source>big endian</source>
<translation>big endian</translation>
<translation>big-endian</translation>
</message>
<message>
<location filename="../SaveConverter.cpp" line="415"/>
@ -5322,8 +5322,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../SettingsView.ui" line="444"/>
<source>Force integer scaling</source>
<translation>Erzwinge pixelgenaue Skalierung
(Integer scaling)</translation>
<translation>Erzwinge pixelgenaue Skalierung</translation>
</message>
<message>
<location filename="../SettingsView.ui" line="458"/>
@ -5384,8 +5383,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
<message>
<location filename="../SettingsView.ui" line="961"/>
<source>Enable Game Boy Player features by default</source>
<translation>Game Boy Player-Features
standardmäßig aktivieren</translation>
<translation>Game Boy Player-Features standardmäßig aktivieren</translation>
</message>
<message>
<location filename="../SettingsView.ui" line="1858"/>
@ -5430,8 +5428,7 @@ standardmäßig aktivieren</translation>
<message>
<location filename="../SettingsView.ui" line="592"/>
<source>Show filename instead of ROM name in title bar</source>
<translation>Dateinamen statt ROM-Namen in der
Titelleiste anzeigen</translation>
<translation>Dateinamen statt ROM-Namen in der Titelleiste anzeigen</translation>
</message>
<message>
<location filename="../SettingsView.ui" line="740"/>
@ -5566,8 +5563,7 @@ Titelleiste anzeigen</translation>
<message>
<location filename="../SettingsView.ui" line="872"/>
<source>Preload entire ROM into memory</source>
<translation>ROM-Datei vollständig
in Arbeitsspeicher vorladen</translation>
<translation>ROM-Datei vollständig in Arbeitsspeicher vorladen</translation>
</message>
<message>
<location filename="../SettingsView.ui" line="1092"/>
@ -5595,8 +5591,7 @@ in Arbeitsspeicher vorladen</translation>
<message>
<location filename="../SettingsView.ui" line="1101"/>
<source>Use BIOS file if found</source>
<translation>BIOS-Datei verwenden,
wenn vorhanden</translation>
<translation>BIOS-Datei verwenden, wenn vorhanden</translation>
</message>
<message>
<location filename="../SettingsView.ui" line="1111"/>
@ -5733,12 +5728,12 @@ wenn vorhanden</translation>
<message>
<location filename="../SettingsView.ui" line="1305"/>
<source>Screenshots</source>
<translation>Screenshots</translation>
<translation>Bildschirmfotos</translation>
</message>
<message>
<location filename="../SettingsView.ui" line="1353"/>
<source>Patches</source>
<translation>Patches</translation>
<translation>Korrekturen</translation>
</message>
</context>
<context>
@ -5807,7 +5802,7 @@ wenn vorhanden</translation>
<message>
<location filename="../TileView.ui" line="14"/>
<source>Tiles</source>
<translation>Tiles</translation>
<translation>Kacheln</translation>
</message>
<message>
<location filename="../TileView.ui" line="20"/>

View File

@ -1862,27 +1862,27 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd.</translation>
<message>
<location filename="../IOViewer.cpp" line="288"/>
<source>BG 0 target 1</source>
<translation>BG 0 target 1</translation>
<translation>BG 0 objetivo 1</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="289"/>
<source>BG 1 target 1</source>
<translation>BG 1 target 1</translation>
<translation>BG 1 objetivo 1</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="290"/>
<source>BG 2 target 1</source>
<translation>BG 2 target 1</translation>
<translation>BG 2 objetivo 1</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="291"/>
<source>BG 3 target 1</source>
<translation>BG 3 target 1</translation>
<translation>BG 3 objetivo 1</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="292"/>
<source>OBJ target 1</source>
<translation>OBJ target 1</translation>
<translation>OBJ objetivo 1</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="293"/>
@ -1917,27 +1917,27 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd.</translation>
<message>
<location filename="../IOViewer.cpp" line="300"/>
<source>BG 0 target 2</source>
<translation>BG 0 target 2</translation>
<translation>BG 0 objetivo 2</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="301"/>
<source>BG 1 target 2</source>
<translation>BG 1 target 2</translation>
<translation>BG 1 objetivo 2</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="302"/>
<source>BG 2 target 2</source>
<translation>BG 2 target 2</translation>
<translation>BG 2 objetivo 2</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="303"/>
<source>BG 3 target 2</source>
<translation>BG 3 target 2</translation>
<translation>BG 3 objetivo 2</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="304"/>
<source>OBJ target 2</source>
<translation>OBJ target 2</translation>
<translation>OBJ objetivo 2</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="305"/>
@ -1947,12 +1947,12 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd.</translation>
<message>
<location filename="../IOViewer.cpp" line="309"/>
<source>Blend A (target 1)</source>
<translation>Mezcla A (target 1)</translation>
<translation>Mezcla A (objetivo 1)</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="310"/>
<source>Blend B (target 2)</source>
<translation>Mezcla B (target 2)</translation>
<translation>Mezcla B (objetivo 2)</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="314"/>
@ -2044,7 +2044,7 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd.</translation>
<location filename="../IOViewer.cpp" line="1171"/>
<location filename="../IOViewer.cpp" line="1197"/>
<source>Timed</source>
<translation>Timed</translation>
<translation>Cronometrado</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="344"/>
@ -2620,7 +2620,7 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd.</translation>
<location filename="../IOViewer.cpp" line="689"/>
<location filename="../IOViewer.cpp" line="735"/>
<source>Audio FIFO</source>
<translation>Audio FIFO</translation>
<translation>FIFO de audio</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="726"/>
@ -2835,7 +2835,7 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd.</translation>
<location filename="../IOViewer.cpp" line="956"/>
<location filename="../IOViewer.cpp" line="973"/>
<source>Keypad</source>
<translation>Keypad</translation>
<translation>Teclado numérico</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="957"/>
@ -2916,7 +2916,7 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd.</translation>
<message>
<location filename="../IOViewer.cpp" line="1014"/>
<source>PHI terminal</source>
<translation>PHI terminal</translation>
<translation>Terminal PHI</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1015"/>

View File

@ -221,37 +221,37 @@ Game Boy Advance 是任天堂有限公司Nintendo Co., Ltd.)的注册商标
<message>
<location filename="../DolphinConnector.ui" line="14"/>
<source>Connect to Dolphin</source>
<translation type="unfinished"></translation>
<translation> Dolphin</translation>
</message>
<message>
<location filename="../DolphinConnector.ui" line="23"/>
<source>Local computer</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<location filename="../DolphinConnector.ui" line="36"/>
<source>IP address</source>
<translation type="unfinished"></translation>
<translation>IP </translation>
</message>
<message>
<location filename="../DolphinConnector.ui" line="55"/>
<source>Connect</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<location filename="../DolphinConnector.ui" line="68"/>
<source>Disconnect</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<location filename="../DolphinConnector.ui" line="78"/>
<source>Close</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<location filename="../DolphinConnector.ui" line="90"/>
<source>Reset on connect</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
</context>
<context>
@ -2952,27 +2952,27 @@ Game Boy Advance 是任天堂有限公司Nintendo Co., Ltd.)的注册商标
<message>
<location filename="../IOViewer.cpp" line="1034"/>
<source>Right/A</source>
<translation type="unfinished"></translation>
<translation>/A</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1035"/>
<source>Left/B</source>
<translation type="unfinished"></translation>
<translation>/B</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1036"/>
<source>Up/Select</source>
<translation type="unfinished"></translation>
<translation>/</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1037"/>
<source>Down/Start</source>
<translation type="unfinished"></translation>
<translation>/</translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1038"/>
<source>Active D-pad</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<location filename="../IOViewer.cpp" line="1039"/>

View File

@ -2,6 +2,7 @@ include(ExportDirectory)
set(SOURCE_FILES
circle-buffer.c
configuration.c
convolve.c
crc32.c
elf-read.c
export.c

138
src/util/convolve.c Normal file
View File

@ -0,0 +1,138 @@
/* Copyright (c) 2013-2021 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 <mgba-util/convolve.h>
void ConvolutionKernelCreate(struct ConvolutionKernel* kernel, size_t rank, size_t* dims) {
kernel->rank = rank;
kernel->dims = malloc(sizeof(kernel->dims[0]) * rank);
size_t ksize = 1;
size_t i;
for (i = 0; i < rank; ++i) {
kernel->dims[i] = dims[i];
ksize *= dims[i];
}
kernel->kernel = calloc(ksize, sizeof(float));
}
void ConvolutionKernelDestroy(struct ConvolutionKernel* kernel) {
free(kernel->kernel);
free(kernel->dims);
kernel->kernel = NULL;
kernel->dims = NULL;
kernel->rank = 0;
}
void ConvolutionKernelFillRadial(struct ConvolutionKernel* kernel, bool normalize) {
if (kernel->rank != 2) {
return;
}
float support;
if (normalize) {
support = 12.f / (M_PI * (kernel->dims[0] - 1) * (kernel->dims[1] - 1));
} else {
support = 1.f;
}
float wr = (kernel->dims[0] - 1) / 2.f;
float hr = (kernel->dims[1] - 1) / 2.f;
float* elem = kernel->kernel;
size_t y;
for (y = 0; y < kernel->dims[1]; ++y) {
size_t x;
for (x = 0; x < kernel->dims[0]; ++x) {
float r = (1.f - hypotf((x - wr) / wr, (y - hr) / hr)) * support;
*elem = fmaxf(0, r);
++elem;
}
}
}
void ConvolutionKernelFillCircle(struct ConvolutionKernel* kernel, bool normalize) {
if (kernel->rank != 2) {
return;
}
float support;
if (normalize) {
support = 4.f / (M_PI * (kernel->dims[0] - 1) * (kernel->dims[1] - 1));
} else {
support = 1.f;
}
float wr = (kernel->dims[0] - 1) / 2.f;
float hr = (kernel->dims[1] - 1) / 2.f;
float* elem = kernel->kernel;
size_t y;
for (y = 0; y < kernel->dims[1]; ++y) {
size_t x;
for (x = 0; x < kernel->dims[0]; ++x) {
float r = hypotf((x - wr) / wr, (y - hr) / hr);
*elem = r <= 1.f ? support : 0.f;
++elem;
}
}
}
void Convolve1DPad0PackedS32(const int32_t* restrict src, int32_t* restrict dst, size_t length, const struct ConvolutionKernel* restrict kernel) {
if (kernel->rank != 1) {
return;
}
size_t kx2 = kernel->dims[0] / 2;
size_t x;
for (x = 0; x < length; ++x) {
float sum = 0.f;
size_t kx;
for (kx = 0; kx < kernel->dims[0]; ++kx) {
if (x + kx <= kx2) {
continue;
}
size_t cx = x + kx - kx2;
if (cx >= length) {
continue;
}
sum += src[cx] * kernel->kernel[kx];
}
*dst = sum;
++dst;
}
}
void Convolve2DClampPacked8(const uint8_t* restrict src, uint8_t* restrict dst, size_t width, size_t height, size_t stride, const struct ConvolutionKernel* restrict kernel) {
if (kernel->rank != 2) {
return;
}
size_t kx2 = kernel->dims[0] / 2;
size_t ky2 = kernel->dims[1] / 2;
size_t y;
for (y = 0; y < height; ++y) {
uint8_t* orow = &dst[y * stride];
size_t x;
for (x = 0; x < width; ++x) {
float sum = 0.f;
size_t ky;
for (ky = 0; ky < kernel->dims[1]; ++ky) {
size_t cy = 0;
if (y + ky > ky2) {
cy = y + ky - ky2;
}
if (cy >= height) {
cy = height - 1;
}
const uint8_t* irow = &src[cy * stride];
size_t kx;
for (kx = 0; kx < kernel->dims[0]; ++kx) {
size_t cx = 0;
if (x + kx > kx2) {
cx = x + kx - kx2;
}
if (cx >= width) {
cx = width - 1;
}
sum += irow[cx] * kernel->kernel[ky * kernel->dims[0] + kx];
}
}
*orow = sum;
++orow;
}
}
}