Merge branch 'master' into medusa

This commit is contained in:
Vicki Pfau 2019-09-28 16:00:17 -07:00
commit e654c188f9
21 changed files with 479 additions and 91 deletions

View File

@ -7,8 +7,8 @@ os: linux
env:
- DOCKER_TAG=ubuntu:xenial
- DOCKER_TAG=ubuntu:bionic
- DOCKER_TAG=ubuntu:cosmic
- DOCKER_TAG=ubuntu:disco
- DOCKER_TAG=ubuntu:eoan
- DOCKER_TAG=3ds
- DOCKER_TAG=wii
- DOCKER_TAG=vita

58
CHANGES
View File

@ -41,6 +41,7 @@ Features:
- Qt: Add export button for tile view (closes mgba.io/i/1507)
- Qt: Add recent game list clearing (closes mgba.io/i/1380)
- GB: Yanking gamepak now supported
- Qt: Memory range dumping (closes mgba.io/i/1298)
Emulation fixes:
- GBA: All IRQs have 7 cycle delay (fixes mgba.io/i/539, mgba.io/i/1208)
- GBA: Reset now reloads multiboot ROMs
@ -48,39 +49,21 @@ Emulation fixes:
- GB Video: Delay LYC STAT check (fixes mgba.io/i/1331)
- GB Video: Fix window being enabled mid-scanline (fixes mgba.io/i/1328)
- GB I/O: Filter IE top bits properly (fixes mgba.io/i/1329)
- GBA Video: Fix wrapped sprite mosaic clamping (fixes mgba.io/i/1432)
- GBA Memory: Fix STM to VRAM (fixes mgba.io/i/1430)
- GB Audio: Only reset channel 3 sample in DMG mode
- GB Audio: Sample inactive channels (fixes mgba.io/i/1455, mgba.io/i/1456)
- GB Video: Increment BCPS/OCPS even in mode 3 (fixes mgba.io/i/1462)
- GB Audio: Deschedule channel 3 when disabled (fixes mgba.io/i/1463)
- GB Audio: Deschedule channel 1 when disabled by sweep (fixes mgba.io/i/1467)
- GBA Memory: Fix STM/LDM to invalid VRAM
- GB: Fix savedata initialization (fixes mgba.io/i/1473, mgba.io/i/1478)
- GB Memory: Better emulate 0xFEA0 region on DMG, MGB and AGB
- GB Printer: Reset printer buffer index after printing
- GB Video: Fix mode 0 window edge case (fixes mgba.io/i/1519)
- GBA Audio: Fix channel 4 aliasing (fixes mgba.io/i/1265)
- GB Audio: Improve channel 4 supersampling
- GB Audio: Fix channel 4 volume (fixes mgba.io/i/1529)
Other fixes:
- Qt: Fix some Qt display driver race conditions
- Core: Improved lockstep driver reliability (Le Hoang Quyen)
- Switch: Fix threading-related crash on second launch
- Qt: Fix FPS target maxing out at 59.727 (fixes mgba.io/i/1421)
- Core: Fix crashes if core directories aren't set
- Qt: Fix menu bar staying hidden in full screen (fixes mgba.io/i/317)
- GB SIO: Fix lockstep failing games aren't reloaded
- Core: Fix crash when exiting game with cheats loaded
- GBA Cheats: Fix PARv3 Thumb hooks
- mGUI: Fix crash if last loaded ROM directory disappears (fixes mgba.io/i/1466)
- Libretro: Fix crash changing allowing opposing directions (hhromic)
- Qt: Fix race conditions initializing GDB stub
- GBA: Set up GPIO mapping on null and ELF ROM regions (fixes mgba.io/i/1481)
- GBA Cheats: Fix value incrementing in CB slide codes (fixes mgba.io/i/1501)
- Qt: Only show emulator restart warning once per settings saving
- Qt: Improve cheat view UX
- GB: Fix SGB controller incrementing (fixes mgba.io/i/1104)
- FFmpeg: Drain recording buffers
- Shaders: Fix gba-color shader resolution (fixes mgba.io/i/1435)
Misc:
- GBA Savedata: EEPROM performance fixes
- GBA Savedata: Automatically map 1Mbit Flash files as 1Mbit Flash
@ -100,16 +83,47 @@ Misc:
- Qt: Add native FPS button to settings view
- Qt: Improve sync code
- Switch: Dynamic display resizing
- Qt: Make mute menu option also toggle fast-forward mute (fixes mgba.io/i/1424)
- Vita: L2/R2 and L3/R3 can now be mapped on PSTV (fixes mgba.io/i/1292)
- mGUI: Remember name and position of last loaded game
- Core: Create game-related paths if they don't exist (fixes mgba.io/i/1446)
- Qt: Add option to pause on minimizing window (closes mgba.io/i/1379)
- Switch: Support file associations
- Qt: Show error message if file failed to load
- Qt: Scale pixel color values to full range (fixes mgba.io/i/1511)
- Qt, OpenGL: Disable integer scaling for dimensions that don't fit
- Feature: Switch from ImageMagick to FFmpeg for GIF generation
- OpenGL: Only resize textures when needed
- GBA BIOS: Fix clobbered registers in CpuSet (fixes mgba.io/i/1531)
- Qt: Remove What's This icon from dialogs
0.7.3: (2019-09-15)
Emulation fixes:
- GB: Fix savedata initialization (fixes mgba.io/i/1473, mgba.io/i/1478)
- GB: Fix SGB controller incrementing (fixes mgba.io/i/1104)
- GB Audio: Improve channel 4 supersampling
- GB Printer: Reset printer buffer index after printing
- GB Audio: Deschedule channel 3 when disabled (fixes mgba.io/i/1463)
- GB Audio: Deschedule channel 1 when disabled by sweep (fixes mgba.io/i/1467)
- GB Video: Increment BCPS/OCPS even in mode 3 (fixes mgba.io/i/1462)
- GBA Memory: Fix STM to VRAM (fixes mgba.io/i/1430)
- GBA Memory: Fix STM/LDM to invalid VRAM
- GBA Video: Fix wrapped sprite mosaic clamping (fixes mgba.io/i/1432)
- GBA Audio: Fix channel 4 aliasing (fixes mgba.io/i/1265)
Other fixes:
- Core: Fix crashes if core directories aren't set
- Core: Fix crash when exiting game with cheats loaded
- GBA: Set up GPIO mapping on null and ELF ROM regions (fixes mgba.io/i/1481)
- GBA Cheats: Fix PARv3 Thumb hooks
- GBA Cheats: Fix value incrementing in CB slide codes (fixes mgba.io/i/1501)
- Qt: Fix FPS target maxing out at 59.727 (fixes mgba.io/i/1421)
- Qt: Cap audio buffer size to 8192 (fixes mgba.io/i/1433)
- Qt: Fix race conditions initializing GDB stub
- Qt: Improve cheat view UX
- Libretro: Fix crash changing allowing opposing directions (hhromic)
- mGUI: Fix crash if last loaded ROM directory disappears (fixes mgba.io/i/1466)
- Switch: Fix threading-related crash on second launch
Misc:
- Qt: Make mute menu option also toggle fast-forward mute (fixes mgba.io/i/1424)
- Qt: Show error message if file failed to load
0.7.2: (2019-05-25)
Emulation fixes:

View File

@ -7,6 +7,8 @@ passes=1
[pass.0]
fragmentShader=gba-color.fs
blend=1
width=-1
height=-1
[pass.0.uniform.darken_screen]
type=float

View File

@ -770,7 +770,7 @@ static int32_t _updateSquareChannel(struct GBAudioSquareChannel* ch) {
static int16_t _coalesceNoiseChannel(struct GBAudioNoiseChannel* ch) {
if (!ch->nSamples) {
return ch->sample;
return ch->sample << 3;
}
// TODO keep track of timing
int16_t sample = (ch->samples << 3) / ch->nSamples;

View File

@ -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_SIZE_CART_BANK0 * 2, 0x800000, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED, 511 },
{ 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_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,10 +56,10 @@ 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_SIZE_CART_BANK0 * 2, 0x800000, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED, 511 },
{ 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_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_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 },
{ GB_BASE_OAM, "oam", "OAM", "OBJ Attribute Memory", GB_BASE_OAM, GB_BASE_OAM + GB_SIZE_OAM, GB_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GB_BASE_IO, "io", "MMIO", "Memory-Mapped I/O", GB_BASE_IO, GB_BASE_IO + GB_SIZE_IO, GB_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GB_BASE_HRAM, "hram", "HRAM", "High RAM", GB_BASE_HRAM, GB_BASE_HRAM + GB_SIZE_HRAM, GB_SIZE_HRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },

View File

@ -6,7 +6,7 @@ const uint8_t hleBios[SIZE_BIOS] = {
0x06, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 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, 0xec, 0x01, 0x9f, 0x15,
0x03, 0x10, 0xd0, 0xe5, 0xea, 0x00, 0x51, 0xe3, 0xf8, 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,
@ -20,7 +20,7 @@ const uint8_t hleBios[SIZE_BIOS] = {
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,
0xc8, 0x01, 0x00, 0x00, 0x0f, 0x50, 0x2d, 0xe9, 0x01, 0x03, 0xa0, 0xe3,
0xd4, 0x01, 0x00, 0x00, 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,
@ -29,18 +29,19 @@ const uint8_t hleBios[SIZE_BIOS] = {
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, 0x00, 0x40, 0x2d, 0xe9,
0x02, 0x36, 0xa0, 0xe1, 0x01, 0x04, 0x12, 0xe3, 0x0f, 0x00, 0x00, 0x0a,
0x01, 0x03, 0x12, 0xe3, 0x05, 0x00, 0x00, 0x0a, 0x23, 0x35, 0x81, 0xe0,
0x04, 0x00, 0xb0, 0xe8, 0x03, 0x00, 0x51, 0xe1, 0x04, 0x00, 0xa1, 0xb8,
0xfc, 0xff, 0xff, 0xba, 0x14, 0x00, 0x00, 0xea, 0x01, 0x00, 0xc0, 0xe3,
0x01, 0x10, 0xc1, 0xe3, 0xa3, 0x35, 0x81, 0xe0, 0xb0, 0x20, 0xd0, 0xe1,
0x03, 0x00, 0x51, 0xe1, 0xb2, 0x20, 0xc1, 0xb0, 0xfc, 0xff, 0xff, 0xba,
0x0c, 0x00, 0x00, 0xea, 0x01, 0x03, 0x12, 0xe3, 0x05, 0x00, 0x00, 0x0a,
0x23, 0x35, 0x81, 0xe0, 0x03, 0x00, 0x51, 0xe1, 0x04, 0x00, 0xb0, 0xb8,
0x04, 0x00, 0xa1, 0xb8, 0xfb, 0xff, 0xff, 0xba, 0x04, 0x00, 0x00, 0xea,
0xa3, 0x35, 0x81, 0xe0, 0x03, 0x00, 0x51, 0xe1, 0xb2, 0x20, 0xd0, 0xb0,
0xb2, 0x20, 0xc1, 0xb0, 0xfb, 0xff, 0xff, 0xba, 0x00, 0x80, 0xbd, 0xe8,
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,

View File

@ -15,4 +15,4 @@ hle-bios.c: hle-bios.bin
echo >> $@
echo '#include <mgba/internal/gba/memory.h>' >> $@
echo >> $@
xxd -i $< | sed -e 's/unsigned char hle_bios_bin\[\]/const uint8_t hleBios[SIZE_BIOS]/' | grep -v hle_bios_bin_len >> $@
xxd -i $< | sed -e 's/unsigned char hle_bios_bin\[\]/const uint8_t hleBios[SIZE_BIOS]/' -e 's/^ \+/\t/' | grep -v hle_bios_bin_len >> $@

View File

@ -65,7 +65,7 @@ swiTable:
.word ArcTan2
.word CpuSet
.word CpuFastSet
# ... The rest of this table isn't needed if the rest aren't implemented
@ ... The rest of this table isn't needed if the rest aren't implemented
irqBase:
stmfd sp!, {r0-r3, r12, lr}
@ -83,7 +83,7 @@ mov r1, #1
IntrWait:
stmfd sp!, {r2-r3, lr}
mov r12, #0x04000000
# See if we want to return immediately
@ See if we want to return immediately
cmp r0, #0
mov r0, #0
mov r2, #1
@ -91,11 +91,11 @@ beq 1f
ldrh r3, [r12, #-8]
bic r3, r1
strh r3, [r12, #-8]
# Halt
@ Halt
0:
strb r0, [r12, #0x301]
1:
# Check which interrupts were acknowledged
@ Check which interrupts were acknowledged
strb r0, [r12, #0x208]
ldrh r3, [r12, #-8]
ands r3, r1
@ -106,54 +106,57 @@ beq 0b
ldmfd sp!, {r2-r3, pc}
CpuSet:
stmfd sp!, {lr}
mov r3, r2, lsl #12
stmfd sp!, {r4, r5, lr}
mov r4, r2, lsl #12
mov r12, r0
mov r5, r1
tst r2, #0x01000000
beq 0f
# Fill
@ Fill
tst r2, #0x04000000
beq 1f
# Word
add r3, r1, r3, lsr #10
ldmia r0!, {r2}
@ Word
add r4, r5, r4, lsr #10
ldmia r12!, {r3}
2:
cmp r1, r3
stmltia r1!, {r2}
cmp r5, r4
stmltia r5!, {r3}
blt 2b
b 3f
# Halfword
@ Halfword
1:
bic r0, #1
bic r1, #1
add r3, r1, r3, lsr #11
ldrh r2, [r0]
bic r12, #1
bic r5, #1
add r4, r5, r4, lsr #11
ldrh r3, [r12]
2:
cmp r1, r3
strlth r2, [r1], #2
cmp r5, r4
strlth r3, [r5], #2
blt 2b
b 3f
# Copy
@ Copy
0:
tst r2, #0x04000000
beq 1f
# Word
add r3, r1, r3, lsr #10
@ Word
add r4, r5, r4, lsr #10
2:
cmp r1, r3
ldmltia r0!, {r2}
stmltia r1!, {r2}
cmp r5, r4
ldmltia r12!, {r3}
stmltia r5!, {r3}
blt 2b
b 3f
# Halfword
@ Halfword
1:
add r3, r1, r3, lsr #11
add r4, r5, r4, lsr #11
2:
cmp r1, r3
ldrlth r2, [r0], #2
strlth r2, [r1], #2
cmp r5, r4
ldrlth r3, [r12], #2
strlth r3, [r5], #2
blt 2b
3:
ldmfd sp!, {pc}
mov r3, #0x170 @ Match official BIOS's clobbered r3
ldmfd sp!, {r4, r5, pc}
CpuFastSet:
stmfd sp!, {r4-r10, lr}
@ -161,7 +164,7 @@ tst r2, #0x01000000
mov r3, r2, lsl #12
add r2, r1, r3, lsr #10
beq 0f
# Fill
@ Fill
ldr r3, [r0]
mov r4, r3
mov r5, r3
@ -175,7 +178,7 @@ cmp r1, r2
stmltia r1!, {r3-r10}
blt 1b
b 2f
# Copy
@ Copy
0:
cmp r1, r2
ldmltia r0!, {r3-r10}

View File

@ -178,6 +178,15 @@ static void mGLES2ContextSetDimensions(struct VideoBackend* v, unsigned width, u
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
#endif
size_t n;
for (n = 0; n < context->nShaders; ++n) {
if (context->shaders[n].width < 0 || context->shaders[n].height < 0) {
context->shaders[n].dirty = true;
}
}
context->initialShader.dirty = true;
context->interframeShader.dirty = true;
}
static void mGLES2ContextDeinit(struct VideoBackend* v) {
@ -191,6 +200,7 @@ static void mGLES2ContextDeinit(struct VideoBackend* v) {
}
static void mGLES2ContextResized(struct VideoBackend* v, unsigned w, unsigned h) {
struct mGLES2Context* context = (struct mGLES2Context*) v;
unsigned drawW = w;
unsigned drawH = h;
if (v->lockAspectRatio) {
@ -208,6 +218,12 @@ static void mGLES2ContextResized(struct VideoBackend* v, unsigned w, unsigned h)
drawH -= drawH % v->height;
}
}
size_t n;
for (n = 0; n < context->nShaders; ++n) {
if (context->shaders[n].width == 0 || context->shaders[n].height == 0) {
context->shaders[n].dirty = true;
}
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH);
}
@ -221,8 +237,6 @@ static void mGLES2ContextClear(struct VideoBackend* v) {
void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) {
GLint viewport[4];
glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo);
glGetIntegerv(GL_VIEWPORT, viewport);
int drawW = shader->width;
int drawH = shader->height;
@ -246,6 +260,19 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) {
drawW -= drawW % context->d.width;
drawH -= drawH % context->d.height;
}
if (shader->dirty) {
if (shader->tex && (shader->width <= 0 || shader->height <= 0)) {
GLint oldTex;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
glBindTexture(GL_TEXTURE_2D, shader->tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, drawW, drawH, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, oldTex);
}
shader->dirty = false;
}
glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo);
glViewport(padW, padH, drawW, drawH);
if (shader->blend) {
glEnable(GL_BLEND);
@ -256,14 +283,6 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) {
glClear(GL_COLOR_BUFFER_BIT);
}
if (shader->tex && (shader->width <= 0 || shader->height <= 0)) {
GLint oldTex;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
glBindTexture(GL_TEXTURE_2D, shader->tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, drawW, drawH, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, oldTex);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, shader->filter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shader->filter ? GL_LINEAR : GL_NEAREST);
glUseProgram(shader->program);
@ -340,6 +359,7 @@ void mGLES2ContextDrawFrame(struct VideoBackend* v) {
glGetIntegerv(GL_VIEWPORT, viewport);
context->finalShader.filter = v->filter;
context->finalShader.dirty = true;
_drawShader(context, &context->initialShader);
if (v->interframeBlending) {
context->interframeShader.blend = true;
@ -404,6 +424,7 @@ void mGLES2ShaderInit(struct mGLES2Shader* shader, const char* vs, const char* f
shader->integerScaling = integerScaling;
shader->filter = false;
shader->blend = false;
shader->dirty = true;
shader->uniforms = uniforms;
shader->nUniforms = nUniforms;
glGenFramebuffers(1, &shader->fbo);

View File

@ -60,6 +60,7 @@ struct mGLES2Shader {
bool integerScaling;
bool filter;
bool blend;
bool dirty;
GLuint tex;
GLuint fbo;
GLuint vao;

View File

@ -10,7 +10,7 @@
using namespace QGBA;
ArchiveInspector::ArchiveInspector(const QString& filename, QWidget* parent)
: QDialog(parent)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
{
m_ui.setupUi(this);
connect(m_ui.archiveView, &LibraryController::doneLoading, [this]() {

View File

@ -83,6 +83,7 @@ set(SOURCE_FILES
LogConfigModel.cpp
LogView.cpp
MapView.cpp
MemoryDump.cpp
MemoryModel.cpp
MemorySearch.cpp
MemoryView.cpp
@ -129,6 +130,7 @@ set(UI_FILES
LoadSaveState.ui
LogView.ui
MapView.ui
MemoryDump.ui
MemorySearch.ui
MemoryView.ui
ObjView.ui

View File

@ -1024,7 +1024,7 @@ const QList<IOViewer::RegisterDescription>& IOViewer::registerDescriptions() {
}
IOViewer::IOViewer(std::shared_ptr<CoreController> controller, QWidget* parent)
: QDialog(parent)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
, m_controller(controller)
{
m_ui.setupUi(this);

View File

@ -0,0 +1,120 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MemoryDump.h"
#include "CoreController.h"
#include "GBAApp.h"
#include "LogController.h"
using namespace QGBA;
MemoryDump::MemoryDump(std::shared_ptr<CoreController> controller, QWidget* parent)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
, m_controller(controller)
{
m_ui.setupUi(this);
connect(this, &QDialog::accepted, this, &MemoryDump::save);
}
void MemoryDump::save() {
QString filename = GBAApp::app()->getSaveFileName(this, tr("Save memory region"));
if (filename.isNull()) {
return;
}
QFile outfile(filename);
if (!outfile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
LOG(QT, WARN) << tr("Failed to open output file: %1").arg(filename);
return;
}
QByteArray out(serialize());
outfile.write(out);
}
void MemoryDump::setAddress(uint32_t start) {
m_ui.address->setValue(start);
}
void MemoryDump::setSegment(int seg) {
m_ui.segment->setValue(seg);
}
void MemoryDump::setByteCount(uint32_t count) {
m_ui.bytes->setValue(count);
}
QByteArray MemoryDump::serialize() {
CoreController::Interrupter interrupter(m_controller);
mCore* core = m_controller->thread()->core;
const mCoreMemoryBlock* blocks;
size_t nBlocks = core->listMemoryBlocks(core, &blocks);
int size = m_ui.bytes->value();
uint32_t start = m_ui.address->value();
int segment = m_ui.segment->value();
bool spanSegments = m_ui.spanSegments->isChecked();
QByteArray mem;
while (size) {
const mCoreMemoryBlock* bestMatch = NULL;
const char* block = NULL;
size_t blockSize = 0;
for (size_t i = 0; i < nBlocks; ++i) {
if (blocks[i].end <= start) {
continue;
}
if (blocks[i].start > start) {
continue;
}
block = static_cast<const char*>(core->getMemoryBlock(core, blocks[i].id, &blockSize));
if (block) {
bestMatch = &blocks[i];
break;
} else if (!bestMatch) {
bestMatch = &blocks[i];
blockSize = 0;
}
}
if (!spanSegments) {
blockSize = bestMatch->end - bestMatch->start;
} else if (!blockSize) {
blockSize = bestMatch->size;
}
size_t segmentSize = bestMatch->end - bestMatch->start;
if (bestMatch->segmentStart) {
segmentSize = bestMatch->segmentStart - bestMatch->start;
}
if (segment > 0) {
start += segment * segmentSize;
}
int maxFromRegion = blockSize - (start - bestMatch->start);
if (maxFromRegion <= 0) {
continue;
}
int fromRegion = std::min(size, maxFromRegion);
if (block && (segment >= 0 || segmentSize == blockSize)) {
block = &block[start - bestMatch->start];
mem.append(QByteArray::fromRawData(block, fromRegion));
size -= fromRegion;
start += fromRegion;
if (spanSegments) {
break;
}
} else {
for (int i = 0; i < 16; ++i) {
char datum = core->rawRead8(core, start, segment);
mem.append(datum);
++start;
--size;
if (!size) {
break;
}
}
}
}
return mem;
}

View File

@ -0,0 +1,38 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
#include "ui_MemoryDump.h"
#include <memory>
namespace QGBA {
class CoreController;
class MemoryDump : public QDialog {
Q_OBJECT
public:
MemoryDump(std::shared_ptr<CoreController> controller, QWidget* parent = nullptr);
public slots:
void setSegment(int);
void setAddress(uint32_t address);
void setByteCount(uint32_t);
private slots:
void save();
private:
QByteArray serialize();
Ui::MemoryDump m_ui;
std::shared_ptr<CoreController> m_controller;
};
}

View File

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MemoryDump</class>
<widget class="QDialog" name="MemoryDump">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>448</width>
<height>208</height>
</rect>
</property>
<property name="windowTitle">
<string>Save Memory Range</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Start Address:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSpinBox" name="segment">
<property name="minimum">
<number>-1</number>
</property>
<property name="maximum">
<number>511</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="address">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="accelerated">
<bool>true</bool>
</property>
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>268435455</number>
</property>
<property name="singleStep">
<number>16</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Byte Count:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="bytes">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="prefix">
<string>0x</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>268435456</number>
</property>
<property name="value">
<number>256</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="spanSegments">
<property name="text">
<string>Dump across banks</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>MemoryDump</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MemoryDump</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -7,6 +7,7 @@
#include "MemoryView.h"
#include "CoreController.h"
#include "MemoryDump.h"
#include <mgba/core/core.h>
@ -44,6 +45,7 @@ MemoryView::MemoryView(std::shared_ptr<CoreController> controller, QWidget* pare
connect(m_ui.setAddress, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
this, static_cast<void (MemoryView::*)(uint32_t)>(&MemoryView::jumpToAddress));
connect(m_ui.hexfield, &MemoryModel::selectionChanged, this, &MemoryView::updateSelection);
connect(m_ui.saveRange, &QAbstractButton::clicked, this, &MemoryView::saveRange);
connect(controller.get(), &CoreController::stopping, this, &QWidget::close);
@ -69,6 +71,7 @@ void MemoryView::setIndex(int index) {
m_region = qMakePair(info.start, info.end);
m_ui.segments->setValue(-1);
m_ui.segments->setVisible(info.maxSegment > 0);
m_ui.segmentColon->setVisible(info.maxSegment > 0);
m_ui.segments->setMaximum(info.maxSegment);
m_ui.hexfield->setRegion(info.start, info.end - info.start, info.shortName);
}
@ -142,3 +145,12 @@ void MemoryView::updateStatus() {
break;
}
}
void MemoryView::saveRange() {
MemoryDump* memdump = new MemoryDump(m_controller);
memdump->setAttribute(Qt::WA_DeleteOnClose);
memdump->setAddress(m_selection.first);
memdump->setSegment(m_ui.segments->value());
memdump->setByteCount(m_selection.second - m_selection.first);
memdump->show();
}

View File

@ -28,6 +28,7 @@ private slots:
void setSegment(int);
void updateSelection(uint32_t start, uint32_t end);
void updateStatus();
void saveRange();
private:
Ui::MemoryView m_ui;

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>822</width>
<height>886</height>
<width>874</width>
<height>900</height>
</rect>
</property>
<property name="windowTitle">
@ -52,6 +52,13 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="segmentColon">
<property name="text">
<string>:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="setAddress">
<property name="accelerated">
@ -271,6 +278,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="saveRange">
<property name="text">
<string>Save Range</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="load">
<property name="text">

View File

@ -14,7 +14,7 @@
using namespace QGBA;
PlacementControl::PlacementControl(std::shared_ptr<CoreController> controller, QWidget* parent)
: QDialog(parent)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
, m_controller(controller)
{
m_ui.setupUi(this);

View File

@ -13,7 +13,7 @@
using namespace QGBA;
PrinterView::PrinterView(std::shared_ptr<CoreController> controller, QWidget* parent)
: QDialog(parent)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
, m_controller(controller)
{
m_ui.setupUi(this);