Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2021-06-29 20:26:03 -07:00
commit f7943aaa98
12 changed files with 156 additions and 90 deletions

View File

@ -38,10 +38,18 @@ Emulation fixes:
- Core: Fix first event scheduling after loading savestate
- GB Serialize: Fix switching speed modes when loading a state (fixes mgba.io/i/2097)
- GBA Memory: Fix loading Thumb savestates when in ARM mode
- GBA Video: Fix window start on modes 3-5 with mosaic (fixes mgba.io/i/1690)
- GBA Video: Fix mode 3-5 overflow with mosaic (fixes mgba.io/i/1691)
Other fixes:
- GBA: Fix non-USA 1.0 FireRed misdetecting as a ROM hack (fixes mgba.io/i/2100)
- GBA: Fix crash when ROM loading fails
- GBA e-Reader: Fix bitmap short strip scanning
- GBA Video: Fix mode 5 frame 1 caching (fixes mgba.io/i/2075)
- GBA Video: Don't attempt to copy invalid registers when switching renderer
Misc:
- Core: Truncate preloading ROMs that slightly exceed max size (fixes mgba.io/i/2093)
- GBA: Default-enable VBA bug compat for Ruby and Emerald ROM hacks
- GBA Memory: Log GPIO writes on non-GPIO carts as Pak Hardware instead of Memory
- Qt: Add ROM filename and size to bug reporter
0.9.0: (2021-03-28)

View File

@ -139,18 +139,18 @@ void mBitmapCacheCleanRow(struct mBitmapCache* cache, struct mBitmapCacheEntry*
return;
}
size_t offset = cache->bitsStart[cache->buffer] + y * mBitmapCacheSystemInfoGetWidth(cache->sysConfig);
size_t offset = y * mBitmapCacheSystemInfoGetWidth(cache->sysConfig);
void* vram;
int bpe = mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig);
uint32_t (*lookupEntry)(void*, uint32_t);
switch (bpe) {
case 3:
lookupEntry = _lookupEntry8;
vram = &cache->vram[offset];
vram = &cache->vram[offset + cache->bitsStart[cache->buffer]];
break;
case 4:
lookupEntry = _lookupEntry15;
vram = &cache->vram[offset << 1];
vram = &cache->vram[offset * 2 + cache->bitsStart[cache->buffer]];
break;
default:
abort();

View File

@ -166,7 +166,13 @@ bool mCorePreloadVFCB(struct mCore* core, struct VFile* vf, void (cb)(size_t, si
extern uint32_t* romBuffer;
extern size_t romBufferSize;
if (size > romBufferSize) {
return false;
if (size - romBufferSize < romBufferSize / 2) {
// Some ROM hacks accidentally overflow the size a bit, but since those are broken
// on hardware anyway we can just silently truncate them without issue.
size = romBufferSize;
} else {
return false;
}
}
vfm = VFileFromMemory(romBuffer, size);
#else

View File

@ -370,6 +370,11 @@ void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, s
// Bitmap sizes
case 5456:
bitmap = true;
blocks = 124;
break;
case 3520:
bitmap = true;
blocks = 80;
break;
default:
return;
@ -380,9 +385,9 @@ void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, s
if (bitmap) {
size_t x;
for (i = 0; i < 40; ++i) {
const uint8_t* line = &cdata[(i + 2) * 124];
const uint8_t* line = &cdata[(i + 2) * blocks];
uint8_t* origin = &hw->eReaderDots[EREADER_DOTCODE_STRIDE * i + 200];
for (x = 0; x < 124; ++x) {
for (x = 0; x < blocks; ++x) {
uint8_t byte = line[x];
if (x == 123) {
byte &= 0xE0;

View File

@ -912,7 +912,11 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
}
break;
case REGION_CART0:
if (memory->hw.devices != HW_NONE && IS_GPIO_REGISTER(address & 0xFFFFFE)) {
if (IS_GPIO_REGISTER(address & 0xFFFFFE)) {
if (memory->hw.devices == HW_NONE) {
mLOG(GBA_HW, WARN, "Write to GPIO address %08X on cartridge without GPIO", address);
break;
}
uint32_t reg = address & 0xFFFFFE;
GBAHardwareGPIOWrite(&memory->hw, reg, value);
break;

View File

@ -376,6 +376,14 @@ void GBAOverrideApplyDefaults(struct GBA* gba, const struct Configuration* overr
memcpy(override.id, &cart->id, sizeof(override.id));
static const uint32_t pokemonTable[] = {
// Emerald
0x4881F3F8, // BPEJ
0x8C4D3108, // BPES
0x1F1C08FB, // BPEE
0x34C9DF89, // BPED
0xA3FDCCB1, // BPEF
0xA0AEC80A, // BPEI
// FireRed
0x1A81EEDF, // BPRD
0x3B2056E9, // BPRJ
@ -385,10 +393,17 @@ void GBAOverrideApplyDefaults(struct GBA* gba, const struct Configuration* overr
0x9F08064E, // BPRS
0xBB640DF7, // BPRJ rev 1
0xDD88761C, // BPRE
// Ruby
0x61641576, // AXVE rev 1
0xAEAC73E6, // AXVE rev 2
0xF0815EE7, // AXVE
};
bool isPokemon = false;
isPokemon = isPokemon || !strncmp("pokemon red version", &((const char*) gba->memory.rom)[0x108], 20);
isPokemon = isPokemon || !strncmp("pokemon emerald version", &((const char*) gba->memory.rom)[0x108], 24);
isPokemon = isPokemon || !strncmp("AXVE", &((const char*) gba->memory.rom)[0xAC], 4);
bool isKnownPokemon = false;
if (isPokemon) {
size_t i;

View File

@ -8,16 +8,14 @@
#include <mgba/core/interface.h>
#include <mgba/internal/gba/gba.h>
#define BACKGROUND_BITMAP_ITERATE(W, H) \
x += background->dx; \
y += background->dy; \
\
if (x < 0 || y < 0 || (x >> 8) >= W || (y >> 8) >= H) { \
continue; \
} else { \
localX = x; \
localY = y; \
}
#define BACKGROUND_BITMAP_ITERATE(W, H) \
x += background->dx; \
y += background->dy; \
if ((x < 0 || y < 0 || (x >> 8) >= W || (y >> 8) >= H) && !mosaicWait) { \
continue; \
} \
localX = x; \
localY = y;
#define MODE_2_COORD_OVERFLOW \
localX = x & (sizeAdjusted - 1); \
@ -65,12 +63,20 @@
#define DRAW_BACKGROUND_MODE_2(BLEND, OBJWIN) \
if (background->overflow) { \
if (mosaicH > 1) { \
localX &= sizeAdjusted - 1; \
localY &= sizeAdjusted - 1; \
MODE_2_NO_MOSAIC(); \
MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \
} else { \
MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \
} \
} else { \
if (mosaicH > 1) { \
if (!((x | y) & ~(sizeAdjusted - 1))) { \
localX &= sizeAdjusted - 1; \
localY &= sizeAdjusted - 1; \
MODE_2_NO_MOSAIC(); \
} \
MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \
} else { \
MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \
@ -106,10 +112,14 @@ void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer
BACKGROUND_BITMAP_INIT;
uint32_t color = renderer->normalPalette[0];
if (mosaicWait && localX >= 0 && localY >= 0) {
LOAD_16(color, ((localX >> 8) + (localY >> 8) * renderer->masterEnd) << 1, renderer->d.vramBG[0]);
color = mColorFrom555(color);
}
int outX;
for (outX = renderer->start; outX < renderer->end; ++outX) {
BACKGROUND_BITMAP_ITERATE(renderer->masterEnd, GBA_VIDEO_VERTICAL_PIXELS);
BACKGROUND_BITMAP_ITERATE(renderer->masterEnd, renderer->masterHeight);
if (!mosaicWait) {
LOAD_16(color, ((localX >> 8) + (localY >> 8) * renderer->masterEnd) << 1, renderer->d.vramBG[0]);
@ -144,6 +154,9 @@ void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer
if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
offset = 0xA000;
}
if (mosaicWait && localX >= 0 && localY >= 0) {
color = ((uint8_t*)renderer->d.vramBG[0])[offset + (localX >> 8) + (localY >> 8) * renderer->masterEnd];
}
int outX;
for (outX = renderer->start; outX < renderer->end; ++outX) {
@ -181,6 +194,10 @@ void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer
if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
offset = 0xA000;
}
if (mosaicWait && localX >= 0 && localY >= 0) {
LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vramBG[0]);
color = mColorFrom555(color);
}
int outX;
for (outX = renderer->start; outX < renderer->end; ++outX) {

View File

@ -175,15 +175,21 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
int32_t y = background->sy + (renderer->start - 1) * background->dy; \
int mosaicH = 0; \
int mosaicWait = 0; \
if (background->mosaic) { \
int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; \
y -= (inY % mosaicV) * background->dmy; \
x -= (inY % mosaicV) * background->dmx; \
mosaicH = GBAMosaicControlGetBgH(renderer->mosaic); \
mosaicWait = renderer->start % (mosaicH + 1); \
} \
int32_t localX; \
int32_t localY; \
if (background->mosaic) { \
int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; \
mosaicH = GBAMosaicControlGetBgH(renderer->mosaic) + 1; \
mosaicWait = (mosaicH - renderer->start + GBA_VIDEO_HORIZONTAL_PIXELS * mosaicH) % mosaicH; \
int32_t startX = renderer->start - (renderer->start % mosaicH); \
--mosaicH; \
localX = -(inY % mosaicV) * background->dmx; \
localY = -(inY % mosaicV) * background->dmy; \
x += localX; \
y += localY; \
localX += background->sx + startX * background->dx; \
localY += background->sy + startX * background->dy; \
} \
\
uint32_t flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \
flags |= FLAG_TARGET_2 * background->target2; \

View File

@ -60,7 +60,9 @@ static void _switchMode(struct GBASIO* sio) {
if (sio->activeDriver && sio->activeDriver->unload) {
sio->activeDriver->unload(sio->activeDriver);
}
mLOG(GBA_SIO, DEBUG, "Switching mode from %s to %s", _modeName(sio->mode), _modeName(newMode));
if (sio->mode != (enum GBASIOMode) -1) {
mLOG(GBA_SIO, DEBUG, "Switching mode from %s to %s", _modeName(sio->mode), _modeName(newMode));
}
sio->mode = newMode;
sio->activeDriver = _lookupDriver(sio, sio->mode);
if (sio->activeDriver && sio->activeDriver->load) {

View File

@ -153,7 +153,10 @@ void GBAVideoAssociateRenderer(struct GBAVideo* video, struct GBAVideoRenderer*
renderer->writeVideoRegister(renderer, REG_DISPCNT, video->p->memory.io[REG_DISPCNT >> 1]);
renderer->writeVideoRegister(renderer, REG_GREENSWP, video->p->memory.io[REG_GREENSWP >> 1]);
int address;
for (address = REG_BG0CNT; address < REG_SOUND1CNT_LO; address += 2) {
for (address = REG_BG0CNT; address < 0x56; address += 2) {
if (address == 0x4E) {
continue;
}
renderer->writeVideoRegister(renderer, address, video->p->memory.io[address >> 1]);
}
}

View File

@ -787,7 +787,7 @@ void CoreController::scanCard(const QString& path) {
QFile file(path);
file.open(QIODevice::ReadOnly);
m_eReaderData = file.read(2912);
} else if (image.size() == QSize(989, 44)) {
} else if (image.size() == QSize(989, 44) || image.size() == QSize(639, 44)) {
const uchar* bits = image.constBits();
size_t size;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))

View File

@ -34,8 +34,6 @@ for i in range(16):
for i in range(16):
gg[i] = rev[gg[i]]
print(*[hex(x) for x in gg])
def interleave(data, header):
data = data.reshape([-1, 48]).T
new_data = np.zeros((64, data.shape[1]), dtype=data.dtype)
@ -88,67 +86,69 @@ def bin2raw(data):
new_data = interleave(np.frombuffer(data, np.uint8), header)
return new_data.tobytes()
with open(sys.argv[1], 'rb') as f:
data = f.read()
size = len(data)
if size in (1344, 2112):
data = bin2raw(data)
def make_dotcode(data):
size = len(data)
with open('dotcode.raw', 'wb') as f:
f.write(data)
blocks = size // blocksize
height = 36
width = 35
margin = 2
if size in (1344, 2112):
data = bin2raw(data)
size = len(data)
dots = np.zeros((width * blocks + margin * 2 + 1, height + margin * 2), dtype=np.bool)
anchor = np.array([[0, 1, 1, 1, 0],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[0, 1, 1, 1, 0]], dtype=np.bool)
alignment = np.array([1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0], dtype=np.bool)
nybbles = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [1, 0, 0, 1, 0],
[0, 0, 1, 0, 0], [0, 0, 1, 0, 1], [0, 0, 1, 1, 0], [1, 0, 1, 1, 0],
[0, 1, 0, 0, 0], [0, 1, 0, 0, 1], [0, 1, 0, 1, 0], [1, 0, 1, 0, 0],
[0, 1, 1, 0, 0], [0, 1, 1, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 0]]
addr = [0x03FF]
for i in range(1, 54):
addr.append(addr[i - 1] ^ ((i & -i) * 0x769))
if (i & 0x07) == 0:
addr[i] ^= 0x769
if (i & 0x0F) == 0:
addr[i] ^= 0x769 << 1
if (i & 0x1F) == 0:
addr[i] ^= (0x769 << 2) ^ 0x769
blocks = size // blocksize
height = 36
width = 35
margin = 2
base = 1 if blocks == 18 else 25
for i in range(blocks + 1):
dots[i * width:i * width + 5, 0:5] = anchor
dots[i * width:i * width + 5, height + margin * 2 - 5:height + margin * 2] = anchor
dots[i * width + margin, margin + 5] = 1
a = addr[base + i]
for j in range(16):
dots[i * width + margin, margin + 14 + j] = a & (1 << (15 - j))
for i in range(blocks):
dots[i * width:(i + 1) * width, margin] = alignment
dots[i * width:(i + 1) * width, height + margin - 1] = alignment
block = []
for byte in data[i * blocksize:(i + 1) * blocksize]:
block.extend(nybbles[byte >> 4])
block.extend(nybbles[byte & 0xF])
j = 0
for y in range(3):
dots[i * width + margin + 5:i * width + margin + 31, margin + 2 + y] = block[j:j + 26]
j += 26
for y in range(26):
dots[i * width + margin + 1:i * width + margin + 35, margin + 5 + y] = block[j:j + 34]
j += 34
for y in range(3):
dots[i * width + margin + 5:i * width + margin + 31, margin + 31 + y] = block[j:j + 26]
j += 26
im = PIL.Image.fromarray(dots.T)
dots = np.zeros((width * blocks + margin * 2 + 1, height + margin * 2), dtype=bool)
anchor = np.array([[0, 1, 1, 1, 0],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[0, 1, 1, 1, 0]], dtype=bool)
alignment = np.array([1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0], dtype=bool)
nybbles = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [1, 0, 0, 1, 0],
[0, 0, 1, 0, 0], [0, 0, 1, 0, 1], [0, 0, 1, 1, 0], [1, 0, 1, 1, 0],
[0, 1, 0, 0, 0], [0, 1, 0, 0, 1], [0, 1, 0, 1, 0], [1, 0, 1, 0, 0],
[0, 1, 1, 0, 0], [0, 1, 1, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 0]]
addr = [0x03FF]
for i in range(1, 54):
addr.append(addr[i - 1] ^ ((i & -i) * 0x769))
if (i & 0x07) == 0:
addr[i] ^= 0x769
if (i & 0x0F) == 0:
addr[i] ^= 0x769 << 1
if (i & 0x1F) == 0:
addr[i] ^= (0x769 << 2) ^ 0x769
base = 1 if blocks == 18 else 25
for i in range(blocks + 1):
dots[i * width:i * width + 5, 0:5] = anchor
dots[i * width:i * width + 5, height + margin * 2 - 5:height + margin * 2] = anchor
dots[i * width + margin, margin + 5] = 1
a = addr[base + i]
for j in range(16):
dots[i * width + margin, margin + 14 + j] = a & (1 << (15 - j))
for i in range(blocks):
dots[i * width:(i + 1) * width, margin] = alignment
dots[i * width:(i + 1) * width, height + margin - 1] = alignment
block = []
for byte in data[i * blocksize:(i + 1) * blocksize]:
block.extend(nybbles[byte >> 4])
block.extend(nybbles[byte & 0xF])
j = 0
for y in range(3):
dots[i * width + margin + 5:i * width + margin + 31, margin + 2 + y] = block[j:j + 26]
j += 26
for y in range(26):
dots[i * width + margin + 1:i * width + margin + 35, margin + 5 + y] = block[j:j + 34]
j += 34
for y in range(3):
dots[i * width + margin + 5:i * width + margin + 31, margin + 31 + y] = block[j:j + 26]
j += 26
return np.pad(dots.T, 2)
with open(sys.argv[1], 'rb') as f:
dots = make_dotcode(f.read())
im = PIL.Image.fromarray(dots)
im = PIL.ImageChops.invert(im)
im.save('dotcode.png')
im.save('dotcode.bmp')