mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' into medusa
This commit is contained in:
commit
e5c6373f88
|
@ -1,7 +1,7 @@
|
|||
#!/bin/sh
|
||||
if [ $TRAVIS_OS_NAME = "osx" ]; then
|
||||
brew update
|
||||
brew install qt5 ffmpeg sdl2 libedit libelf libpng libzip
|
||||
brew install qt5 ffmpeg sdl2 libelf libpng libzip
|
||||
else
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install libseccomp2
|
||||
|
|
45
CHANGES
45
CHANGES
|
@ -19,34 +19,65 @@ Misc:
|
|||
- DS Video: Simplify VRAM mapping
|
||||
|
||||
0.9.0: (Future)
|
||||
Features:
|
||||
- Add APNG recording
|
||||
Emulation fixes:
|
||||
- ARM: Fix ALU reading PC after shifting
|
||||
- ARM: Fix STR storing PC after address calculation
|
||||
- GBA BIOS: Implement dummy sound driver calls
|
||||
- GBA BIOS: Improve HLE BIOS timing
|
||||
- GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320)
|
||||
- GBA Memory: Misaligned SRAM writes are ignored
|
||||
- GBA Memory: Improve gamepak prefetch timing
|
||||
- GBA Serialize: Fix serializing DMA transfer register
|
||||
- GBA Serialize: Fix audio serialization for desynced FIFOs
|
||||
- GBA Serialize: Fix audio DMA timing deserialization
|
||||
- GBA Video: Fix OAM not invalidating after reset (fixes mgba.io/i/1630)
|
||||
- GBA Video: Latch scanline at end of Hblank (fixes mgba.io/i/1319)
|
||||
- GBA Video: Fix Hblank timing
|
||||
Other fixes:
|
||||
- Core: Ensure ELF regions can be written before trying
|
||||
- Core: Fix ELF loading regression (fixes mgba.io/i/1669)
|
||||
- Debugger: Don't skip undefined instructions when debugger attached
|
||||
- Qt: Force OpenGL paint engine creation thread (fixes mgba.io/i/1642)
|
||||
Misc:
|
||||
- FFmpeg: Add looping option for GIF/APNG
|
||||
- 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
|
||||
|
||||
0.8.1: (2020-02-16)
|
||||
Emulation fixes:
|
||||
- GB Serialize: Fix timing bug loading channel 4 timing
|
||||
- GBA: Fix multiboot entry point while skipping BIOS
|
||||
- GBA BIOS: Fix undefined instruction HLE behavior
|
||||
- GBA DMA: Fix invalid audio DMA parameters
|
||||
- GBA Memory: Misaligned SRAM writes are ignored
|
||||
- GBA Serialize: Fix serializing DMA transfer register
|
||||
- GBA Serialize: Fix audio DMA timing deserialization
|
||||
- GBA Video: Fix OAM not invalidating after reset (fixes mgba.io/i/1630)
|
||||
- GBA Video: Fix backdrop blending on lines without sprites (fixes mgba.io/i/1647)
|
||||
- GBA Video: Fix OpenGL sprite flag priority
|
||||
Other fixes:
|
||||
- Core: Fix race condition initializing thread proxy
|
||||
- Core: Fix integer overflow in ELF loading
|
||||
- FFmpeg: Fix crash when -strict -2 is needed for vcodec or container
|
||||
- FFmpeg: Disallow recording video with no audio nor video
|
||||
- GBA: Automatically skip BIOS for multiboot ROMs
|
||||
- Qt: Only dynamically reset video scale if a game is running
|
||||
- Qt: Fix race condition with proxied video events
|
||||
- Qt: Force OpenGL paint engine creation thread (fixes mgba.io/i/1642)
|
||||
- Qt: Fix color selection in asset view (fixes mgba.io/i/1648)
|
||||
- Qt: Fix missing OSD messages
|
||||
- Qt: Fix crash unloading shaders
|
||||
- Qt: Fix toggled actions on gamepads (fixes mgba.io/i/1650)
|
||||
- Qt: Fix extraneous dialog (fixes mgba.io/i/1654)
|
||||
- Qt: Fix window title not updating after shutting down game
|
||||
- Qt: Fix GIF view not allowing manual filename entry
|
||||
- Qt: Fix non-GB build (fixes mgba.io/i/1664)
|
||||
- Qt: Fix pausing Qt Multimedia audio (fixes mgba.io/i/1643)
|
||||
- Qt: Fix invalid names for modifier keys (fixes mgba.io/i/525)
|
||||
- SDL: Refresh stale pointers after adding a joystick (fixes mgba.io/i/1622)
|
||||
- Util: Fix crash reading invalid ELFs
|
||||
- VFS: Fix handle leak when double-mapping (fixes mgba.io/i/1659)
|
||||
Misc:
|
||||
- Qt: Renderer can be changed while a game is running
|
||||
- FFmpeg: Add more presets
|
||||
- Qt: Fix non-SDL build (fixes mgba.io/i/1656)
|
||||
- SDL: Use DirectSound audio driver by default on Windows
|
||||
- Switch: Make OpenGL scale adjustable while running
|
||||
|
||||
0.8.0: (2020-01-21)
|
||||
|
|
|
@ -870,6 +870,9 @@ if(NOT SKIP_LIBRARY)
|
|||
|
||||
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})
|
||||
if(BUILD_SHARED)
|
||||
install(TARGETS ${BINARY_NAME} LIBRARY DESTINATION ${LIBDIR} COMPONENT ${BINARY_NAME}-dev NAMELINK_ONLY)
|
||||
endif()
|
||||
if(UNIX AND NOT APPLE AND NOT HAIKU)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/mgba-16.png DESTINATION share/icons/hicolor/16x16/apps RENAME mgba.png COMPONENT lib${BINARY_NAME})
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/mgba-24.png DESTINATION share/icons/hicolor/24x24/apps RENAME mgba.png COMPONENT lib${BINARY_NAME})
|
||||
|
|
|
@ -20,15 +20,21 @@ CXX_GUARD_START
|
|||
#define SOCKET_FAILED(s) ((s) == INVALID_SOCKET)
|
||||
typedef SOCKET Socket;
|
||||
#else
|
||||
#ifdef GEKKO
|
||||
#include <network.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#ifndef GEKKO
|
||||
#define INVALID_SOCKET (-1)
|
||||
#endif
|
||||
#define SOCKET_FAILED(s) ((s) < 0)
|
||||
typedef int Socket;
|
||||
#endif
|
||||
|
@ -70,6 +76,8 @@ static inline void SocketSubsystemInit() {
|
|||
}
|
||||
#elif defined(__SWITCH__)
|
||||
socketInitializeDefault();
|
||||
#elif defined(GEKKO)
|
||||
net_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -82,6 +90,8 @@ static inline void SocketSubsystemDeinit() {
|
|||
SOCUBuffer = NULL;
|
||||
#elif defined(__SWITCH__)
|
||||
socketExit();
|
||||
#elif defined(GEKKO)
|
||||
net_deinit();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -104,6 +114,8 @@ static inline bool SocketWouldBlock() {
|
|||
static inline ssize_t SocketSend(Socket socket, const void* buffer, size_t size) {
|
||||
#ifdef _WIN32
|
||||
return send(socket, (const char*) buffer, size, 0);
|
||||
#elif defined(GEKKO)
|
||||
return net_write(socket, buffer, size);
|
||||
#else
|
||||
return write(socket, buffer, size);
|
||||
#endif
|
||||
|
@ -112,6 +124,8 @@ static inline ssize_t SocketSend(Socket socket, const void* buffer, size_t size)
|
|||
static inline ssize_t SocketRecv(Socket socket, void* buffer, size_t size) {
|
||||
#if defined(_WIN32) || defined(__SWITCH__)
|
||||
return recv(socket, (char*) buffer, size, 0);
|
||||
#elif defined(GEKKO)
|
||||
return net_read(socket, buffer, size);
|
||||
#else
|
||||
return read(socket, buffer, size);
|
||||
#endif
|
||||
|
@ -120,13 +134,19 @@ static inline ssize_t SocketRecv(Socket socket, void* buffer, size_t size) {
|
|||
static inline int SocketClose(Socket socket) {
|
||||
#ifdef _WIN32
|
||||
return closesocket(socket) == 0;
|
||||
#elif defined(GEKKO)
|
||||
return net_close(socket) >= 0;
|
||||
#else
|
||||
return close(socket) >= 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress) {
|
||||
#ifdef GEKKO
|
||||
Socket sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
#else
|
||||
Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
#endif
|
||||
if (SOCKET_FAILED(sock)) {
|
||||
return sock;
|
||||
}
|
||||
|
@ -142,15 +162,23 @@ static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress)
|
|||
#else
|
||||
bindInfo.sin_addr.s_addr = gethostid();
|
||||
#endif
|
||||
#ifdef GEKKO
|
||||
err = net_bind(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
|
||||
#else
|
||||
err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
|
||||
#endif
|
||||
} else if (bindAddress->version == IPV4) {
|
||||
struct sockaddr_in bindInfo;
|
||||
memset(&bindInfo, 0, sizeof(bindInfo));
|
||||
bindInfo.sin_family = AF_INET;
|
||||
bindInfo.sin_port = htons(port);
|
||||
bindInfo.sin_addr.s_addr = htonl(bindAddress->ipv4);
|
||||
#ifdef GEKKO
|
||||
err = net_bind(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
|
||||
#else
|
||||
err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
|
||||
#ifndef _3DS
|
||||
#endif
|
||||
#if !defined(_3DS) && !defined(GEKKO)
|
||||
} else {
|
||||
struct sockaddr_in6 bindInfo;
|
||||
memset(&bindInfo, 0, sizeof(bindInfo));
|
||||
|
@ -168,7 +196,11 @@ static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress)
|
|||
}
|
||||
|
||||
static inline Socket SocketConnectTCP(int port, const struct Address* destinationAddress) {
|
||||
#ifdef GEKKO
|
||||
Socket sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
#else
|
||||
Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
#endif
|
||||
if (SOCKET_FAILED(sock)) {
|
||||
return sock;
|
||||
}
|
||||
|
@ -179,15 +211,23 @@ static inline Socket SocketConnectTCP(int port, const struct Address* destinatio
|
|||
memset(&bindInfo, 0, sizeof(bindInfo));
|
||||
bindInfo.sin_family = AF_INET;
|
||||
bindInfo.sin_port = htons(port);
|
||||
#ifdef GEKKO
|
||||
err = net_connect(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
|
||||
#else
|
||||
err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
|
||||
#endif
|
||||
} else if (destinationAddress->version == IPV4) {
|
||||
struct sockaddr_in bindInfo;
|
||||
memset(&bindInfo, 0, sizeof(bindInfo));
|
||||
bindInfo.sin_family = AF_INET;
|
||||
bindInfo.sin_port = htons(port);
|
||||
bindInfo.sin_addr.s_addr = htonl(destinationAddress->ipv4);
|
||||
#ifdef GEKKO
|
||||
err = net_connect(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
|
||||
#else
|
||||
err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
|
||||
#ifndef _3DS
|
||||
#endif
|
||||
#if !defined(_3DS) && !defined(GEKKO)
|
||||
} else {
|
||||
struct sockaddr_in6 bindInfo;
|
||||
memset(&bindInfo, 0, sizeof(bindInfo));
|
||||
|
@ -206,12 +246,23 @@ static inline Socket SocketConnectTCP(int port, const struct Address* destinatio
|
|||
}
|
||||
|
||||
static inline Socket SocketListen(Socket socket, int queueLength) {
|
||||
#ifdef GEKKO
|
||||
return net_listen(socket, queueLength);
|
||||
#else
|
||||
return listen(socket, queueLength);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline Socket SocketAccept(Socket socket, struct Address* address) {
|
||||
if (!address) {
|
||||
#ifdef GEKKO
|
||||
struct sockaddr_in addrInfo;
|
||||
memset(&addrInfo, 0, sizeof(addrInfo));
|
||||
socklen_t len = sizeof(addrInfo);
|
||||
return net_accept(socket, (struct sockaddr*) &addrInfo, &len);
|
||||
#else
|
||||
return accept(socket, 0, 0);
|
||||
#endif
|
||||
}
|
||||
if (address->version == IPV4) {
|
||||
struct sockaddr_in addrInfo;
|
||||
|
@ -219,8 +270,12 @@ static inline Socket SocketAccept(Socket socket, struct Address* address) {
|
|||
addrInfo.sin_family = AF_INET;
|
||||
addrInfo.sin_addr.s_addr = address->ipv4;
|
||||
socklen_t len = sizeof(addrInfo);
|
||||
#ifdef GEKKO
|
||||
return net_accept(socket, (struct sockaddr*) &addrInfo, &len);
|
||||
#else
|
||||
return accept(socket, (struct sockaddr*) &addrInfo, &len);
|
||||
#ifndef _3DS
|
||||
#endif
|
||||
#if !defined(_3DS) && !defined(GEKKO)
|
||||
} else {
|
||||
struct sockaddr_in6 addrInfo;
|
||||
memset(&addrInfo, 0, sizeof(addrInfo));
|
||||
|
@ -237,8 +292,12 @@ static inline int SocketSetBlocking(Socket socket, bool blocking) {
|
|||
#ifdef _WIN32
|
||||
u_long unblocking = !blocking;
|
||||
return ioctlsocket(socket, FIONBIO, &unblocking) == NO_ERROR;
|
||||
#else
|
||||
#ifdef GEKKO
|
||||
int flags = net_fcntl(socket, F_GETFL, 0);
|
||||
#else
|
||||
int flags = fcntl(socket, F_GETFL);
|
||||
#endif
|
||||
if (flags == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -247,12 +306,20 @@ static inline int SocketSetBlocking(Socket socket, bool blocking) {
|
|||
} else {
|
||||
flags |= O_NONBLOCK;
|
||||
}
|
||||
#ifdef GEKKO
|
||||
return net_fcntl(socket, F_SETFL, flags) >= 0;
|
||||
#else
|
||||
return fcntl(socket, F_SETFL, flags) >= 0;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int SocketSetTCPPush(Socket socket, int push) {
|
||||
#ifdef GEKKO
|
||||
return net_setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0;
|
||||
#else
|
||||
return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int SocketPoll(size_t nSockets, Socket* reads, Socket* writes, Socket* errors, int64_t timeoutMillis) {
|
||||
|
@ -304,7 +371,11 @@ static inline int SocketPoll(size_t nSockets, Socket* reads, Socket* writes, Soc
|
|||
struct timeval tv;
|
||||
tv.tv_sec = timeoutMillis / 1000;
|
||||
tv.tv_usec = (timeoutMillis % 1000) * 1000;
|
||||
#ifdef GEKKO
|
||||
int result = net_select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv);
|
||||
#else
|
||||
int result = select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv);
|
||||
#endif
|
||||
int r = 0;
|
||||
int w = 0;
|
||||
int e = 0;
|
||||
|
|
|
@ -208,6 +208,7 @@ void mCoreLoadForeignConfig(struct mCore* core, const struct mCoreConfig* config
|
|||
void mCoreSetRTC(struct mCore* core, struct mRTCSource* rtc);
|
||||
|
||||
void* mCoreGetMemoryBlock(struct mCore* core, uint32_t start, size_t* size);
|
||||
void* mCoreGetMemoryBlockMasked(struct mCore* core, uint32_t start, size_t* size, uint32_t mask);
|
||||
|
||||
#ifdef USE_ELF
|
||||
struct ELF;
|
||||
|
|
|
@ -176,6 +176,7 @@ enum mCoreMemoryBlockFlags {
|
|||
mCORE_MEMORY_READ = 0x01,
|
||||
mCORE_MEMORY_WRITE = 0x02,
|
||||
mCORE_MEMORY_RW = 0x03,
|
||||
mCORE_MEMORY_WORM = 0x04,
|
||||
mCORE_MEMORY_MAPPED = 0x10,
|
||||
mCORE_MEMORY_VIRTUAL = 0x20,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2013-2017 Jeffrey Pfau
|
||||
/* Copyright (c) 2013-2019 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
|
||||
|
@ -24,7 +24,6 @@ enum GBKey {
|
|||
GB_KEY_UP = 6,
|
||||
GB_KEY_DOWN = 7,
|
||||
GB_KEY_MAX,
|
||||
GB_KEY_NONE = -1
|
||||
};
|
||||
|
||||
CXX_GUARD_END
|
||||
|
|
|
@ -14,6 +14,52 @@ CXX_GUARD_START
|
|||
|
||||
mLOG_DECLARE_CATEGORY(GBA_BIOS);
|
||||
|
||||
enum GBASwi {
|
||||
GBA_SWI_SOFT_RESET = 0x00,
|
||||
GBA_SWI_REGISTER_RAM_RESET = 0x01,
|
||||
GBA_SWI_HALT = 0x02,
|
||||
GBA_SWI_STOP = 0x03,
|
||||
GBA_SWI_INTR_WAIT = 0x04,
|
||||
GBA_SWI_VBLANK_INTR_WAIT = 0x05,
|
||||
GBA_SWI_DIV = 0x06,
|
||||
GBA_SWI_DIV_ARM = 0x07,
|
||||
GBA_SWI_SQRT = 0x08,
|
||||
GBA_SWI_ARCTAN = 0x09,
|
||||
GBA_SWI_ARCTAN2 = 0x0A,
|
||||
GBA_SWI_CPU_SET = 0x0B,
|
||||
GBA_SWI_CPU_FAST_SET = 0x0C,
|
||||
GBA_SWI_GET_BIOS_CHECKSUM = 0x0D,
|
||||
GBA_SWI_BG_AFFINE_SET = 0x0E,
|
||||
GBA_SWI_OBJ_AFFINE_SET = 0x0F,
|
||||
GBA_SWI_BIT_UNPACK = 0x10,
|
||||
GBA_SWI_LZ77_UNCOMP_WRAM = 0x11,
|
||||
GBA_SWI_LZ77_UNCOMP_VRAM = 0x12,
|
||||
GBA_SWI_HUFFMAN_UNCOMP = 0x13,
|
||||
GBA_SWI_RL_UNCOMP_WRAM = 0x14,
|
||||
GBA_SWI_RL_UNCOMP_VRAM = 0x15,
|
||||
GBA_SWI_DIFF_8BIT_UNFILTER_WRAM = 0x16,
|
||||
GBA_SWI_DIFF_8BIT_UNFILTER_VRAM = 0x17,
|
||||
GBA_SWI_DIFF_16BIT_UNFILTER = 0x18,
|
||||
GBA_SWI_SOUND_BIAS = 0x19,
|
||||
GBA_SWI_SOUND_DRIVER_INIT = 0x1A,
|
||||
GBA_SWI_SOUND_DRIVER_MODE = 0x1B,
|
||||
GBA_SWI_SOUND_DRIVER_MAIN = 0x1C,
|
||||
GBA_SWI_SOUND_DRIVER_VSYNC = 0x1D,
|
||||
GBA_SWI_SOUND_CHANNEL_CLEAR = 0x1E,
|
||||
GBA_SWI_MIDI_KEY_2_FREQ = 0x1F,
|
||||
GBA_SWI_MUSIC_PLAYER_OPEN = 0x20,
|
||||
GBA_SWI_MUSIC_PLAYER_START = 0x21,
|
||||
GBA_SWI_MUSIC_PLAYER_STOP = 0x22,
|
||||
GBA_SWI_MUSIC_PLAYER_CONTINUE = 0x23,
|
||||
GBA_SWI_MUSIC_PLAYER_FADE_OUT = 0x24,
|
||||
GBA_SWI_MULTI_BOOT = 0x25,
|
||||
GBA_SWI_HARD_RESET = 0x26,
|
||||
GBA_SWI_CUSTOM_HALT = 0x27,
|
||||
GBA_SWI_SOUND_DRIVER_VSYNC_OFF = 0x28,
|
||||
GBA_SWI_SOUND_DRIVER_VSYNC_ON = 0x29,
|
||||
GBA_SWI_SOUND_DRIVER_GET_JUMP_LIST = 0x2A,
|
||||
};
|
||||
|
||||
struct ARMCore;
|
||||
void GBASwi16(struct ARMCore* cpu, int immediate);
|
||||
void GBASwi32(struct ARMCore* cpu, int immediate);
|
||||
|
|
|
@ -351,6 +351,10 @@ void mCoreSetRTC(struct mCore* core, struct mRTCSource* rtc) {
|
|||
}
|
||||
|
||||
void* mCoreGetMemoryBlock(struct mCore* core, uint32_t start, size_t* size) {
|
||||
return mCoreGetMemoryBlockMasked(core, start, size, mCORE_MEMORY_MAPPED);
|
||||
}
|
||||
|
||||
void* mCoreGetMemoryBlockMasked(struct mCore* core, uint32_t start, size_t* size, uint32_t mask) {
|
||||
const struct mCoreMemoryBlock* blocks;
|
||||
size_t nBlocks = core->listMemoryBlocks(core, &blocks);
|
||||
size_t i;
|
||||
|
@ -358,6 +362,9 @@ void* mCoreGetMemoryBlock(struct mCore* core, uint32_t start, size_t* size) {
|
|||
if (!(blocks[i].flags & mCORE_MEMORY_MAPPED)) {
|
||||
continue;
|
||||
}
|
||||
if (!(blocks[i].flags & mask)) {
|
||||
continue;
|
||||
}
|
||||
if (start < blocks[i].start) {
|
||||
continue;
|
||||
}
|
||||
|
@ -381,9 +388,9 @@ bool mCoreLoadELF(struct mCore* core, struct ELF* elf) {
|
|||
for (i = 0; i < ELFProgramHeadersSize(&ph); ++i) {
|
||||
size_t bsize, esize;
|
||||
Elf32_Phdr* phdr = ELFProgramHeadersGetPointer(&ph, i);
|
||||
void* block = mCoreGetMemoryBlock(core, phdr->p_paddr, &bsize);
|
||||
void* block = mCoreGetMemoryBlockMasked(core, phdr->p_paddr, &bsize, mCORE_MEMORY_WRITE | mCORE_MEMORY_WORM);
|
||||
char* bytes = ELFBytes(elf, &esize);
|
||||
if (block && bsize >= phdr->p_filesz && esize >= phdr->p_filesz + phdr->p_offset) {
|
||||
if (block && bsize >= phdr->p_filesz && esize > phdr->p_offset && esize >= phdr->p_filesz + phdr->p_offset) {
|
||||
memcpy(block, &bytes[phdr->p_offset], phdr->p_filesz);
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
@ -65,6 +65,7 @@ void FFmpegEncoderInit(struct FFmpegEncoder* encoder) {
|
|||
encoder->cycles = GBA_ARM7TDMI_FREQUENCY;
|
||||
encoder->frameskip = 1;
|
||||
encoder->skipResidue = 0;
|
||||
encoder->loop = false;
|
||||
encoder->ipixFormat =
|
||||
#ifdef COLOR_16_BIT
|
||||
#ifdef COLOR_5_6_5
|
||||
|
@ -232,11 +233,15 @@ void FFmpegEncoderSetDimensions(struct FFmpegEncoder* encoder, int width, int he
|
|||
encoder->height = height > 0 ? height : GBA_VIDEO_VERTICAL_PIXELS;
|
||||
}
|
||||
|
||||
void FFmpegEncoderSetLooping(struct FFmpegEncoder* encoder, bool loop) {
|
||||
encoder->loop = loop;
|
||||
}
|
||||
|
||||
bool FFmpegEncoderVerifyContainer(struct FFmpegEncoder* encoder) {
|
||||
AVOutputFormat* oformat = av_guess_format(encoder->containerFormat, 0, 0);
|
||||
AVCodec* acodec = avcodec_find_encoder_by_name(encoder->audioCodec);
|
||||
AVCodec* vcodec = avcodec_find_encoder_by_name(encoder->videoCodec);
|
||||
if ((encoder->audioCodec && !acodec) || (encoder->videoCodec && !vcodec) || !oformat) {
|
||||
if ((encoder->audioCodec && !acodec) || (encoder->videoCodec && !vcodec) || !oformat || (!acodec && !vcodec)) {
|
||||
return false;
|
||||
}
|
||||
if (encoder->audioCodec && !avformat_query_codec(oformat, acodec->id, FF_COMPLIANCE_EXPERIMENTAL)) {
|
||||
|
@ -449,8 +454,11 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
|
|||
encoder->sinkFrame = avcodec_alloc_frame();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (avcodec_open2(encoder->video, vcodec, 0) < 0) {
|
||||
AVDictionary* opts = 0;
|
||||
av_dict_set(&opts, "strict", "-2", 0);
|
||||
int res = avcodec_open2(encoder->video, vcodec, &opts);
|
||||
av_dict_free(&opts);
|
||||
if (res < 0) {
|
||||
FFmpegEncoderClose(encoder);
|
||||
return false;
|
||||
}
|
||||
|
@ -470,7 +478,17 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
|
|||
#endif
|
||||
}
|
||||
|
||||
if (avio_open(&encoder->context->pb, outfile, AVIO_FLAG_WRITE) < 0 || avformat_write_header(encoder->context, 0) < 0) {
|
||||
if (strcmp(encoder->containerFormat, "gif") == 0) {
|
||||
av_opt_set(encoder->context->priv_data, "loop", encoder->loop ? "0" : "-1", 0);
|
||||
} else if (strcmp(encoder->containerFormat, "apng") == 0) {
|
||||
av_opt_set(encoder->context->priv_data, "plays", encoder->loop ? "0" : "1", 0);
|
||||
}
|
||||
|
||||
AVDictionary* opts = 0;
|
||||
av_dict_set(&opts, "strict", "-2", 0);
|
||||
bool res = avio_open(&encoder->context->pb, outfile, AVIO_FLAG_WRITE) < 0 || avformat_write_header(encoder->context, &opts) < 0;
|
||||
av_dict_free(&opts);
|
||||
if (res) {
|
||||
FFmpegEncoderClose(encoder);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ struct FFmpegEncoder {
|
|||
unsigned cycles;
|
||||
int frameskip;
|
||||
int skipResidue;
|
||||
bool loop;
|
||||
int64_t currentVideoFrame;
|
||||
struct SwsContext* scaleContext;
|
||||
struct AVStream* videoStream;
|
||||
|
@ -98,6 +99,7 @@ bool FFmpegEncoderSetAudio(struct FFmpegEncoder*, const char* acodec, unsigned a
|
|||
bool FFmpegEncoderSetVideo(struct FFmpegEncoder*, const char* vcodec, unsigned vbr, int frameskip);
|
||||
bool FFmpegEncoderSetContainer(struct FFmpegEncoder*, const char* container);
|
||||
void FFmpegEncoderSetDimensions(struct FFmpegEncoder*, int width, int height);
|
||||
void FFmpegEncoderSetLooping(struct FFmpegEncoder*, bool loop);
|
||||
bool FFmpegEncoderVerifyContainer(struct FFmpegEncoder*);
|
||||
bool FFmpegEncoderOpen(struct FFmpegEncoder*, const char* outfile);
|
||||
void FFmpegEncoderClose(struct FFmpegEncoder*);
|
||||
|
|
|
@ -1078,9 +1078,13 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt
|
|||
LOAD_32LE(audio->ch4.lastEvent, 0, &state->ch4.lastEvent);
|
||||
LOAD_32LE(when, 0, &state->ch4.nextEvent);
|
||||
if (audio->ch4.envelope.dead < 2 && audio->playingCh4) {
|
||||
if (when - audio->ch4.lastEvent > (uint32_t) audio->sampleInterval) {
|
||||
if (!audio->ch4.lastEvent) {
|
||||
// Back-compat: fake this value
|
||||
audio->ch4.lastEvent = when - audio->sampleInterval;
|
||||
uint32_t currentTime = mTimingCurrentTime(audio->timing);
|
||||
int32_t cycles = audio->ch4.ratio ? 2 * audio->ch4.ratio : 1;
|
||||
cycles <<= audio->ch4.frequency;
|
||||
cycles *= 8 * audio->timingFactor;
|
||||
audio->ch4.lastEvent = currentTime + (when & (cycles - 1)) - cycles;
|
||||
}
|
||||
mTimingSchedule(audio->timing, &audio->ch4Event, when);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ static const struct mCoreChannelInfo _GBAudioChannels[] = {
|
|||
|
||||
static const struct mCoreMemoryBlock _GBMemoryBlocks[] = {
|
||||
{ -1, "mem", "All", "All", 0, 0x10000, 0x10000, mCORE_MEMORY_VIRTUAL },
|
||||
{ GB_REGION_CART_BANK0, "cart0", "ROM Bank", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_BASE_CART_BANK0 + GB_SIZE_CART_BANK0 * 2, 0x800000, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED, 511, GB_BASE_CART_BANK0 + GB_SIZE_CART_BANK0 },
|
||||
{ GB_REGION_CART_BANK0, "cart0", "ROM Bank", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_BASE_CART_BANK0 + GB_SIZE_CART_BANK0 * 2, 0x800000, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED, 511, GB_BASE_CART_BANK0 + GB_SIZE_CART_BANK0 },
|
||||
{ GB_REGION_VRAM, "vram", "VRAM", "Video RAM (8kiB)", GB_BASE_VRAM, GB_BASE_VRAM + GB_SIZE_VRAM, GB_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ GB_REGION_EXTERNAL_RAM, "sram", "SRAM", "External RAM (8kiB)", GB_BASE_EXTERNAL_RAM, GB_BASE_EXTERNAL_RAM + GB_SIZE_EXTERNAL_RAM, GB_SIZE_EXTERNAL_RAM * 4, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 3 },
|
||||
{ GB_REGION_WORKING_RAM_BANK0, "wram", "WRAM", "Working RAM (8kiB)", GB_BASE_WORKING_RAM_BANK0, GB_BASE_WORKING_RAM_BANK0 + GB_SIZE_WORKING_RAM_BANK0 * 2 , GB_SIZE_WORKING_RAM_BANK0 * 2, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
|
@ -56,7 +56,7 @@ static const struct mCoreMemoryBlock _GBMemoryBlocks[] = {
|
|||
|
||||
static const struct mCoreMemoryBlock _GBCMemoryBlocks[] = {
|
||||
{ -1, "mem", "All", "All", 0, 0x10000, 0x10000, mCORE_MEMORY_VIRTUAL },
|
||||
{ GB_REGION_CART_BANK0, "cart0", "ROM Bank", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_BASE_CART_BANK0 + GB_SIZE_CART_BANK0 * 2, 0x800000, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED, 511, GB_BASE_CART_BANK0 + GB_SIZE_CART_BANK0 },
|
||||
{ GB_REGION_CART_BANK0, "cart0", "ROM Bank", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_BASE_CART_BANK0 + GB_SIZE_CART_BANK0 * 2, 0x800000, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED, 511, GB_BASE_CART_BANK0 + GB_SIZE_CART_BANK0 },
|
||||
{ GB_REGION_VRAM, "vram", "VRAM", "Video RAM (8kiB)", GB_BASE_VRAM, GB_BASE_VRAM + GB_SIZE_VRAM, GB_SIZE_VRAM * 2, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 1 },
|
||||
{ GB_REGION_EXTERNAL_RAM, "sram", "SRAM", "External RAM (8kiB)", GB_BASE_EXTERNAL_RAM, GB_BASE_EXTERNAL_RAM + GB_SIZE_EXTERNAL_RAM, GB_SIZE_EXTERNAL_RAM * 4, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 3 },
|
||||
{ GB_REGION_WORKING_RAM_BANK0, "wram", "WRAM", "Working RAM (8kiB)", GB_BASE_WORKING_RAM_BANK0, GB_BASE_WORKING_RAM_BANK0 + GB_SIZE_WORKING_RAM_BANK0 * 2, GB_SIZE_WORKING_RAM_BANK0 * 8, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 7, GB_BASE_WORKING_RAM_BANK0 + GB_SIZE_WORKING_RAM_BANK0 },
|
||||
|
|
|
@ -16,13 +16,17 @@ static void _GBCLIDebuggerInit(struct CLIDebuggerSystem*);
|
|||
static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem*);
|
||||
|
||||
static void _frame(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
static void _load(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _save(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
#endif
|
||||
|
||||
struct CLIDebuggerCommandSummary _GBCLIDebuggerCommands[] = {
|
||||
{ "frame", _frame, "", "Frame advance" },
|
||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
{ "load", _load, "*", "Load a savestate" },
|
||||
{ "save", _save, "*", "Save a savestate" },
|
||||
#endif
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -73,6 +77,7 @@ static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
|||
gbDebugger->inVblank = GBRegisterSTATGetMode(((struct GB*) gbDebugger->core->board)->memory.io[REG_STAT]) == 1;
|
||||
}
|
||||
|
||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
struct CLIDebuggerBackend* be = debugger->backend;
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
|
@ -106,3 +111,4 @@ static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
|||
|
||||
mCoreSaveState(gbDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT | SAVESTATE_RTC | SAVESTATE_METADATA);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* Copyright (c) 2013-2017 Jeffrey Pfau
|
||||
/* Copyright (c) 2013-2019 Jeffrey Pfau
|
||||
>>>>>>> master
|
||||
*
|
||||
* 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
|
||||
|
@ -17,7 +18,7 @@ const struct mInputPlatformInfo GBInputInfo = {
|
|||
"Right",
|
||||
"Left",
|
||||
"Up",
|
||||
"Down"
|
||||
"Down",
|
||||
},
|
||||
.nKeys = GB_KEY_MAX,
|
||||
.hat = {
|
||||
|
|
|
@ -104,6 +104,8 @@ void GBAAudioResizeBuffer(struct GBAAudio* audio, size_t samples) {
|
|||
}
|
||||
|
||||
void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA* info) {
|
||||
info->reg = GBADMARegisterSetDestControl(info->reg, GBA_DMA_FIXED);
|
||||
info->reg = GBADMARegisterSetWidth(info->reg, 1);
|
||||
switch (info->dest) {
|
||||
case BASE_IO | REG_FIFO_A_LO:
|
||||
audio->chA.dmaSource = number;
|
||||
|
@ -129,8 +131,6 @@ void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA*
|
|||
audio->externalMixing = false;
|
||||
}
|
||||
}
|
||||
info->reg = GBADMARegisterSetDestControl(info->reg, GBA_DMA_FIXED);
|
||||
info->reg = GBADMARegisterSetWidth(info->reg, 1);
|
||||
}
|
||||
|
||||
void GBAAudioWriteSOUND1CNT_LO(struct GBAAudio* audio, uint16_t value) {
|
||||
|
|
|
@ -424,43 +424,43 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
|||
return;
|
||||
}
|
||||
switch (immediate) {
|
||||
case 0x0:
|
||||
case GBA_SWI_SOFT_RESET:
|
||||
_SoftReset(gba);
|
||||
break;
|
||||
case 0x1:
|
||||
case GBA_SWI_REGISTER_RAM_RESET:
|
||||
_RegisterRamReset(gba);
|
||||
break;
|
||||
case 0x2:
|
||||
GBAHalt(gba);
|
||||
break;
|
||||
case 0x3:
|
||||
case GBA_SWI_HALT:
|
||||
ARMRaiseSWI(cpu);
|
||||
return;
|
||||
case GBA_SWI_STOP:
|
||||
GBAStop(gba);
|
||||
break;
|
||||
case 0x05:
|
||||
case GBA_SWI_VBLANK_INTR_WAIT:
|
||||
// VBlankIntrWait
|
||||
// Fall through:
|
||||
case 0x04:
|
||||
case GBA_SWI_INTR_WAIT:
|
||||
// IntrWait
|
||||
ARMRaiseSWI(cpu);
|
||||
break;
|
||||
case 0x6:
|
||||
return;
|
||||
case GBA_SWI_DIV:
|
||||
_Div(gba, cpu->gprs[0], cpu->gprs[1]);
|
||||
break;
|
||||
case 0x7:
|
||||
case GBA_SWI_DIV_ARM:
|
||||
_Div(gba, cpu->gprs[1], cpu->gprs[0]);
|
||||
break;
|
||||
case 0x8:
|
||||
case GBA_SWI_SQRT:
|
||||
cpu->gprs[0] = _Sqrt(cpu->gprs[0], &cpu->cycles);
|
||||
break;
|
||||
case 0x9:
|
||||
case GBA_SWI_ARCTAN:
|
||||
cpu->gprs[0] = _ArcTan(cpu->gprs[0], &cpu->gprs[1], &cpu->gprs[3], &cpu->cycles);
|
||||
break;
|
||||
case 0xA:
|
||||
case GBA_SWI_ARCTAN2:
|
||||
cpu->gprs[0] = (uint16_t) _ArcTan2(cpu->gprs[0], cpu->gprs[1], &cpu->gprs[1], &cpu->cycles);
|
||||
cpu->gprs[3] = 0x170;
|
||||
break;
|
||||
case 0xB:
|
||||
case 0xC:
|
||||
case GBA_SWI_CPU_SET:
|
||||
case GBA_SWI_CPU_FAST_SET:
|
||||
if (cpu->gprs[0] >> BASE_OFFSET < REGION_WORKING_RAM) {
|
||||
mLOG(GBA_BIOS, GAME_ERROR, "Cannot CpuSet from BIOS");
|
||||
break;
|
||||
|
@ -472,19 +472,19 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
|||
mLOG(GBA_BIOS, GAME_ERROR, "Misaligned CpuSet destination");
|
||||
}
|
||||
ARMRaiseSWI(cpu);
|
||||
break;
|
||||
case 0xD:
|
||||
return;
|
||||
case GBA_SWI_GET_BIOS_CHECKSUM:
|
||||
cpu->gprs[0] = GBA_BIOS_CHECKSUM;
|
||||
cpu->gprs[1] = 1;
|
||||
cpu->gprs[3] = SIZE_BIOS;
|
||||
break;
|
||||
case 0xE:
|
||||
case GBA_SWI_BG_AFFINE_SET:
|
||||
_BgAffineSet(gba);
|
||||
break;
|
||||
case 0xF:
|
||||
case GBA_SWI_OBJ_AFFINE_SET:
|
||||
_ObjAffineSet(gba);
|
||||
break;
|
||||
case 0x10:
|
||||
case GBA_SWI_BIT_UNPACK:
|
||||
if (cpu->gprs[0] < BASE_WORKING_RAM) {
|
||||
mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack source");
|
||||
break;
|
||||
|
@ -500,8 +500,8 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
case GBA_SWI_LZ77_UNCOMP_WRAM:
|
||||
case GBA_SWI_LZ77_UNCOMP_VRAM:
|
||||
if (cpu->gprs[0] < BASE_WORKING_RAM) {
|
||||
mLOG(GBA_BIOS, GAME_ERROR, "Bad LZ77 source");
|
||||
break;
|
||||
|
@ -513,11 +513,11 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
|||
case REGION_WORKING_RAM:
|
||||
case REGION_WORKING_IRAM:
|
||||
case REGION_VRAM:
|
||||
_unLz77(gba, immediate == 0x11 ? 1 : 2);
|
||||
_unLz77(gba, immediate == GBA_SWI_LZ77_UNCOMP_WRAM ? 1 : 2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x13:
|
||||
case GBA_SWI_HUFFMAN_UNCOMP:
|
||||
if (cpu->gprs[0] < BASE_WORKING_RAM) {
|
||||
mLOG(GBA_BIOS, GAME_ERROR, "Bad Huffman source");
|
||||
break;
|
||||
|
@ -533,8 +533,8 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
case GBA_SWI_RL_UNCOMP_WRAM:
|
||||
case GBA_SWI_RL_UNCOMP_VRAM:
|
||||
if (cpu->gprs[0] < BASE_WORKING_RAM) {
|
||||
mLOG(GBA_BIOS, GAME_ERROR, "Bad RL source");
|
||||
break;
|
||||
|
@ -546,13 +546,13 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
|||
case REGION_WORKING_RAM:
|
||||
case REGION_WORKING_IRAM:
|
||||
case REGION_VRAM:
|
||||
_unRl(gba, immediate == 0x14 ? 1 : 2);
|
||||
_unRl(gba, immediate == GBA_SWI_RL_UNCOMP_WRAM ? 1 : 2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x16:
|
||||
case 0x17:
|
||||
case 0x18:
|
||||
case GBA_SWI_DIFF_8BIT_UNFILTER_WRAM:
|
||||
case GBA_SWI_DIFF_8BIT_UNFILTER_VRAM:
|
||||
case GBA_SWI_DIFF_16BIT_UNFILTER:
|
||||
if (cpu->gprs[0] < BASE_WORKING_RAM) {
|
||||
mLOG(GBA_BIOS, GAME_ERROR, "Bad UnFilter source");
|
||||
break;
|
||||
|
@ -564,17 +564,20 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
|||
case REGION_WORKING_RAM:
|
||||
case REGION_WORKING_IRAM:
|
||||
case REGION_VRAM:
|
||||
_unFilter(gba, immediate == 0x18 ? 2 : 1, immediate == 0x16 ? 1 : 2);
|
||||
_unFilter(gba, immediate == GBA_SWI_DIFF_16BIT_UNFILTER ? 2 : 1, immediate == GBA_SWI_DIFF_8BIT_UNFILTER_WRAM ? 1 : 2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x19:
|
||||
case GBA_SWI_SOUND_BIAS:
|
||||
// SoundBias is mostly meaningless here
|
||||
mLOG(GBA_BIOS, STUB, "Stub software interrupt: SoundBias (19)");
|
||||
break;
|
||||
case 0x1F:
|
||||
case GBA_SWI_MIDI_KEY_2_FREQ:
|
||||
_MidiKey2Freq(gba);
|
||||
break;
|
||||
case GBA_SWI_SOUND_DRIVER_GET_JUMP_LIST:
|
||||
ARMRaiseSWI(cpu);
|
||||
return;
|
||||
default:
|
||||
mLOG(GBA_BIOS, STUB, "Stub software interrupt: %02X", immediate);
|
||||
}
|
||||
|
|
|
@ -62,9 +62,9 @@ static const struct mCoreMemoryBlock _GBAMemoryBlocks[] = {
|
|||
{ REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
};
|
||||
|
||||
static const struct mCoreMemoryBlock _GBAMemoryBlocksSRAM[] = {
|
||||
|
@ -76,9 +76,9 @@ static const struct mCoreMemoryBlock _GBAMemoryBlocksSRAM[] = {
|
|||
{ REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART_SRAM, "sram", "SRAM", "Static RAM (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_SRAM, SIZE_CART_SRAM, true },
|
||||
};
|
||||
|
||||
|
@ -91,9 +91,9 @@ static const struct mCoreMemoryBlock _GBAMemoryBlocksFlash512[] = {
|
|||
{ REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART_SRAM, "sram", "Flash", "Flash Memory (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_FLASH512, SIZE_CART_FLASH512, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
};
|
||||
|
||||
|
@ -106,9 +106,9 @@ static const struct mCoreMemoryBlock _GBAMemoryBlocksFlash1M[] = {
|
|||
{ REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART_SRAM, "sram", "Flash", "Flash Memory (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_FLASH512, SIZE_CART_FLASH1M, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 1 },
|
||||
};
|
||||
|
||||
|
@ -121,9 +121,9 @@ static const struct mCoreMemoryBlock _GBAMemoryBlocksEEPROM[] = {
|
|||
{ REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
|
||||
{ REGION_CART_SRAM_MIRROR, "eeprom", "EEPROM", "EEPROM (8kiB)", 0, SIZE_CART_EEPROM, SIZE_CART_EEPROM, mCORE_MEMORY_RW },
|
||||
};
|
||||
|
||||
|
@ -647,7 +647,7 @@ static void _GBACoreReset(struct mCore* core) {
|
|||
#endif
|
||||
|
||||
ARMReset(core->cpu);
|
||||
if (core->opts.skipBios && (gba->romVf || gba->memory.rom)) {
|
||||
if ((core->opts.skipBios && (gba->romVf || gba->memory.rom)) || (gba->romVf && GBAIsMB(gba->romVf))) {
|
||||
GBASkipBIOS(core->board);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,13 +16,17 @@ static void _GBACLIDebuggerInit(struct CLIDebuggerSystem*);
|
|||
static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem*);
|
||||
|
||||
static void _frame(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
static void _load(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _save(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
#endif
|
||||
|
||||
struct CLIDebuggerCommandSummary _GBACLIDebuggerCommands[] = {
|
||||
{ "frame", _frame, "", "Frame advance" },
|
||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
{ "load", _load, "*", "Load a savestate" },
|
||||
{ "save", _save, "*", "Save a savestate" },
|
||||
#endif
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -72,6 +76,7 @@ static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
|||
gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]);
|
||||
}
|
||||
|
||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
struct CLIDebuggerBackend* be = debugger->backend;
|
||||
if (!dv || dv->type != CLIDV_INT_TYPE) {
|
||||
|
@ -107,3 +112,4 @@ static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
|||
|
||||
mCoreSaveState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT | SAVESTATE_RTC | SAVESTATE_METADATA);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -253,7 +253,7 @@ void GBASkipBIOS(struct GBA* gba) {
|
|||
if (gba->memory.rom) {
|
||||
cpu->gprs[ARM_PC] = BASE_CART0;
|
||||
} else {
|
||||
cpu->gprs[ARM_PC] = BASE_WORKING_RAM;
|
||||
cpu->gprs[ARM_PC] = BASE_WORKING_RAM + 0xC0;
|
||||
}
|
||||
gba->video.vcount = 0x7D;
|
||||
gba->memory.io[REG_VCOUNT >> 1] = 0x7D;
|
||||
|
@ -741,11 +741,9 @@ void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) {
|
|||
.type.bp.opcode = opcode
|
||||
};
|
||||
mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ARMRaiseUndefined(cpu);
|
||||
}
|
||||
#endif
|
||||
ARMRaiseUndefined(cpu);
|
||||
}
|
||||
|
||||
void GBABreakpoint(struct ARMCore* cpu, int immediate) {
|
||||
|
|
|
@ -3,51 +3,74 @@
|
|||
#include <mgba/internal/gba/memory.h>
|
||||
|
||||
const uint8_t hleBios[SIZE_BIOS] = {
|
||||
0x06, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x0b, 0x00, 0x00, 0xea,
|
||||
0x06, 0x00, 0x00, 0xea, 0x66, 0x00, 0x00, 0xea, 0x0b, 0x00, 0x00, 0xea,
|
||||
0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe1,
|
||||
0x2c, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x02, 0x03, 0xa0, 0xe3,
|
||||
0x03, 0x10, 0xd0, 0xe5, 0xea, 0x00, 0x51, 0xe3, 0xf8, 0x01, 0x9f, 0x15,
|
||||
0x59, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x02, 0x03, 0xa0, 0xe3,
|
||||
0x03, 0x10, 0xd0, 0xe5, 0xea, 0x00, 0x51, 0xe3, 0x4c, 0x01, 0x9f, 0x15,
|
||||
0x10, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x29, 0xe1,
|
||||
0x00, 0x00, 0x5d, 0xe3, 0x01, 0xd3, 0xa0, 0x03, 0x20, 0xd0, 0x4d, 0x02,
|
||||
0x00, 0x58, 0x2d, 0xe9, 0x02, 0xb0, 0x5e, 0xe5, 0x9c, 0xc0, 0xa0, 0xe3,
|
||||
0x00, 0x58, 0x2d, 0xe9, 0x02, 0xb0, 0x5e, 0xe5, 0xd4, 0xc0, 0xa0, 0xe3,
|
||||
0x0b, 0xb1, 0x9c, 0xe7, 0x00, 0x00, 0x5b, 0xe3, 0x00, 0xc0, 0x4f, 0xe1,
|
||||
0x00, 0x10, 0x2d, 0xe9, 0x80, 0xc0, 0x0c, 0xe2, 0x1f, 0xc0, 0x8c, 0xe3,
|
||||
0x0c, 0xf0, 0x29, 0xe1, 0x00, 0x40, 0x2d, 0xe9, 0x0f, 0xe0, 0xa0, 0xe1,
|
||||
0x1b, 0xff, 0x2f, 0x11, 0x00, 0x40, 0xbd, 0xe8, 0x93, 0xf0, 0x29, 0xe3,
|
||||
0x00, 0x10, 0xbd, 0xe8, 0x0c, 0xf0, 0x69, 0xe1, 0x00, 0x58, 0xbd, 0xe8,
|
||||
0x0e, 0xf0, 0xb0, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0xa0, 0xe3,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00,
|
||||
0xd4, 0x01, 0x00, 0x00, 0x0f, 0x50, 0x2d, 0xe9, 0x01, 0x03, 0xa0, 0xe3,
|
||||
0x0c, 0xf0, 0x29, 0xe1, 0x00, 0x40, 0x2d, 0xe9, 0x00, 0x00, 0xa0, 0xe1,
|
||||
0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1,
|
||||
0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1,
|
||||
0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1,
|
||||
0x0f, 0xe0, 0xa0, 0xe1, 0x1b, 0xff, 0x2f, 0x11, 0x00, 0x00, 0xa0, 0xe1,
|
||||
0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1,
|
||||
0x00, 0x40, 0xbd, 0xe8, 0x93, 0xf0, 0x29, 0xe3, 0x00, 0x10, 0xbd, 0xe8,
|
||||
0x0c, 0xf0, 0x69, 0xe1, 0x00, 0x58, 0xbd, 0xe8, 0x0e, 0xf0, 0xb0, 0xe1,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0xa0, 0xe3, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb4, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xcc, 0x01, 0x00, 0x00, 0xc4, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0x14, 0x02, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0xc0, 0x00, 0x00, 0x02, 0x0f, 0x50, 0x2d, 0xe9, 0x01, 0x03, 0xa0, 0xe3,
|
||||
0x00, 0xe0, 0x8f, 0xe2, 0x04, 0xf0, 0x10, 0xe5, 0x0f, 0x50, 0xbd, 0xe8,
|
||||
0x04, 0xf0, 0x5e, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x5e, 0xe5,
|
||||
0x01, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3, 0x0c, 0x40, 0x2d, 0xe9,
|
||||
0x01, 0xc3, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x00, 0x00, 0xa0, 0xe3,
|
||||
0x01, 0x20, 0xa0, 0xe3, 0x03, 0x00, 0x00, 0x0a, 0xb8, 0x30, 0x5c, 0xe1,
|
||||
0x01, 0x30, 0xc3, 0xe1, 0xb8, 0x30, 0x4c, 0xe1, 0x01, 0x03, 0xcc, 0xe5,
|
||||
0x08, 0x02, 0xcc, 0xe5, 0xb8, 0x30, 0x5c, 0xe1, 0x01, 0x30, 0x13, 0xe0,
|
||||
0x01, 0x30, 0x23, 0x10, 0xb8, 0x30, 0x4c, 0x11, 0x08, 0x22, 0xcc, 0xe5,
|
||||
0xf7, 0xff, 0xff, 0x0a, 0x0c, 0x80, 0xbd, 0xe8, 0x30, 0x40, 0x2d, 0xe9,
|
||||
0x02, 0x46, 0xa0, 0xe1, 0x00, 0xc0, 0xa0, 0xe1, 0x01, 0x50, 0xa0, 0xe1,
|
||||
0x01, 0x04, 0x12, 0xe3, 0x0f, 0x00, 0x00, 0x0a, 0x01, 0x03, 0x12, 0xe3,
|
||||
0x05, 0x00, 0x00, 0x0a, 0x24, 0x45, 0x85, 0xe0, 0x08, 0x00, 0xbc, 0xe8,
|
||||
0x04, 0x00, 0x55, 0xe1, 0x08, 0x00, 0xa5, 0xb8, 0xfc, 0xff, 0xff, 0xba,
|
||||
0x14, 0x00, 0x00, 0xea, 0x01, 0xc0, 0xcc, 0xe3, 0x01, 0x50, 0xc5, 0xe3,
|
||||
0xa4, 0x45, 0x85, 0xe0, 0xb0, 0x30, 0xdc, 0xe1, 0x04, 0x00, 0x55, 0xe1,
|
||||
0xb2, 0x30, 0xc5, 0xb0, 0xfc, 0xff, 0xff, 0xba, 0x0c, 0x00, 0x00, 0xea,
|
||||
0x01, 0x03, 0x12, 0xe3, 0x05, 0x00, 0x00, 0x0a, 0x24, 0x45, 0x85, 0xe0,
|
||||
0x04, 0x00, 0x55, 0xe1, 0x08, 0x00, 0xbc, 0xb8, 0x08, 0x00, 0xa5, 0xb8,
|
||||
0xfb, 0xff, 0xff, 0xba, 0x04, 0x00, 0x00, 0xea, 0xa4, 0x45, 0x85, 0xe0,
|
||||
0x04, 0x00, 0x55, 0xe1, 0xb2, 0x30, 0xdc, 0xb0, 0xb2, 0x30, 0xc5, 0xb0,
|
||||
0xfb, 0xff, 0xff, 0xba, 0x17, 0x3e, 0xa0, 0xe3, 0x30, 0x80, 0xbd, 0xe8,
|
||||
0xf0, 0x47, 0x2d, 0xe9, 0x01, 0x04, 0x12, 0xe3, 0x02, 0x36, 0xa0, 0xe1,
|
||||
0x23, 0x25, 0x81, 0xe0, 0x0b, 0x00, 0x00, 0x0a, 0x00, 0x30, 0x90, 0xe5,
|
||||
0x03, 0x40, 0xa0, 0xe1, 0x03, 0x50, 0xa0, 0xe1, 0x03, 0x60, 0xa0, 0xe1,
|
||||
0x03, 0x70, 0xa0, 0xe1, 0x03, 0x80, 0xa0, 0xe1, 0x03, 0x90, 0xa0, 0xe1,
|
||||
0x03, 0xa0, 0xa0, 0xe1, 0x02, 0x00, 0x51, 0xe1, 0xf8, 0x07, 0xa1, 0xb8,
|
||||
0xfc, 0xff, 0xff, 0xba, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x51, 0xe1,
|
||||
0xf8, 0x07, 0xb0, 0xb8, 0xf8, 0x07, 0xa1, 0xb8, 0xfb, 0xff, 0xff, 0xba,
|
||||
0xf0, 0x87, 0xbd, 0xe8, 0xc0, 0x00, 0x00, 0x02
|
||||
0x04, 0xf0, 0x5e, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe0, 0xa0, 0x03,
|
||||
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x20, 0xa0, 0xe3, 0x01, 0xc3, 0xa0, 0xe3,
|
||||
0x01, 0x23, 0xcc, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x00, 0xa0, 0xe3,
|
||||
0x01, 0x10, 0xa0, 0xe3, 0x0c, 0x40, 0x2d, 0xe9, 0x01, 0xc3, 0xa0, 0xe3,
|
||||
0x00, 0x00, 0x50, 0xe3, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x20, 0xa0, 0xe3,
|
||||
0x03, 0x00, 0x00, 0x0a, 0xb8, 0x30, 0x5c, 0xe1, 0x01, 0x30, 0xc3, 0xe1,
|
||||
0xb8, 0x30, 0x4c, 0xe1, 0x01, 0x03, 0xcc, 0xe5, 0x08, 0x02, 0xcc, 0xe5,
|
||||
0xb8, 0x30, 0x5c, 0xe1, 0x01, 0x30, 0x13, 0xe0, 0x01, 0x30, 0x23, 0x10,
|
||||
0xb8, 0x30, 0x4c, 0x11, 0x08, 0x22, 0xcc, 0xe5, 0xf7, 0xff, 0xff, 0x0a,
|
||||
0x0c, 0x80, 0xbd, 0xe8, 0x30, 0x40, 0x2d, 0xe9, 0x02, 0x46, 0xa0, 0xe1,
|
||||
0x00, 0xc0, 0xa0, 0xe1, 0x01, 0x50, 0xa0, 0xe1, 0x01, 0x04, 0x12, 0xe3,
|
||||
0x0f, 0x00, 0x00, 0x0a, 0x01, 0x03, 0x12, 0xe3, 0x05, 0x00, 0x00, 0x0a,
|
||||
0x24, 0x45, 0x85, 0xe0, 0x08, 0x00, 0xbc, 0xe8, 0x04, 0x00, 0x55, 0xe1,
|
||||
0x08, 0x00, 0xa5, 0xb8, 0xfc, 0xff, 0xff, 0xba, 0x14, 0x00, 0x00, 0xea,
|
||||
0x01, 0xc0, 0xcc, 0xe3, 0x01, 0x50, 0xc5, 0xe3, 0xa4, 0x45, 0x85, 0xe0,
|
||||
0xb0, 0x30, 0xdc, 0xe1, 0x04, 0x00, 0x55, 0xe1, 0xb2, 0x30, 0xc5, 0xb0,
|
||||
0xfc, 0xff, 0xff, 0xba, 0x0c, 0x00, 0x00, 0xea, 0x01, 0x03, 0x12, 0xe3,
|
||||
0x05, 0x00, 0x00, 0x0a, 0x24, 0x45, 0x85, 0xe0, 0x04, 0x00, 0x55, 0xe1,
|
||||
0x08, 0x00, 0xbc, 0xb8, 0x08, 0x00, 0xa5, 0xb8, 0xfb, 0xff, 0xff, 0xba,
|
||||
0x04, 0x00, 0x00, 0xea, 0xa4, 0x45, 0x85, 0xe0, 0x04, 0x00, 0x55, 0xe1,
|
||||
0xb2, 0x30, 0xdc, 0xb0, 0xb2, 0x30, 0xc5, 0xb0, 0xfb, 0xff, 0xff, 0xba,
|
||||
0x17, 0x3e, 0xa0, 0xe3, 0x30, 0x80, 0xbd, 0xe8, 0xf0, 0x47, 0x2d, 0xe9,
|
||||
0x01, 0x04, 0x12, 0xe3, 0x02, 0x36, 0xa0, 0xe1, 0x23, 0x25, 0x81, 0xe0,
|
||||
0x0b, 0x00, 0x00, 0x0a, 0x00, 0x30, 0x90, 0xe5, 0x03, 0x40, 0xa0, 0xe1,
|
||||
0x03, 0x50, 0xa0, 0xe1, 0x03, 0x60, 0xa0, 0xe1, 0x03, 0x70, 0xa0, 0xe1,
|
||||
0x03, 0x80, 0xa0, 0xe1, 0x03, 0x90, 0xa0, 0xe1, 0x03, 0xa0, 0xa0, 0xe1,
|
||||
0x02, 0x00, 0x51, 0xe1, 0xf8, 0x07, 0xa1, 0xb8, 0xfc, 0xff, 0xff, 0xba,
|
||||
0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x51, 0xe1, 0xf8, 0x07, 0xb0, 0xb8,
|
||||
0xf8, 0x07, 0xa1, 0xb8, 0xfb, 0xff, 0xff, 0xba, 0xf0, 0x87, 0xbd, 0xe8,
|
||||
0xf0, 0x07, 0x2d, 0xe9, 0x38, 0x10, 0x9f, 0xe5, 0x01, 0x30, 0xa0, 0xe1,
|
||||
0x01, 0x40, 0xa0, 0xe1, 0x01, 0x50, 0xa0, 0xe1, 0x01, 0x60, 0xa0, 0xe1,
|
||||
0x01, 0x70, 0xa0, 0xe1, 0x01, 0x80, 0xa0, 0xe1, 0x01, 0x90, 0xa0, 0xe1,
|
||||
0x01, 0xa0, 0xa0, 0xe1, 0xfa, 0x07, 0xa0, 0xe8, 0xfa, 0x07, 0xa0, 0xe8,
|
||||
0xfa, 0x07, 0xa0, 0xe8, 0xfa, 0x07, 0xa0, 0xe8, 0x00, 0x10, 0xa0, 0xe3,
|
||||
0xf0, 0x07, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0xb0, 0x01, 0x00, 0x00
|
||||
};
|
||||
|
|
|
@ -40,8 +40,22 @@ and r12, #0x80
|
|||
orr r12, #0x1F
|
||||
msr cpsr, r12
|
||||
stmfd sp!, {lr}
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
mov lr, pc
|
||||
bxne r11
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
ldmfd sp!, {lr}
|
||||
msr cpsr, #0x93
|
||||
ldmfd sp!, {r12}
|
||||
|
@ -52,20 +66,51 @@ movs pc, lr
|
|||
.word 0xE3A02004
|
||||
|
||||
swiTable:
|
||||
.word SoftReset
|
||||
.word RegisterRamReset
|
||||
.word Halt
|
||||
.word Stop
|
||||
.word IntrWait
|
||||
.word VBlankIntrWait
|
||||
.word Div
|
||||
.word DivArm
|
||||
.word Sqrt
|
||||
.word ArcTan
|
||||
.word ArcTan2
|
||||
.word CpuSet
|
||||
.word CpuFastSet
|
||||
@ ... The rest of this table isn't needed if the rest aren't implemented
|
||||
.word SoftReset @ 0x00
|
||||
.word RegisterRamReset @ 0x01
|
||||
.word Halt @ 0x02
|
||||
.word Stop @ 0x03
|
||||
.word IntrWait @ 0x04
|
||||
.word VBlankIntrWait @ 0x05
|
||||
.word Div @ 0x06
|
||||
.word DivArm @ 0x07
|
||||
.word Sqrt @ 0x08
|
||||
.word ArcTan @ 0x09
|
||||
.word ArcTan2 @ 0x0A
|
||||
.word CpuSet @ 0x0B
|
||||
.word CpuFastSet @ 0x0C
|
||||
.word GetBiosChecksum @ 0x0D
|
||||
.word BgAffineSet @ 0x0E
|
||||
.word ObjAffineSet @ 0x0F
|
||||
.word BitUnPack @ 0x10
|
||||
.word Lz77UnCompWram @ 0x11
|
||||
.word Lz77UnCompVram @ 0x12
|
||||
.word HuffmanUnComp @ 0x13
|
||||
.word RlUnCompWram @ 0x14
|
||||
.word RlUnCompVram @ 0x15
|
||||
.word Diff8BitUnFilterWram @ 0x16
|
||||
.word Diff8BitUnFilterVram @ 0x17
|
||||
.word Diff16BitUnFilter @ 0x18
|
||||
.word SoundBias @ 0x19
|
||||
.word SoundDriverInit @ 0x1A
|
||||
.word SoundDriverMode @ 0x1B
|
||||
.word SoundDriverMain @ 0x1C
|
||||
.word SoundDriverVsync @ 0x1D
|
||||
.word SoundChannelClear @ 0x1E
|
||||
.word MidiKey2Freq @ 0x1F
|
||||
.word MusicPlayerOpen @ 0x20
|
||||
.word MusicPlayerStart @ 0x21
|
||||
.word MusicPlayerStop @ 0x22
|
||||
.word MusicPlayerContinue @ 0x23
|
||||
.word MusicPlayerFadeOut @ 0x24
|
||||
.word MultiBoot @ 0x25
|
||||
.word HardReset @ 0x26
|
||||
.word CustomHalt @ 0x27
|
||||
.word SoundDriverVsyncOff @ 0x28
|
||||
.word SoundDriverVsyncOn @ 0x29
|
||||
.word SoundDriverGetJumpList @ 0x2A
|
||||
|
||||
.ltorg
|
||||
|
||||
irqBase:
|
||||
stmfd sp!, {r0-r3, r12, lr}
|
||||
|
@ -77,6 +122,59 @@ subs pc, lr, #4
|
|||
.word 0
|
||||
.word 0xE55EC002
|
||||
|
||||
undefBase:
|
||||
subs pc, lr, #4
|
||||
.word 0
|
||||
.word 0x03A0E004
|
||||
|
||||
@ Unimplemented
|
||||
SoftReset:
|
||||
RegisterRamReset:
|
||||
Stop:
|
||||
Div:
|
||||
DivArm:
|
||||
Sqrt:
|
||||
ArcTan:
|
||||
ArcTan2:
|
||||
GetBiosChecksum:
|
||||
BgAffineSet:
|
||||
ObjAffineSet:
|
||||
BitUnPack:
|
||||
Lz77UnCompWram:
|
||||
Lz77UnCompVram:
|
||||
HuffmanUnComp:
|
||||
RlUnCompWram:
|
||||
RlUnCompVram:
|
||||
Diff8BitUnFilterWram:
|
||||
Diff8BitUnFilterVram:
|
||||
Diff16BitUnFilter:
|
||||
SoundBias:
|
||||
SoundDriverInit:
|
||||
SoundDriverMode:
|
||||
SoundDriverMain:
|
||||
SoundDriverVsync:
|
||||
SoundChannelClear:
|
||||
MidiKey2Freq:
|
||||
MusicPlayerOpen:
|
||||
MusicPlayerStart:
|
||||
MusicPlayerStop:
|
||||
MusicPlayerContinue:
|
||||
MusicPlayerFadeOut:
|
||||
MultiBoot:
|
||||
HardReset:
|
||||
CustomHalt:
|
||||
SoundDriverVsyncOff:
|
||||
SoundDriverVsyncOn:
|
||||
|
||||
NopCall:
|
||||
bx lr
|
||||
|
||||
Halt:
|
||||
mov r2, #0
|
||||
mov r12, #0x04000000
|
||||
strb r2, [r12, #0x301]
|
||||
bx lr
|
||||
|
||||
VBlankIntrWait:
|
||||
mov r0, #1
|
||||
mov r1, #1
|
||||
|
@ -187,4 +285,23 @@ blt 0b
|
|||
2:
|
||||
ldmfd sp!, {r4-r10, pc}
|
||||
|
||||
SoundDriverGetJumpList:
|
||||
stmfd sp!, {r4-r10}
|
||||
ldr r1, =NopCall
|
||||
mov r3, r1
|
||||
mov r4, r1
|
||||
mov r5, r1
|
||||
mov r6, r1
|
||||
mov r7, r1
|
||||
mov r8, r1
|
||||
mov r9, r1
|
||||
mov r10, r1
|
||||
stmia r0!, {r1, r3-r10}
|
||||
stmia r0!, {r1, r3-r10}
|
||||
stmia r0!, {r1, r3-r10}
|
||||
stmia r0!, {r1, r3-r10}
|
||||
mov r1, #0
|
||||
ldmfd sp!, {r4-r10}
|
||||
bx lr
|
||||
|
||||
.ltorg
|
||||
|
|
|
@ -369,6 +369,7 @@ void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState
|
|||
} else {
|
||||
video->event.callback = _startHblank;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
video->event.callback = _startHdraw;
|
||||
break;
|
||||
|
|
|
@ -25,10 +25,11 @@ GIFView::GIFView(QWidget* parent)
|
|||
|
||||
connect(m_ui.selectFile, &QAbstractButton::clicked, this, &GIFView::selectFile);
|
||||
connect(m_ui.filename, &QLineEdit::textChanged, this, &GIFView::setFilename);
|
||||
connect(m_ui.fmtGif, &QAbstractButton::clicked, this, &GIFView::changeExtension);
|
||||
connect(m_ui.fmtApng, &QAbstractButton::clicked, this, &GIFView::changeExtension);
|
||||
|
||||
FFmpegEncoderInit(&m_encoder);
|
||||
FFmpegEncoderSetAudio(&m_encoder, nullptr, 0);
|
||||
FFmpegEncoderSetContainer(&m_encoder, "gif");
|
||||
}
|
||||
|
||||
GIFView::~GIFView() {
|
||||
|
@ -44,14 +45,24 @@ void GIFView::setController(std::shared_ptr<CoreController> controller) {
|
|||
}
|
||||
|
||||
void GIFView::startRecording() {
|
||||
FFmpegEncoderSetVideo(&m_encoder, "gif", 0, m_ui.frameskip->value());
|
||||
if (m_ui.fmtApng->isChecked()) {
|
||||
FFmpegEncoderSetContainer(&m_encoder, "apng");
|
||||
FFmpegEncoderSetVideo(&m_encoder, "apng", 0, m_ui.frameskip->value());
|
||||
} else {
|
||||
FFmpegEncoderSetContainer(&m_encoder, "gif");
|
||||
FFmpegEncoderSetVideo(&m_encoder, "gif", 0, m_ui.frameskip->value());
|
||||
}
|
||||
FFmpegEncoderSetLooping(&m_encoder, m_ui.loop->isChecked());
|
||||
if (!FFmpegEncoderOpen(&m_encoder, m_filename.toUtf8().constData())) {
|
||||
LOG(QT, ERROR) << tr("Failed to open output GIF file: %1").arg(m_filename);
|
||||
LOG(QT, ERROR) << tr("Failed to open output GIF or APNG file: %1").arg(m_filename);
|
||||
return;
|
||||
}
|
||||
m_ui.start->setEnabled(false);
|
||||
m_ui.stop->setEnabled(true);
|
||||
m_ui.frameskip->setEnabled(false);
|
||||
m_ui.loop->setEnabled(false);
|
||||
m_ui.fmtApng->setEnabled(false);
|
||||
m_ui.fmtGif->setEnabled(false);
|
||||
emit recordingStarted(&m_encoder.d);
|
||||
}
|
||||
|
||||
|
@ -59,22 +70,45 @@ void GIFView::stopRecording() {
|
|||
emit recordingStopped();
|
||||
FFmpegEncoderClose(&m_encoder);
|
||||
m_ui.stop->setEnabled(false);
|
||||
m_ui.start->setEnabled(true);
|
||||
m_ui.start->setEnabled(!m_filename.isEmpty());
|
||||
m_ui.frameskip->setEnabled(true);
|
||||
m_ui.loop->setEnabled(true);
|
||||
m_ui.fmtApng->setEnabled(true);
|
||||
m_ui.fmtGif->setEnabled(true);
|
||||
}
|
||||
|
||||
void GIFView::selectFile() {
|
||||
QString filename = GBAApp::app()->getSaveFileName(this, tr("Select output file"), tr("Graphics Interchange Format (*.gif)"));
|
||||
if (!filename.isEmpty()) {
|
||||
m_ui.filename->setText(filename);
|
||||
if (!FFmpegEncoderIsOpen(&m_encoder)) {
|
||||
m_ui.start->setEnabled(true);
|
||||
QString filename = GBAApp::app()->getSaveFileName(this, tr("Select output file"), tr("Graphics Interchange Format (*.gif);;Animated Portable Network Graphics (*.png *.apng)"));
|
||||
m_ui.filename->setText(filename);
|
||||
}
|
||||
|
||||
void GIFView::setFilename(const QString& filename) {
|
||||
m_filename = filename;
|
||||
if (!FFmpegEncoderIsOpen(&m_encoder)) {
|
||||
m_ui.start->setEnabled(!filename.isEmpty());
|
||||
if (filename.endsWith(".gif")) {
|
||||
m_ui.fmtGif->setChecked(Qt::Checked);
|
||||
} else if (filename.endsWith(".png") || filename.endsWith(".apng")) {
|
||||
m_ui.fmtApng->setChecked(Qt::Checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GIFView::setFilename(const QString& fname) {
|
||||
m_filename = fname;
|
||||
void GIFView::changeExtension() {
|
||||
if (m_filename.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QString filename = m_filename;
|
||||
int index = m_filename.lastIndexOf(".");
|
||||
if (index >= 0) {
|
||||
filename.truncate(index);
|
||||
}
|
||||
if (m_ui.fmtGif->isChecked()) {
|
||||
filename += ".gif";
|
||||
} else if (m_ui.fmtApng->isChecked()) {
|
||||
filename += ".png";
|
||||
}
|
||||
m_ui.filename->setText(filename);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -41,6 +41,7 @@ signals:
|
|||
private slots:
|
||||
void selectFile();
|
||||
void setFilename(const QString&);
|
||||
void changeExtension();
|
||||
|
||||
private:
|
||||
Ui::GIFView m_ui;
|
||||
|
|
|
@ -7,50 +7,42 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>392</width>
|
||||
<height>220</height>
|
||||
<height>262</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Record GIF</string>
|
||||
<string>Record GIF/APNG</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<item row="2" column="0">
|
||||
<widget class="QRadioButton" name="fmtApng">
|
||||
<property name="text">
|
||||
<string>Frameskip</string>
|
||||
<string>APNG</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">format</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<item row="2" column="2">
|
||||
<widget class="QSpinBox" name="frameskip">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
|
@ -123,8 +115,55 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Frameskip</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="3">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="fmtGif">
|
||||
<property name="text">
|
||||
<string>GIF</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">format</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="loop">
|
||||
<property name="text">
|
||||
<string>Loop</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>filename</tabstop>
|
||||
<tabstop>start</tabstop>
|
||||
<tabstop>stop</tabstop>
|
||||
<tabstop>selectFile</tabstop>
|
||||
<tabstop>fmtGif</tabstop>
|
||||
<tabstop>fmtApng</tabstop>
|
||||
<tabstop>loop</tabstop>
|
||||
<tabstop>frameskip</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
|
@ -144,4 +183,7 @@
|
|||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="format"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "GamepadButtonEvent.h"
|
||||
#include "InputIndex.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFontMetrics>
|
||||
#include <QKeyEvent>
|
||||
|
||||
|
@ -32,7 +33,35 @@ void KeyEditor::setValue(int key) {
|
|||
if (key < 0) {
|
||||
setText(tr("---"));
|
||||
} else {
|
||||
setText(QKeySequence(key).toString(QKeySequence::NativeText));
|
||||
QKeySequence seq(key);
|
||||
switch (key) {
|
||||
#ifndef Q_OS_MAC
|
||||
case Qt::Key_Shift:
|
||||
setText(QCoreApplication::translate("QShortcut", "Shift"));
|
||||
break;
|
||||
case Qt::Key_Control:
|
||||
setText(QCoreApplication::translate("QShortcut", "Control"));
|
||||
break;
|
||||
case Qt::Key_Alt:
|
||||
setText(QCoreApplication::translate("QShortcut", "Alt"));
|
||||
break;
|
||||
case Qt::Key_Meta:
|
||||
setText(QCoreApplication::translate("QShortcut", "Meta"));
|
||||
break;
|
||||
#endif
|
||||
case Qt::Key_Super_L:
|
||||
setText(tr("Super (L)"));
|
||||
break;
|
||||
case Qt::Key_Super_R:
|
||||
setText(tr("Super (R)"));
|
||||
break;
|
||||
case Qt::Key_Menu:
|
||||
setText(tr("Menu"));
|
||||
break;
|
||||
default:
|
||||
setText(QKeySequence(key).toString(QKeySequence::NativeText));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
emit valueChanged(key);
|
||||
|
|
|
@ -16,11 +16,13 @@
|
|||
|
||||
using namespace QGBA;
|
||||
|
||||
#ifdef M_CORE_GB
|
||||
MultiplayerController::Player::Player(CoreController* coreController, GBSIOLockstepNode* node)
|
||||
: controller(coreController)
|
||||
, gbNode(node)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef M_CORE_GBA
|
||||
MultiplayerController::Player::Player(CoreController* coreController, GBASIOLockstepNode* node)
|
||||
|
|
|
@ -44,6 +44,10 @@ ObjView::ObjView(std::shared_ptr<CoreController> controller, QWidget* parent)
|
|||
m_ui.priority->setFont(font);
|
||||
m_ui.palette->setFont(font);
|
||||
m_ui.transform->setFont(font);
|
||||
m_ui.xformPA->setFont(font);
|
||||
m_ui.xformPB->setFont(font);
|
||||
m_ui.xformPC->setFont(font);
|
||||
m_ui.xformPD->setFont(font);
|
||||
m_ui.mode->setFont(font);
|
||||
|
||||
connect(m_ui.tiles, &TilePainter::indexPressed, this, &ObjView::translateIndex);
|
||||
|
@ -157,9 +161,23 @@ void ObjView::updateTilesGBA(bool force) {
|
|||
m_ui.mosaic->setChecked(GBAObjAttributesAIsMosaic(obj->a));
|
||||
|
||||
if (GBAObjAttributesAIsTransformed(obj->a)) {
|
||||
m_ui.transform->setText(QString::number(GBAObjAttributesBGetMatIndex(obj->b)));
|
||||
int mtxId = GBAObjAttributesBGetMatIndex(obj->b);
|
||||
struct GBAOAMMatrix mat;
|
||||
LOAD_16LE(mat.a, 0, &gba->video.oam.mat[mtxId].a);
|
||||
LOAD_16LE(mat.b, 0, &gba->video.oam.mat[mtxId].b);
|
||||
LOAD_16LE(mat.c, 0, &gba->video.oam.mat[mtxId].c);
|
||||
LOAD_16LE(mat.d, 0, &gba->video.oam.mat[mtxId].d);
|
||||
m_ui.transform->setText(QString::number(mtxId));
|
||||
m_ui.xformPA->setText(QString("%0").arg(mat.a / 256., 5, 'f', 2));
|
||||
m_ui.xformPB->setText(QString("%0").arg(mat.b / 256., 5, 'f', 2));
|
||||
m_ui.xformPC->setText(QString("%0").arg(mat.c / 256., 5, 'f', 2));
|
||||
m_ui.xformPD->setText(QString("%0").arg(mat.d / 256., 5, 'f', 2));
|
||||
} else {
|
||||
m_ui.transform->setText(tr("Off"));
|
||||
m_ui.xformPA->setText(tr("---"));
|
||||
m_ui.xformPB->setText(tr("---"));
|
||||
m_ui.xformPC->setText(tr("---"));
|
||||
m_ui.xformPD->setText(tr("---"));
|
||||
}
|
||||
|
||||
switch (GBAObjAttributesAGetMode(obj->a)) {
|
||||
|
@ -230,6 +248,10 @@ void ObjView::updateTilesGB(bool force) {
|
|||
m_ui.doubleSize->setChecked(false);
|
||||
m_ui.mosaic->setChecked(false);
|
||||
m_ui.transform->setText(tr("N/A"));
|
||||
m_ui.xformPA->setText(tr("---"));
|
||||
m_ui.xformPB->setText(tr("---"));
|
||||
m_ui.xformPC->setText(tr("---"));
|
||||
m_ui.xformPD->setText(tr("---"));
|
||||
m_ui.mode->setText(tr("N/A"));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -13,7 +13,81 @@
|
|||
<property name="windowTitle">
|
||||
<string>Sprites</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0,1" columnstretch="0,0,1,1">
|
||||
<layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0,0" columnstretch="0,0,0,1">
|
||||
<item row="0" column="2" rowspan="4" colspan="2">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0" alignment="Qt::AlignHCenter|Qt::AlignVCenter">
|
||||
<widget class="QGBA::TilePainter" name="tiles" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>8</width>
|
||||
<height>8</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="objId">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="address">
|
||||
<property name="text">
|
||||
<string>0x07000000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QPushButton" name="copyButton">
|
||||
<property name="text">
|
||||
|
@ -21,13 +95,49 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="magnification">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>×</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Magnification</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Geometry</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
|
@ -93,7 +203,14 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<item row="0" column="1" rowspan="2">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
|
@ -159,50 +276,86 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" rowspan="4" colspan="2">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0" alignment="Qt::AlignHCenter|Qt::AlignVCenter">
|
||||
<widget class="QGBA::TilePainter" name="tiles" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>8</width>
|
||||
<height>8</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
<item row="0" column="2" rowspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="xformPC">
|
||||
<property name="text">
|
||||
<string>+0.00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="xformPA">
|
||||
<property name="text">
|
||||
<string>+1.00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Matrix</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="xformPD">
|
||||
<property name="text">
|
||||
<string>+1.00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer_8">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="xformPB">
|
||||
<property name="text">
|
||||
<string>+0.00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="5">
|
||||
<widget class="QGBA::AssetTile" name="tile">
|
||||
<property name="title">
|
||||
<string>Tile</string>
|
||||
<item row="5" column="0" colspan="4">
|
||||
<widget class="QListWidget" name="objList">
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flow">
|
||||
<enum>QListView::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="resizeMode">
|
||||
<enum>QListView::Adjust</enum>
|
||||
</property>
|
||||
<property name="gridSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>96</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
<property name="uniformItemSizes">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -215,6 +368,12 @@
|
|||
</item>
|
||||
<item row="3" column="0" rowspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Attributes</string>
|
||||
</property>
|
||||
|
@ -517,98 +676,10 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="objId">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="address">
|
||||
<property name="text">
|
||||
<string>0x07000000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="magnification">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>×</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Magnification</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="4">
|
||||
<widget class="QListWidget" name="objList">
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flow">
|
||||
<enum>QListView::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="resizeMode">
|
||||
<enum>QListView::Adjust</enum>
|
||||
</property>
|
||||
<property name="gridSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>96</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
<property name="uniformItemSizes">
|
||||
<bool>true</bool>
|
||||
<item row="0" column="1" rowspan="5">
|
||||
<widget class="QGBA::AssetTile" name="tile">
|
||||
<property name="title">
|
||||
<string>Tile</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -120,7 +120,7 @@ void PaletteView::selectIndex(int index) {
|
|||
hexcode |= (hexcode >> 5) & 0x070707;
|
||||
m_ui.hexcode->setText(tr("#%0").arg(hexcode, 6, 16, QChar('0')));
|
||||
m_ui.value->setText(tr("0x%0").arg(color, 4, 16, QChar('0')));
|
||||
m_ui.index->setText(tr("%0").arg(index, 3, 10, QChar('0')));
|
||||
m_ui.index->setText(tr("0x%0 (%1)").arg(index, 3, 16, QChar('0')).arg(index, 3, 10, QChar('0')));
|
||||
m_ui.r->setText(tr("0x%0 (%1)").arg(r, 2, 16, QChar('0')).arg(r, 2, 10, QChar('0')));
|
||||
m_ui.g->setText(tr("0x%0 (%1)").arg(g, 2, 16, QChar('0')).arg(g, 2, 10, QChar('0')));
|
||||
m_ui.b->setText(tr("0x%0 (%1)").arg(b, 2, 16, QChar('0')).arg(b, 2, 10, QChar('0')));
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>443</width>
|
||||
<width>500</width>
|
||||
<height>397</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -289,7 +289,7 @@
|
|||
<item>
|
||||
<widget class="QLabel" name="index">
|
||||
<property name="text">
|
||||
<string>000</string>
|
||||
<string>0x000 (000)</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
|
|
|
@ -112,6 +112,15 @@ VideoView::VideoView(QWidget* parent)
|
|||
void VideoView::updatePresets() {
|
||||
m_presets.clear();
|
||||
|
||||
addPreset(m_ui.preset4K, {
|
||||
.container = QString(),
|
||||
.vcodec = QString(),
|
||||
.acodec = QString(),
|
||||
.vbr = 0,
|
||||
.abr = 0,
|
||||
.dims = maintainAspect(QSize(3840, 2160))
|
||||
});
|
||||
|
||||
addPreset(m_ui.preset1080, {
|
||||
.container = QString(),
|
||||
.vcodec = QString(),
|
||||
|
@ -177,6 +186,14 @@ void VideoView::updatePresets() {
|
|||
.abr = 128
|
||||
});
|
||||
|
||||
addPreset(m_ui.presetMP4, {
|
||||
.container = "MP4",
|
||||
.vcodec = "h.264",
|
||||
.acodec = "AAC",
|
||||
.vbr = 800,
|
||||
.abr = 128
|
||||
});
|
||||
|
||||
if (m_nativeWidth && m_nativeHeight) {
|
||||
addPreset(m_ui.presetLossless, {
|
||||
.container = "MKV",
|
||||
|
|
|
@ -133,6 +133,13 @@
|
|||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="presetMP4">
|
||||
<property name="text">
|
||||
<string>MP4</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="presetLossless">
|
||||
<property name="text">
|
||||
|
@ -150,6 +157,13 @@
|
|||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="preset4K">
|
||||
<property name="text">
|
||||
<string>4K</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="preset1080">
|
||||
<property name="text">
|
||||
|
@ -289,6 +303,11 @@
|
|||
<string>FFV1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -326,6 +345,11 @@
|
|||
<string>Uncompressed</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -871,7 +871,6 @@ void Window::gameStopped() {
|
|||
action->setEnabled(false);
|
||||
}
|
||||
setWindowFilePath(QString());
|
||||
updateTitle();
|
||||
detachWidget(m_display.get());
|
||||
m_screenWidget->setCenteredAspectRatio(m_logo.width(), m_logo.height());
|
||||
m_screenWidget->setDimensions(m_logo.width(), m_logo.height());
|
||||
|
@ -900,6 +899,7 @@ void Window::gameStopped() {
|
|||
m_display->stopDrawing();
|
||||
|
||||
m_controller.reset();
|
||||
updateTitle();
|
||||
|
||||
m_display->setVideoProxy({});
|
||||
if (m_pendingClose) {
|
||||
|
@ -1015,6 +1015,8 @@ void Window::reloadAudioDriver() {
|
|||
m_audioProcessor->start();
|
||||
connect(m_controller.get(), &CoreController::stopping, m_audioProcessor.get(), &AudioProcessor::stop);
|
||||
connect(m_controller.get(), &CoreController::fastForwardChanged, m_audioProcessor.get(), &AudioProcessor::inputParametersChanged);
|
||||
connect(m_controller.get(), &CoreController::paused, m_audioProcessor.get(), &AudioProcessor::pause);
|
||||
connect(m_controller.get(), &CoreController::unpaused, m_audioProcessor.get(), &AudioProcessor::start);
|
||||
}
|
||||
|
||||
void Window::changeRenderer() {
|
||||
|
@ -1547,7 +1549,7 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
|
||||
#ifdef USE_FFMPEG
|
||||
addGameAction(tr("Record A/V..."), "recordOutput", this, &Window::openVideoWindow, "av");
|
||||
addGameAction(tr("Record GIF..."), "recordGIF", this, &Window::openGIFWindow, "av");
|
||||
addGameAction(tr("Record GIF/APNG..."), "recordGIF", this, &Window::openGIFWindow, "av");
|
||||
#endif
|
||||
|
||||
m_actions.addSeparator("av");
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -46,7 +46,7 @@ if(USE_PIXMAN)
|
|||
endif()
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND SDL_LIBRARY imm32 version winmm)
|
||||
list(APPEND SDL_LIBRARY imm32 setupapi version winmm)
|
||||
elseif(APPLE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AppKit -framework AudioUnit -framework Carbon -framework CoreAudio -framework AudioToolbox -framework ForceFeedback -framework IOKit")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}" PARENT_SCOPE)
|
||||
|
|
|
@ -19,6 +19,11 @@ mLOG_DEFINE_CATEGORY(SDL_AUDIO, "SDL Audio", "platform.sdl.audio");
|
|||
static void _mSDLAudioCallback(void* context, Uint8* data, int len);
|
||||
|
||||
bool mSDLInitAudio(struct mSDLAudio* context, struct mCoreThread* threadContext) {
|
||||
#if defined(_WIN32) && SDL_VERSION_ATLEAST(2, 0, 8)
|
||||
if (!getenv("SDL_AUDIODRIVER")) {
|
||||
_putenv_s("SDL_AUDIODRIVER", "directsound");
|
||||
}
|
||||
#endif
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
||||
mLOG(SDL_AUDIO, ERROR, "Could not initialize SDL sound system: %s", SDL_GetError());
|
||||
return false;
|
||||
|
|
|
@ -348,6 +348,13 @@ void mSDLUpdateJoysticks(struct mSDLEvents* events, const struct Configuration*
|
|||
if (!sdlJoystick) {
|
||||
continue;
|
||||
}
|
||||
ssize_t joysticks[MAX_PLAYERS];
|
||||
size_t i;
|
||||
// Pointers can get invalidated, so we'll need to refresh them
|
||||
for (i = 0; i < events->playersAttached && i < MAX_PLAYERS; ++i) {
|
||||
joysticks[i] = events->players[i]->joystick ? SDL_JoystickListIndex(&events->joysticks, events->players[i]->joystick) : SIZE_MAX;
|
||||
events->players[i]->joystick = NULL;
|
||||
}
|
||||
struct SDL_JoystickCombo* joystick = SDL_JoystickListAppend(&events->joysticks);
|
||||
joystick->joystick = sdlJoystick;
|
||||
joystick->id = SDL_JoystickInstanceID(joystick->joystick);
|
||||
|
@ -355,8 +362,12 @@ void mSDLUpdateJoysticks(struct mSDLEvents* events, const struct Configuration*
|
|||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
joystick->haptic = SDL_HapticOpenFromJoystick(joystick->joystick);
|
||||
#endif
|
||||
for (i = 0; i < events->playersAttached && i < MAX_PLAYERS; ++i) {
|
||||
if (joysticks[i] != SIZE_MAX) {
|
||||
events->players[i]->joystick = SDL_JoystickListGetPointer(&events->joysticks, joysticks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
size_t i;
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
char joystickName[34] = {0};
|
||||
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick->joystick), joystickName, sizeof(joystickName));
|
||||
|
|
|
@ -22,6 +22,14 @@
|
|||
#ifdef __SWITCH__
|
||||
#include <switch.h>
|
||||
#endif
|
||||
#ifdef GEKKO
|
||||
#include <fat.h>
|
||||
#include <gccore.h>
|
||||
#ifdef FIXED_ROM_BUFFER
|
||||
uint32_t* romBuffer;
|
||||
size_t romBufferSize;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -83,6 +91,29 @@ int main(int argc, char** argv) {
|
|||
#elif defined(__SWITCH__)
|
||||
UNUSED(_mPerfShutdown);
|
||||
consoleInit(NULL);
|
||||
#elif defined(GEKKO)
|
||||
VIDEO_Init();
|
||||
VIDEO_SetBlack(true);
|
||||
VIDEO_Flush();
|
||||
VIDEO_WaitVSync();
|
||||
|
||||
GXRModeObj* vmode = VIDEO_GetPreferredMode(0);
|
||||
void* xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode));
|
||||
console_init(xfb, 20, 20, vmode->fbWidth, vmode->xfbHeight, vmode->fbWidth * VI_DISPLAY_PIX_SZ);
|
||||
|
||||
VIDEO_Configure(vmode);
|
||||
VIDEO_SetNextFramebuffer(xfb);
|
||||
VIDEO_SetBlack(false);
|
||||
VIDEO_Flush();
|
||||
VIDEO_WaitVSync();
|
||||
VIDEO_WaitVSync();
|
||||
fatInitDefault();
|
||||
|
||||
#ifdef FIXED_ROM_BUFFER
|
||||
romBufferSize = 0x02000000;
|
||||
romBuffer = SYS_GetArena2Lo();
|
||||
SYS_SetArena2Lo((void*)((intptr_t) romBuffer + romBufferSize));
|
||||
#endif
|
||||
#else
|
||||
signal(SIGINT, _mPerfShutdown);
|
||||
#endif
|
||||
|
@ -125,6 +156,8 @@ int main(int argc, char** argv) {
|
|||
puts("game_code,frames,duration,renderer");
|
||||
#ifdef __SWITCH__
|
||||
consoleUpdate(NULL);
|
||||
#elif defined(GEKKO)
|
||||
VIDEO_WaitVSync();
|
||||
#endif
|
||||
}
|
||||
if (perfOpts.server) {
|
||||
|
@ -145,6 +178,11 @@ int main(int argc, char** argv) {
|
|||
acExit();
|
||||
#elif defined(__SWITCH__)
|
||||
consoleExit(NULL);
|
||||
#elif defined(GEKKO)
|
||||
VIDEO_SetBlack(true);
|
||||
VIDEO_Flush();
|
||||
VIDEO_WaitVSync();
|
||||
VIDEO_WaitVSync();
|
||||
#endif
|
||||
|
||||
return didFail;
|
||||
|
|
|
@ -11,6 +11,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
|||
file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/wii/wii-*.c)
|
||||
list(APPEND OS_LIB wiiuse bte fat ogc)
|
||||
set(OS_SRC ${OS_SRC} PARENT_SCOPE)
|
||||
set(OS_LIB ${OS_LIB} PARENT_SCOPE)
|
||||
source_group("Wii-specific code" FILES ${OS_SRC})
|
||||
set(CORE_VFS_SRC ${CORE_VFS_SRC} PARENT_SCOPE)
|
||||
set(OS_DEFINES ${OS_DEFINES} PARENT_SCOPE)
|
||||
|
@ -39,6 +40,16 @@ add_custom_target(${BINARY_NAME}.dol ALL
|
|||
add_custom_target(run ${WIILOAD} ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.dol
|
||||
DEPENDS ${BINARY_NAME}.dol)
|
||||
|
||||
if(BUILD_PERF)
|
||||
add_custom_target(${BINARY_NAME}-perf.dol ALL
|
||||
${ELF2DOL} ../${BINARY_NAME}-perf ${BINARY_NAME}-perf.dol
|
||||
DEPENDS ${BINARY_NAME}-perf)
|
||||
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}-perf.dol
|
||||
DESTINATION . COMPONENT ${BINARY_NAME}-perf)
|
||||
endif()
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/meta.xml.in ${CMAKE_CURRENT_BINARY_DIR}/meta.xml)
|
||||
|
||||
install(TARGETS ${BINARY_NAME}.elf DESTINATION . COMPONENT ${BINARY_NAME}-dbg)
|
||||
|
|
|
@ -262,7 +262,7 @@ int main(int argc, char* argv[]) {
|
|||
#ifdef FIXED_ROM_BUFFER
|
||||
romBufferSize = SIZE_CART0;
|
||||
romBuffer = SYS_GetArena2Lo();
|
||||
SYS_SetArena2Lo((void*)((intptr_t) romBuffer + SIZE_CART0));
|
||||
SYS_SetArena2Lo((void*)((intptr_t) romBuffer + romBufferSize));
|
||||
#endif
|
||||
|
||||
#if !defined(COLOR_16_BIT) && !defined(COLOR_5_6_5)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
/* 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
|
||||
|
@ -14,11 +14,23 @@
|
|||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <mgba-util/vector.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
struct HandleMappingTuple {
|
||||
HANDLE handle;
|
||||
void* mapping;
|
||||
};
|
||||
|
||||
DECLARE_VECTOR(HandleMappingList, struct HandleMappingTuple);
|
||||
DEFINE_VECTOR(HandleMappingList, struct HandleMappingTuple);
|
||||
#endif
|
||||
|
||||
struct VFileFD {
|
||||
struct VFile d;
|
||||
int fd;
|
||||
#ifdef _WIN32
|
||||
HANDLE hMap;
|
||||
struct HandleMappingList handles;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -74,12 +86,23 @@ struct VFile* VFileFromFD(int fd) {
|
|||
vfd->d.truncate = _vfdTruncate;
|
||||
vfd->d.size = _vfdSize;
|
||||
vfd->d.sync = _vfdSync;
|
||||
#ifdef _WIN32
|
||||
HandleMappingListInit(&vfd->handles, 4);
|
||||
#endif
|
||||
|
||||
return &vfd->d;
|
||||
}
|
||||
|
||||
bool _vfdClose(struct VFile* vf) {
|
||||
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||
#ifdef _WIN32
|
||||
size_t i;
|
||||
for (i = 0; i < HandleMappingListSize(&vfd->handles); ++i) {
|
||||
UnmapViewOfFile(HandleMappingListGetPointer(&vfd->handles, i)->mapping);
|
||||
CloseHandle(HandleMappingListGetPointer(&vfd->handles, i)->handle);
|
||||
}
|
||||
HandleMappingListDeinit(&vfd->handles);
|
||||
#endif
|
||||
if (close(vfd->fd) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
@ -134,16 +157,25 @@ static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
|
|||
if (size > fileSize) {
|
||||
size = fileSize;
|
||||
}
|
||||
vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
|
||||
return MapViewOfFile(vfd->hMap, mapFiles, 0, 0, size);
|
||||
struct HandleMappingTuple tuple = {0};
|
||||
tuple.handle = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
|
||||
tuple.mapping = MapViewOfFile(tuple.handle, mapFiles, 0, 0, size);
|
||||
*HandleMappingListAppend(&vfd->handles) = tuple;
|
||||
return tuple.mapping;
|
||||
}
|
||||
|
||||
static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
|
||||
UNUSED(size);
|
||||
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||
UnmapViewOfFile(memory);
|
||||
CloseHandle(vfd->hMap);
|
||||
vfd->hMap = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < HandleMappingListSize(&vfd->handles); ++i) {
|
||||
if (HandleMappingListGetPointer(&vfd->handles, i)->mapping == memory) {
|
||||
UnmapViewOfFile(memory);
|
||||
CloseHandle(HandleMappingListGetPointer(&vfd->handles, i)->handle);
|
||||
HandleMappingListShift(&vfd->handles, i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue