View
@@ -69,8 +69,8 @@ static void _processByte(struct GBPrinter* printer) {
static uint8_t GBPrinterWriteSC(struct GBSIODriver* driver, uint8_t value) {
struct GBPrinter* printer = (struct GBPrinter*) driver;
if ((value & 0x81) == 0x81) {
- switch (printer->next) {
driver->p->pendingSB = 0;
+ switch (printer->next) {
case GB_PRINTER_BYTE_MAGIC_0:
if (printer->byte == 0x88) {
printer->next = GB_PRINTER_BYTE_MAGIC_1;
@@ -183,51 +183,54 @@ static uint8_t GBPrinterWriteSC(struct GBSIODriver* driver, uint8_t value) {
}
break;
case GB_PRINTER_COMMAND_STATUS:
- if (!printer->printWait) {
- printer->status &= ~GB_PRINTER_STATUS_READY;
- printer->status |= GB_PRINTER_STATUS_PRINTING | GB_PRINTER_STATUS_PRINT_REQ;
- if (printer->print) {
- size_t y;
- for (y = 0; y < printer->currentIndex / (2 * GB_VIDEO_HORIZONTAL_PIXELS); ++y) {
- uint8_t lineBuffer[GB_VIDEO_HORIZONTAL_PIXELS * 2];
- uint8_t* buffer = &printer->buffer[sizeof(lineBuffer) * y];
- size_t i;
- for (i = 0; i < sizeof(lineBuffer); i += 2) {
- uint8_t ilo = buffer[i + 0x0];
- uint8_t ihi = buffer[i + 0x1];
- uint8_t olo = 0;
- uint8_t ohi = 0;
- olo |= ((ihi & 0x80) >> 0) | ((ilo & 0x80) >> 1);
- olo |= ((ihi & 0x40) >> 1) | ((ilo & 0x40) >> 2);
- olo |= ((ihi & 0x20) >> 2) | ((ilo & 0x20) >> 3);
- olo |= ((ihi & 0x10) >> 3) | ((ilo & 0x10) >> 4);
- ohi |= ((ihi & 0x08) << 4) | ((ilo & 0x08) << 3);
- ohi |= ((ihi & 0x04) << 3) | ((ilo & 0x04) << 2);
- ohi |= ((ihi & 0x02) << 2) | ((ilo & 0x02) << 1);
- ohi |= ((ihi & 0x01) << 1) | ((ilo & 0x01) << 0);
- lineBuffer[(((i >> 1) & 0x7) * GB_VIDEO_HORIZONTAL_PIXELS / 4) + ((i >> 3) & ~1)] = olo;
- lineBuffer[(((i >> 1) & 0x7) * GB_VIDEO_HORIZONTAL_PIXELS / 4) + ((i >> 3) | 1)] = ohi;
- }
- memcpy(buffer, lineBuffer, sizeof(lineBuffer));
- }
- printer->print(printer, printer->currentIndex * 4 / GB_VIDEO_HORIZONTAL_PIXELS, printer->buffer);
- }
- }
- if (printer->printWait >= 0) {
- --printer->printWait;
- }
default:
break;
}
+
driver->p->pendingSB = printer->status;
printer->next = GB_PRINTER_BYTE_MAGIC_0;
break;
}
+
+ if (!printer->printWait) {
+ printer->status &= ~GB_PRINTER_STATUS_READY;
+ printer->status |= GB_PRINTER_STATUS_PRINTING | GB_PRINTER_STATUS_PRINT_REQ;
+ if (printer->print) {
+ size_t y;
+ for (y = 0; y < printer->currentIndex / (2 * GB_VIDEO_HORIZONTAL_PIXELS); ++y) {
+ uint8_t lineBuffer[GB_VIDEO_HORIZONTAL_PIXELS * 2];
+ uint8_t* buffer = &printer->buffer[sizeof(lineBuffer) * y];
+ size_t i;
+ for (i = 0; i < sizeof(lineBuffer); i += 2) {
+ uint8_t ilo = buffer[i + 0x0];
+ uint8_t ihi = buffer[i + 0x1];
+ uint8_t olo = 0;
+ uint8_t ohi = 0;
+ olo |= ((ihi & 0x80) >> 0) | ((ilo & 0x80) >> 1);
+ olo |= ((ihi & 0x40) >> 1) | ((ilo & 0x40) >> 2);
+ olo |= ((ihi & 0x20) >> 2) | ((ilo & 0x20) >> 3);
+ olo |= ((ihi & 0x10) >> 3) | ((ilo & 0x10) >> 4);
+ ohi |= ((ihi & 0x08) << 4) | ((ilo & 0x08) << 3);
+ ohi |= ((ihi & 0x04) << 3) | ((ilo & 0x04) << 2);
+ ohi |= ((ihi & 0x02) << 2) | ((ilo & 0x02) << 1);
+ ohi |= ((ihi & 0x01) << 1) | ((ilo & 0x01) << 0);
+ lineBuffer[(((i >> 1) & 0x7) * GB_VIDEO_HORIZONTAL_PIXELS / 4) + ((i >> 3) & ~1)] = olo;
+ lineBuffer[(((i >> 1) & 0x7) * GB_VIDEO_HORIZONTAL_PIXELS / 4) + ((i >> 3) | 1)] = ohi;
+ }
+ memcpy(buffer, lineBuffer, sizeof(lineBuffer));
+ }
+ printer->print(printer, printer->currentIndex * 4 / GB_VIDEO_HORIZONTAL_PIXELS, printer->buffer);
+ }
+ printer->printWait = -1;
+ } else if (printer->printWait > 0) {
+ --printer->printWait;
+ }
+
printer->byte = 0;
}
return value;
}
void GBPrinterDonePrinting(struct GBPrinter* printer) {
- printer->status &= ~GB_PRINTER_STATUS_PRINTING;
+ printer->status &= ~(GB_PRINTER_STATUS_PRINTING | GB_PRINTER_STATUS_PRINT_REQ);
}
View
@@ -56,7 +56,7 @@ void GBVideoInit(struct GBVideo* video) {
video->renderer = &dummyRenderer;
video->renderer->cache = NULL;
video->renderer->sgbRenderMode = 0;
- video->vram = 0;
+ video->vram = anonymousMemoryMap(GB_SIZE_VRAM);
video->frameskip = 0;
video->modeEvent.context = video;
@@ -99,10 +99,6 @@ void GBVideoReset(struct GBVideo* video) {
video->frameCounter = 0;
video->frameskipCounter = 0;
- if (video->vram) {
- mappedMemoryFree(video->vram, GB_SIZE_VRAM);
- }
- video->vram = anonymousMemoryMap(GB_SIZE_VRAM);
GBVideoSwitchBank(video, 0);
video->renderer->vram = video->vram;
memset(&video->oam, 0, sizeof(video->oam));
@@ -310,7 +306,7 @@ void _endMode2(struct mTiming* timing, void* context, uint32_t cyclesLate) {
void _endMode3(struct mTiming* timing, void* context, uint32_t cyclesLate) {
struct GBVideo* video = context;
- GBVideoProcessDots(video);
+ GBVideoProcessDots(video, cyclesLate);
if (video->ly < GB_VIDEO_VERTICAL_PIXELS && video->p->memory.isHdma && video->p->memory.io[REG_HDMA5] != 0xFF) {
video->p->memory.hdmaRemaining = 0x10;
video->p->cpuBlocked = true;
@@ -400,12 +396,12 @@ static void _cleanOAM(struct GBVideo* video, int y) {
video->objMax = o;
}
-void GBVideoProcessDots(struct GBVideo* video) {
+void GBVideoProcessDots(struct GBVideo* video, uint32_t cyclesLate) {
if (video->mode != 3) {
return;
}
int oldX = video->x;
- video->x = (video->p->timing.masterCycles - video->dotClock + video->p->cpu->cycles) >> video->p->doubleSpeed;
+ video->x = (mTimingCurrentTime(&video->p->timing) - video->dotClock - cyclesLate) >> video->p->doubleSpeed;
if (video->x > GB_VIDEO_HORIZONTAL_PIXELS) {
video->x = GB_VIDEO_HORIZONTAL_PIXELS;
} else if (video->x < 0) {
@@ -455,7 +451,10 @@ void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) {
void GBVideoWriteSTAT(struct GBVideo* video, GBRegisterSTAT value) {
GBRegisterSTAT oldStat = video->stat;
video->stat = (video->stat & 0x7) | (value & 0x78);
- if (video->p->model < GB_MODEL_CGB && !_statIRQAsserted(video, oldStat) && video->mode < 3) {
+ if (!GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC]) || video->p->model >= GB_MODEL_CGB) {
+ return;
+ }
+ if (!_statIRQAsserted(video, oldStat) && video->mode < 3) {
// TODO: variable for the IRQ line value?
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
GBUpdateIRQs(video->p);
@@ -595,78 +594,78 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) {
video->palette[2] = data[5] | (data[6] << 8);
video->palette[3] = data[7] | (data[8] << 8);
- video->palette[16] = data[1] | (data[2] << 8);
- video->palette[17] = data[9] | (data[10] << 8);
- video->palette[18] = data[11] | (data[12] << 8);
- video->palette[19] = data[13] | (data[14] << 8);
+ video->palette[4] = data[1] | (data[2] << 8);
+ video->palette[5] = data[9] | (data[10] << 8);
+ video->palette[6] = data[11] | (data[12] << 8);
+ video->palette[7] = data[13] | (data[14] << 8);
- video->palette[32] = data[1] | (data[2] << 8);
- video->palette[48] = data[1] | (data[2] << 8);
+ video->palette[8] = data[1] | (data[2] << 8);
+ video->palette[12] = data[1] | (data[2] << 8);
video->renderer->writePalette(video->renderer, 0, video->palette[0]);
video->renderer->writePalette(video->renderer, 1, video->palette[1]);
video->renderer->writePalette(video->renderer, 2, video->palette[2]);
video->renderer->writePalette(video->renderer, 3, video->palette[3]);
- video->renderer->writePalette(video->renderer, 16, video->palette[0]);
- video->renderer->writePalette(video->renderer, 17, video->palette[17]);
- video->renderer->writePalette(video->renderer, 18, video->palette[18]);
- video->renderer->writePalette(video->renderer, 19, video->palette[19]);
- video->renderer->writePalette(video->renderer, 32, video->palette[0]);
- video->renderer->writePalette(video->renderer, 48, video->palette[0]);
+ video->renderer->writePalette(video->renderer, 4, video->palette[0]);
+ video->renderer->writePalette(video->renderer, 5, video->palette[5]);
+ video->renderer->writePalette(video->renderer, 6, video->palette[6]);
+ video->renderer->writePalette(video->renderer, 7, video->palette[7]);
+ video->renderer->writePalette(video->renderer, 8, video->palette[0]);
+ video->renderer->writePalette(video->renderer, 12, video->palette[0]);
break;
case SGB_PAL23:
- video->palette[33] = data[3] | (data[4] << 8);
- video->palette[34] = data[5] | (data[6] << 8);
- video->palette[35] = data[7] | (data[8] << 8);
-
- video->palette[49] = data[9] | (data[10] << 8);
- video->palette[50] = data[11] | (data[12] << 8);
- video->palette[51] = data[13] | (data[14] << 8);
- video->renderer->writePalette(video->renderer, 33, video->palette[33]);
- video->renderer->writePalette(video->renderer, 34, video->palette[34]);
- video->renderer->writePalette(video->renderer, 35, video->palette[35]);
- video->renderer->writePalette(video->renderer, 49, video->palette[49]);
- video->renderer->writePalette(video->renderer, 50, video->palette[50]);
- video->renderer->writePalette(video->renderer, 51, video->palette[51]);
+ video->palette[9] = data[3] | (data[4] << 8);
+ video->palette[10] = data[5] | (data[6] << 8);
+ video->palette[11] = data[7] | (data[8] << 8);
+
+ video->palette[13] = data[9] | (data[10] << 8);
+ video->palette[14] = data[11] | (data[12] << 8);
+ video->palette[15] = data[13] | (data[14] << 8);
+ video->renderer->writePalette(video->renderer, 9, video->palette[9]);
+ video->renderer->writePalette(video->renderer, 10, video->palette[10]);
+ video->renderer->writePalette(video->renderer, 11, video->palette[11]);
+ video->renderer->writePalette(video->renderer, 13, video->palette[13]);
+ video->renderer->writePalette(video->renderer, 14, video->palette[14]);
+ video->renderer->writePalette(video->renderer, 15, video->palette[15]);
break;
case SGB_PAL03:
video->palette[0] = data[1] | (data[2] << 8);
video->palette[1] = data[3] | (data[4] << 8);
video->palette[2] = data[5] | (data[6] << 8);
video->palette[3] = data[7] | (data[8] << 8);
- video->palette[16] = data[1] | (data[2] << 8);
- video->palette[32] = data[1] | (data[2] << 8);
+ video->palette[4] = data[1] | (data[2] << 8);
+ video->palette[8] = data[1] | (data[2] << 8);
- video->palette[48] = data[1] | (data[2] << 8);
- video->palette[49] = data[9] | (data[10] << 8);
- video->palette[50] = data[11] | (data[12] << 8);
- video->palette[51] = data[13] | (data[14] << 8);
+ video->palette[12] = data[1] | (data[2] << 8);
+ video->palette[13] = data[9] | (data[10] << 8);
+ video->palette[14] = data[11] | (data[12] << 8);
+ video->palette[15] = data[13] | (data[14] << 8);
video->renderer->writePalette(video->renderer, 0, video->palette[0]);
video->renderer->writePalette(video->renderer, 1, video->palette[1]);
video->renderer->writePalette(video->renderer, 2, video->palette[2]);
video->renderer->writePalette(video->renderer, 3, video->palette[3]);
- video->renderer->writePalette(video->renderer, 16, video->palette[0]);
- video->renderer->writePalette(video->renderer, 32, video->palette[0]);
- video->renderer->writePalette(video->renderer, 48, video->palette[0]);
- video->renderer->writePalette(video->renderer, 49, video->palette[49]);
- video->renderer->writePalette(video->renderer, 50, video->palette[50]);
- video->renderer->writePalette(video->renderer, 51, video->palette[51]);
+ video->renderer->writePalette(video->renderer, 4, video->palette[0]);
+ video->renderer->writePalette(video->renderer, 8, video->palette[0]);
+ video->renderer->writePalette(video->renderer, 12, video->palette[0]);
+ video->renderer->writePalette(video->renderer, 13, video->palette[13]);
+ video->renderer->writePalette(video->renderer, 14, video->palette[14]);
+ video->renderer->writePalette(video->renderer, 15, video->palette[15]);
break;
case SGB_PAL12:
- video->palette[17] = data[3] | (data[4] << 8);
- video->palette[18] = data[5] | (data[6] << 8);
- video->palette[19] = data[7] | (data[8] << 8);
-
- video->palette[33] = data[9] | (data[10] << 8);
- video->palette[34] = data[11] | (data[12] << 8);
- video->palette[35] = data[13] | (data[14] << 8);
- video->renderer->writePalette(video->renderer, 17, video->palette[17]);
- video->renderer->writePalette(video->renderer, 18, video->palette[18]);
- video->renderer->writePalette(video->renderer, 19, video->palette[19]);
- video->renderer->writePalette(video->renderer, 33, video->palette[33]);
- video->renderer->writePalette(video->renderer, 34, video->palette[34]);
- video->renderer->writePalette(video->renderer, 35, video->palette[35]);
+ video->palette[5] = data[3] | (data[4] << 8);
+ video->palette[6] = data[5] | (data[6] << 8);
+ video->palette[7] = data[7] | (data[8] << 8);
+
+ video->palette[9] = data[9] | (data[10] << 8);
+ video->palette[10] = data[11] | (data[12] << 8);
+ video->palette[11] = data[13] | (data[14] << 8);
+ video->renderer->writePalette(video->renderer, 5, video->palette[5]);
+ video->renderer->writePalette(video->renderer, 6, video->palette[6]);
+ video->renderer->writePalette(video->renderer, 7, video->palette[7]);
+ video->renderer->writePalette(video->renderer, 9, video->palette[9]);
+ video->renderer->writePalette(video->renderer, 10, video->palette[10]);
+ video->renderer->writePalette(video->renderer, 11, video->palette[11]);
break;
case SGB_PAL_SET:
for (i = 0; i < 4; ++i) {
@@ -686,6 +685,7 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) {
}
break;
case SGB_ATTR_BLK:
+ case SGB_ATTR_CHR:
case SGB_PAL_TRN:
case SGB_ATRC_EN:
case SGB_CHR_TRN:
@@ -786,6 +786,7 @@ void GBVideoSerialize(const struct GBVideo* video, struct GBSerializedState* sta
STORE_16LE(video->x, 0, &state->video.x);
STORE_16LE(video->ly, 0, &state->video.ly);
STORE_32LE(video->frameCounter, 0, &state->video.frameCounter);
+ STORE_32LE(video->dotClock, 0, &state->video.dotCounter);
state->video.vramCurrentBank = video->vramCurrentBank;
GBSerializedVideoFlags flags = 0;
@@ -814,6 +815,7 @@ void GBVideoDeserialize(struct GBVideo* video, const struct GBSerializedState* s
LOAD_16LE(video->x, 0, &state->video.x);
LOAD_16LE(video->ly, 0, &state->video.ly);
LOAD_32LE(video->frameCounter, 0, &state->video.frameCounter);
+ LOAD_32LE(video->dotClock, 0, &state->video.dotCounter);
video->vramCurrentBank = state->video.vramCurrentBank;
GBSerializedVideoFlags flags = state->video.flags;
View
@@ -111,7 +111,7 @@ void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA*
mLOG(GBA_AUDIO, GAME_ERROR, "Invalid FIFO destination: 0x%08X", info->dest);
return;
}
- info->reg = GBADMARegisterSetDestControl(info->reg, DMA_FIXED);
+ info->reg = GBADMARegisterSetDestControl(info->reg, GBA_DMA_FIXED);
info->reg = GBADMARegisterSetWidth(info->reg, 1);
}
@@ -235,7 +235,7 @@ void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId, int32_t cycles) {
}
if (CircleBufferSize(&channel->fifo) <= 4 * sizeof(int32_t) && channel->dmaSource > 0) {
struct GBADMA* dma = &audio->p->memory.dma[channel->dmaSource];
- if (GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_CUSTOM) {
+ if (GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_CUSTOM) {
dma->when = mTimingCurrentTime(&audio->p->timing) - cycles;
dma->nextCount = 4;
GBADMASchedule(audio->p, channel->dmaSource, dma);
@@ -260,7 +260,7 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) {
struct GBAAudio* audio = user;
int16_t sampleLeft = 0;
int16_t sampleRight = 0;
- int psgShift = 5 - audio->volume;
+ int psgShift = 4 - audio->volume;
GBAudioSamplePSG(&audio->psg, &sampleLeft, &sampleRight);
sampleLeft >>= psgShift;
sampleRight >>= psgShift;
View
@@ -333,6 +333,12 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
mLOG(GBA_BIOS, DEBUG, "SWI: %02X r0: %08X r1: %08X r2: %08X r3: %08X",
immediate, cpu->gprs[0], cpu->gprs[1], cpu->gprs[2], cpu->gprs[3]);
+ switch (immediate) {
+ case 0xFA:
+ GBAPrintFlush(gba);
+ return;
+ }
+
if (gba->memory.fullBios) {
ARMRaiseSWI(cpu);
return;
@@ -529,8 +535,10 @@ static void _unLz77(struct GBA* gba, int width) {
source += 2;
disp = dest - (block & 0x0FFF) - 1;
bytes = (block >> 12) + 3;
- while (bytes-- && remaining) {
- --remaining;
+ while (bytes--) {
+ if (remaining) {
+ --remaining;
+ }
if (width == 2) {
byte = (int16_t) cpu->memory.load16(cpu, disp & ~1, 0);
if (dest & 1) {
View
@@ -274,7 +274,11 @@ bool GBACheatAddLine(struct mCheatSet* set, const char* line, int type) {
static void GBACheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) {
struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats;
- _patchROM(device, gbaset);
+ if (cheats->enabled) {
+ _patchROM(device, gbaset);
+ } else {
+ _unpatchROM(device, gbaset);
+ }
}
static void GBACheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) {
View
@@ -154,9 +154,32 @@ bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t
cheats->romPatches[0].exists = true;
return true;
case GSA_BUTTON:
- // TODO: Implement button
- mLOG(CHEATS, STUB, "GameShark button unimplemented");
- return false;
+ switch (op1 & 0x00F00000) {
+ case 0x00100000:
+ cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_IF_BUTTON;
+ cheat->repeat = 1;
+ cheat->negativeRepeat = 0;
+ cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_ASSIGN;
+ cheat->width = 1;
+ cheat->address = op1 & 0x0F0FFFFF;
+ break;
+ case 0x00200000:
+ cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_IF_BUTTON;
+ cheat->repeat = 1;
+ cheat->negativeRepeat = 0;
+ cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_ASSIGN;
+ cheat->width = 2;
+ cheat->address = op1 & 0x0F0FFFFF;
+ break;
+ default:
+ mLOG(CHEATS, STUB, "GameShark button type unimplemented");
+ return false;
+ }
+ break;
case GSA_IF_EQ:
if (op1 == 0xDEADFACE) {
GBACheatReseedGameShark(cheats->gsaSeeds, op2, _gsa1T1, _gsa1T2);
@@ -174,6 +197,7 @@ bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t
cheat->address = op2 & 0x0FFFFFFF;
cheat->operand = op1 & 0xFFFF;
cheat->repeat = (op1 >> 16) & 0xFF;
+ cheat->negativeRepeat = 0;
return true;
case GSA_HOOK:
if (cheats->hook) {
@@ -190,6 +214,7 @@ bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t
}
cheat->operand = op2;
cheat->repeat = 1;
+ cheat->negativeRepeat = 0;
return true;
}
View
@@ -132,49 +132,65 @@ static bool _addPAR3Cond(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2)
case PAR3_COND_UGT:
cheat->type = CHEAT_IF_UGT;
break;
- case PAR3_COND_LAND:
- cheat->type = CHEAT_IF_LAND;
+ case PAR3_COND_AND:
+ cheat->type = CHEAT_IF_AND;
break;
}
return true;
}
static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) {
+ int romPatch = -1;
struct mCheat* cheat;
switch (op2 & 0xFF000000) {
case PAR3_OTHER_SLOWDOWN:
// TODO: Slowdown
+ mLOG(CHEATS, STUB, "Unimplemented PARv3 slowdown");
return false;
case PAR3_OTHER_BUTTON_1:
+ cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_IF_BUTTON;
+ cheat->repeat = 1;
+ cheat->negativeRepeat = 0;
+ cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_ASSIGN;
+ cheat->width = 1;
+ cheat->address = _parAddr(op2);
+ cheats->incompleteCheat = mCheatListIndex(&cheats->d.list, cheat);
+ break;
case PAR3_OTHER_BUTTON_2:
+ cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_IF_BUTTON;
+ cheat->repeat = 1;
+ cheat->negativeRepeat = 0;
+ cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_ASSIGN;
+ cheat->width = 2;
+ cheat->address = _parAddr(op2);
+ cheats->incompleteCheat = mCheatListIndex(&cheats->d.list, cheat);
+ break;
case PAR3_OTHER_BUTTON_4:
- // TODO: Button
- mLOG(CHEATS, STUB, "GameShark button unimplemented");
- return false;
- // TODO: Fix overriding existing patches
+ cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_IF_BUTTON;
+ cheat->repeat = 1;
+ cheat->negativeRepeat = 0;
+ cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_ASSIGN;
+ cheat->width = 4;
+ cheat->address = _parAddr(op2);
+ cheats->incompleteCheat = mCheatListIndex(&cheats->d.list, cheat);
+ break;
case PAR3_OTHER_PATCH_1:
- cheats->romPatches[0].address = BASE_CART0 | ((op2 & 0xFFFFFF) << 1);
- cheats->romPatches[0].applied = false;
- cheats->romPatches[0].exists = true;
- cheats->incompletePatch = &cheats->romPatches[0];
+ romPatch = 0;
break;
case PAR3_OTHER_PATCH_2:
- cheats->romPatches[1].address = BASE_CART0 | ((op2 & 0xFFFFFF) << 1);
- cheats->romPatches[1].applied = false;
- cheats->romPatches[1].exists = true;
- cheats->incompletePatch = &cheats->romPatches[1];
+ romPatch = 1;
break;
case PAR3_OTHER_PATCH_3:
- cheats->romPatches[2].address = BASE_CART0 | ((op2 & 0xFFFFFF) << 1);
- cheats->romPatches[2].applied = false;
- cheats->romPatches[2].exists = true;
- cheats->incompletePatch = &cheats->romPatches[2];
+ romPatch = 2;
break;
case PAR3_OTHER_PATCH_4:
- cheats->romPatches[3].address = BASE_CART0 | ((op2 & 0xFFFFFF) << 1);
- cheats->romPatches[3].applied = false;
- cheats->romPatches[3].exists = true;
- cheats->incompletePatch = &cheats->romPatches[3];
+ romPatch = 3;
break;
case PAR3_OTHER_ENDIF:
if (cheats->currentBlock != COMPLETE) {
@@ -190,23 +206,38 @@ static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) {
return false;
case PAR3_OTHER_FILL_1:
cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_ASSIGN;
cheat->address = _parAddr(op2);
cheat->width = 1;
cheats->incompleteCheat = mCheatListIndex(&cheats->d.list, cheat);
break;
case PAR3_OTHER_FILL_2:
cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_ASSIGN;
cheat->address = _parAddr(op2);
cheat->width = 2;
cheats->incompleteCheat = mCheatListIndex(&cheats->d.list, cheat);
break;
case PAR3_OTHER_FILL_4:
cheat = mCheatListAppend(&cheats->d.list);
+ cheat->type = CHEAT_ASSIGN;
cheat->address = _parAddr(op2);
- cheat->width = 3;
+ cheat->width = 4;
cheats->incompleteCheat = mCheatListIndex(&cheats->d.list, cheat);
break;
}
+ if (romPatch >= 0) {
+ while (cheats->romPatches[romPatch].exists) {
+ ++romPatch;
+ if (romPatch >= MAX_ROM_PATCHES) {
+ break;
+ }
+ }
+ cheats->romPatches[romPatch].address = BASE_CART0 | ((op2 & 0xFFFFFF) << 1);
+ cheats->romPatches[romPatch].applied = false;
+ cheats->romPatches[romPatch].exists = true;
+ cheats->incompletePatch = &cheats->romPatches[romPatch];
+ }
return true;
}
@@ -219,7 +250,14 @@ bool GBACheatAddProActionReplayRaw(struct GBACheatSet* cheats, uint32_t op1, uin
if (cheats->incompleteCheat != COMPLETE) {
struct mCheat* incompleteCheat = mCheatListGetPointer(&cheats->d.list, cheats->incompleteCheat);
incompleteCheat->operand = op1 & (0xFFFFFFFFU >> ((4 - incompleteCheat->width) * 8));
- incompleteCheat->addressOffset = op2 >> 24;
+ if (cheats->incompleteCheat > 0) {
+ struct mCheat* lastCheat = mCheatListGetPointer(&cheats->d.list, cheats->incompleteCheat - 1);
+ if (lastCheat->type == CHEAT_IF_BUTTON) {
+ cheats->incompleteCheat = COMPLETE;
+ return true;
+ }
+ }
+ incompleteCheat->operandOffset = op2 >> 24;
incompleteCheat->repeat = (op2 >> 16) & 0xFF;
incompleteCheat->addressOffset = (op2 & 0xFFFF) * incompleteCheat->width;
cheats->incompleteCheat = COMPLETE;
@@ -339,7 +377,7 @@ int GBACheatProActionReplayProbability(uint32_t op1, uint32_t op2) {
return 0x100;
}
if (!op1) {
- probability += 0x20;
+ probability += 0x40;
uint32_t address = _parAddr(op2);
switch (op2 & 0xFE000000) {
case PAR3_OTHER_FILL_1:
@@ -360,8 +398,8 @@ int GBACheatProActionReplayProbability(uint32_t op1, uint32_t op2) {
case PAR3_OTHER_BUTTON_4:
case PAR3_OTHER_ENDIF:
case PAR3_OTHER_ELSE:
- if (op2 & 0x01FFFFFF) {
- probability -= 0x20;
+ if (op2 & 0x01000000) {
+ probability -= 0x40;
}
break;
default:
View
@@ -746,6 +746,20 @@ static void _GBACoreLoadSymbols(struct mCore* core, struct VFile* vf) {
}
#endif
}
+
+static bool _GBACoreLookupIdentifier(struct mCore* core, const char* name, int32_t* value, int* segment) {
+ UNUSED(core);
+ *segment = -1;
+ int i;
+ for (i = 0; i < REG_MAX; i += 2) {
+ const char* reg = GBAIORegisterNames[i >> 1];
+ if (reg && strcasecmp(reg, name) == 0) {
+ *value = BASE_IO | i;
+ return true;
+ }
+ }
+ return false;
+}
#endif
static struct mCheatDevice* _GBACoreCheatDevice(struct mCore* core) {
@@ -847,6 +861,7 @@ static void _GBACoreEnableAudioChannel(struct mCore* core, size_t id, bool enabl
}
}
+#ifndef MINIMAL_CORE
static void _GBACoreStartVideoLog(struct mCore* core, struct mVideoLogContext* context) {
struct GBACore* gbacore = (struct GBACore*) core;
struct GBA* gba = core->board;
@@ -873,6 +888,7 @@ static void _GBACoreEndVideoLog(struct mCore* core) {
free(gbacore->proxyRenderer.logger);
gbacore->proxyRenderer.logger = NULL;
}
+#endif
struct mCore* GBACoreCreate(void) {
struct GBACore* gbacore = malloc(sizeof(*gbacore));
@@ -943,6 +959,7 @@ struct mCore* GBACoreCreate(void) {
core->attachDebugger = _GBACoreAttachDebugger;
core->detachDebugger = _GBACoreDetachDebugger;
core->loadSymbols = _GBACoreLoadSymbols;
+ core->lookupIdentifier = _GBACoreLookupIdentifier;
#endif
core->cheatDevice = _GBACoreCheatDevice;
core->savedataClone = _GBACoreSavedataClone;
View
@@ -14,16 +14,15 @@
static void _GBACLIDebuggerInit(struct CLIDebuggerSystem*);
static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem*);
-static uint32_t _GBACLIDebuggerLookupIdentifier(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv);
static void _frame(struct CLIDebugger*, struct CLIDebugVector*);
static void _load(struct CLIDebugger*, struct CLIDebugVector*);
static void _save(struct CLIDebugger*, struct CLIDebugVector*);
struct CLIDebuggerCommandSummary _GBACLIDebuggerCommands[] = {
- { "frame", _frame, 0, "Frame advance" },
- { "load", _load, CLIDVParse, "Load a savestate" },
- { "save", _save, CLIDVParse, "Save a savestate" },
+ { "frame", _frame, "", "Frame advance" },
+ { "load", _load, "*", "Load a savestate" },
+ { "save", _save, "*", "Save a savestate" },
{ 0, 0, 0, 0 }
};
@@ -33,7 +32,6 @@ struct GBACLIDebugger* GBACLIDebuggerCreate(struct mCore* core) {
debugger->d.init = _GBACLIDebuggerInit;
debugger->d.deinit = NULL;
debugger->d.custom = _GBACLIDebuggerCustom;
- debugger->d.lookupIdentifier = _GBACLIDebuggerLookupIdentifier;
debugger->d.name = "Game Boy Advance";
debugger->d.commands = _GBACLIDebuggerCommands;
@@ -64,19 +62,6 @@ static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
return false;
}
-static uint32_t _GBACLIDebuggerLookupIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
- UNUSED(debugger);
- int i;
- for (i = 0; i < REG_MAX; i += 2) {
- const char* reg = GBAIORegisterNames[i >> 1];
- if (reg && strcasecmp(reg, name) == 0) {
- return BASE_IO | i;
- }
- }
- dv->type = CLIDV_ERROR_TYPE;
- return 0;
-}
-
static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
debugger->d.state = DEBUGGER_CUSTOM;
View
@@ -46,6 +46,8 @@ uint32_t GBADMAWriteSAD(struct GBA* gba, int dma, uint32_t address) {
address &= 0x0FFFFFFE;
if (_isValidDMASAD(dma, address)) {
memory->dma[dma].source = address;
+ } else {
+ memory->dma[dma].source = 0;
}
return memory->dma[dma].source;
}
@@ -81,7 +83,19 @@ uint16_t GBADMAWriteCNT_HI(struct GBA* gba, int dma, uint16_t control) {
if (!wasEnabled && GBADMARegisterIsEnable(currentDma->reg)) {
currentDma->nextSource = currentDma->source;
+ if (currentDma->nextSource >= BASE_CART0 && currentDma->nextSource < BASE_CART_SRAM && GBADMARegisterGetSrcControl(currentDma->reg) < 3) {
+ currentDma->reg = GBADMARegisterClearSrcControl(currentDma->reg);
+ }
currentDma->nextDest = currentDma->dest;
+
+ uint32_t width = 2 << GBADMARegisterGetWidth(currentDma->reg);
+ if (currentDma->nextSource & (width - 1)) {
+ mLOG(GBA_MEM, GAME_ERROR, "Misaligned DMA source address: 0x%08X", currentDma->nextSource);
+ }
+ if (currentDma->nextDest & (width - 1)) {
+ mLOG(GBA_MEM, GAME_ERROR, "Misaligned DMA destination address: 0x%08X", currentDma->nextDest);
+ }
+
GBADMASchedule(gba, dma, currentDma);
}
// If the DMA has already occurred, this value might have changed since the function started
@@ -90,15 +104,15 @@ uint16_t GBADMAWriteCNT_HI(struct GBA* gba, int dma, uint16_t control) {
void GBADMASchedule(struct GBA* gba, int number, struct GBADMA* info) {
switch (GBADMARegisterGetTiming(info->reg)) {
- case DMA_TIMING_NOW:
+ case GBA_DMA_TIMING_NOW:
info->when = mTimingCurrentTime(&gba->timing) + 3; // DMAs take 3 cycles to start
info->nextCount = info->count;
break;
- case DMA_TIMING_HBLANK:
- case DMA_TIMING_VBLANK:
+ case GBA_DMA_TIMING_HBLANK:
+ case GBA_DMA_TIMING_VBLANK:
// Handled implicitly
return;
- case DMA_TIMING_CUSTOM:
+ case GBA_DMA_TIMING_CUSTOM:
switch (number) {
case 0:
mLOG(GBA_MEM, WARN, "Discarding invalid DMA0 scheduling");
@@ -108,7 +122,7 @@ void GBADMASchedule(struct GBA* gba, int number, struct GBADMA* info) {
GBAAudioScheduleFifoDma(&gba->audio, number, info);
break;
case 3:
- // GBAVideoScheduleVCaptureDma(dma, info);
+ // Handled implicitly
break;
}
}
@@ -121,7 +135,7 @@ void GBADMARunHblank(struct GBA* gba, int32_t cycles) {
int i;
for (i = 0; i < 4; ++i) {
dma = &memory->dma[i];
- if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_HBLANK && !dma->nextCount) {
+ if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_HBLANK && !dma->nextCount) {
dma->when = mTimingCurrentTime(&gba->timing) + 3 + cycles;
dma->nextCount = dma->count;
}
@@ -135,14 +149,24 @@ void GBADMARunVblank(struct GBA* gba, int32_t cycles) {
int i;
for (i = 0; i < 4; ++i) {
dma = &memory->dma[i];
- if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_VBLANK && !dma->nextCount) {
+ if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_VBLANK && !dma->nextCount) {
dma->when = mTimingCurrentTime(&gba->timing) + 3 + cycles;
dma->nextCount = dma->count;
}
}
GBADMAUpdate(gba);
}
+void GBADMARunDisplayStart(struct GBA* gba, int32_t cycles) {
+ struct GBAMemory* memory = &gba->memory;
+ struct GBADMA* dma = &memory->dma[3];
+ if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_CUSTOM && !dma->nextCount) {
+ dma->when = mTimingCurrentTime(&gba->timing) + 3 + cycles;
+ dma->nextCount = dma->count;
+ GBADMAUpdate(gba);
+ }
+}
+
void _dmaEvent(struct mTiming* timing, void* context, uint32_t cyclesLate) {
UNUSED(timing);
UNUSED(cyclesLate);
@@ -156,13 +180,16 @@ void _dmaEvent(struct mTiming* timing, void* context, uint32_t cyclesLate) {
GBADMAService(gba, memory->activeDMA, dma);
} else {
dma->nextCount = 0;
- if (!GBADMARegisterIsRepeat(dma->reg) || GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_NOW) {
+ bool noRepeat = !GBADMARegisterIsRepeat(dma->reg);
+ noRepeat |= GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_NOW;
+ noRepeat |= memory->activeDMA == 3 && GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_CUSTOM;
+ if (noRepeat) {
dma->reg = GBADMARegisterClearEnable(dma->reg);
// Clear the enable bit in memory
memory->io[(REG_DMA0CNT_HI + memory->activeDMA * (REG_DMA1CNT_HI - REG_DMA0CNT_HI)) >> 1] &= 0x7FE0;
}
- if (GBADMARegisterGetDestControl(dma->reg) == DMA_INCREMENT_RELOAD) {
+ if (GBADMARegisterGetDestControl(dma->reg) == GBA_DMA_INCREMENT_RELOAD) {
dma->nextDest = dma->dest;
}
if (GBADMARegisterIsDoIRQ(dma->reg)) {
@@ -226,31 +253,44 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) {
info->when += cycles;
gba->performingDMA = 1 | (number << 1);
- uint32_t word;
if (width == 4) {
- word = cpu->memory.load32(cpu, source, 0);
- gba->bus = word;
- cpu->memory.store32(cpu, dest, word, 0);
+ if (source) {
+ memory->dmaTransferRegister = cpu->memory.load32(cpu, source, 0);
+ }
+ gba->bus = memory->dmaTransferRegister;
+ cpu->memory.store32(cpu, dest, memory->dmaTransferRegister, 0);
+ memory->dmaTransferRegister &= 0xFFFF0000;
+ memory->dmaTransferRegister |= memory->dmaTransferRegister >> 16;
} else {
if (sourceRegion == REGION_CART2_EX && memory->savedata.type == SAVEDATA_EEPROM) {
- word = GBASavedataReadEEPROM(&memory->savedata);
- cpu->memory.store16(cpu, dest, word, 0);
- } else if (destRegion == REGION_CART2_EX) {
if (memory->savedata.type == SAVEDATA_AUTODETECT) {
mLOG(GBA_MEM, INFO, "Detected EEPROM savegame");
GBASavedataInitEEPROM(&memory->savedata, gba->realisticTiming);
}
- word = cpu->memory.load16(cpu, source, 0);
- GBASavedataWriteEEPROM(&memory->savedata, word, wordsRemaining);
+ memory->dmaTransferRegister = GBASavedataReadEEPROM(&memory->savedata);
+ } else {
+ if (source) {
+ memory->dmaTransferRegister = cpu->memory.load16(cpu, source, 0);
+ }
+ }
+ if (destRegion == REGION_CART2_EX) {
+ if (memory->savedata.type == SAVEDATA_AUTODETECT) {
+ mLOG(GBA_MEM, INFO, "Detected EEPROM savegame");
+ GBASavedataInitEEPROM(&memory->savedata, gba->realisticTiming);
+ }
+ GBASavedataWriteEEPROM(&memory->savedata, memory->dmaTransferRegister, wordsRemaining);
} else {
- word = cpu->memory.load16(cpu, source, 0);
- cpu->memory.store16(cpu, dest, word, 0);
+ cpu->memory.store16(cpu, dest, memory->dmaTransferRegister, 0);
+
}
- gba->bus = word | (word << 16);
+ memory->dmaTransferRegister |= memory->dmaTransferRegister << 16;
+ gba->bus = memory->dmaTransferRegister;
}
int sourceOffset = DMA_OFFSET[GBADMARegisterGetSrcControl(info->reg)] * width;
int destOffset = DMA_OFFSET[GBADMARegisterGetDestControl(info->reg)] * width;
- source += sourceOffset;
+ if (source) {
+ source += sourceOffset;
+ }
dest += destOffset;
--wordsRemaining;
gba->performingDMA = 0;
View
@@ -189,11 +189,16 @@ static uint16_t* _vramBlock(struct mVideoLogger* logger, uint32_t address) {
uint16_t GBAVideoProxyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
switch (address) {
+ case REG_DISPCNT:
+ value &= 0xFFF7;
+ break;
case REG_BG0CNT:
case REG_BG1CNT:
+ value &= 0xDFFF;
+ break;
case REG_BG2CNT:
case REG_BG3CNT:
- value &= 0xFFCF;
+ value &= 0xFFFF;
break;
case REG_BG0HOFS:
case REG_BG0VOFS:
View
@@ -125,7 +125,9 @@ void GBAUnloadROM(struct GBA* gba) {
if (gba->romVf) {
#ifndef FIXED_ROM_BUFFER
- gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize);
+ if (gba->isPristine) {
+ gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize);
+ }
#endif
gba->romVf->close(gba->romVf);
gba->romVf = NULL;
@@ -207,6 +209,9 @@ void GBAReset(struct ARMCore* cpu) {
gba->debug = false;
memset(gba->debugString, 0, sizeof(gba->debugString));
+ if (gba->pristineRomSize > SIZE_CART0) {
+ GBAMatrixReset(gba);
+ }
if (!gba->romVf && gba->memory.rom) {
GBASkipBIOS(gba);
@@ -243,19 +248,17 @@ static void GBAProcessEvents(struct ARMCore* cpu) {
int32_t nextEvent = cpu->nextEvent;
while (cpu->cycles >= nextEvent) {
- int32_t cycles = cpu->cycles;
-
- cpu->cycles = 0;
cpu->nextEvent = INT_MAX;
-
+ nextEvent = 0;
+ do {
+ int32_t cycles = cpu->cycles;
+ cpu->cycles = 0;
#ifndef NDEBUG
- if (cycles < 0) {
- mLOG(GBA, FATAL, "Negative cycles passed: %i", cycles);
- }
+ if (cycles < 0) {
+ mLOG(GBA, FATAL, "Negative cycles passed: %i", cycles);
+ }
#endif
- nextEvent = cycles;
- do {
- nextEvent = mTimingTick(&gba->timing, nextEvent);
+ nextEvent = mTimingTick(&gba->timing, nextEvent + cycles);
} while (gba->cpuBlocked);
cpu->nextEvent = nextEvent;
@@ -276,6 +279,11 @@ static void GBAProcessEvents(struct ARMCore* cpu) {
}
#endif
}
+#ifndef NDEBUG
+ if (gba->cpuBlocked) {
+ mLOG(GBA, FATAL, "CPU is blocked!");
+ }
+#endif
}
#ifdef USE_DEBUGGERS
@@ -300,7 +308,6 @@ bool GBALoadNull(struct GBA* gba) {
GBAUnloadROM(gba);
gba->romVf = NULL;
gba->pristineRomSize = 0;
- gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM);
#ifndef FIXED_ROM_BUFFER
gba->memory.rom = anonymousMemoryMap(SIZE_CART0);
#else
@@ -328,7 +335,6 @@ bool GBALoadMB(struct GBA* gba, struct VFile* vf) {
gba->pristineRomSize = SIZE_WORKING_RAM;
}
gba->isPristine = true;
- gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM);
memset(gba->memory.wram, 0, SIZE_WORKING_RAM);
vf->read(vf, gba->memory.wram, gba->pristineRomSize);
if (!gba->memory.wram) {
@@ -354,23 +360,30 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) {
gba->pristineRomSize = vf->size(vf);
vf->seek(vf, 0, SEEK_SET);
if (gba->pristineRomSize > SIZE_CART0) {
- gba->pristineRomSize = SIZE_CART0;
- }
- gba->isPristine = true;
+ gba->isPristine = false;
+ gba->memory.romSize = 0x01000000;
#ifdef FIXED_ROM_BUFFER
- if (gba->pristineRomSize <= romBufferSize) {
gba->memory.rom = romBuffer;
- vf->read(vf, romBuffer, gba->pristineRomSize);
- }
#else
- gba->memory.rom = vf->map(vf, gba->pristineRomSize, MAP_READ);
+ gba->memory.rom = anonymousMemoryMap(SIZE_CART0);
+#endif
+ } else {
+ gba->isPristine = true;
+#ifdef FIXED_ROM_BUFFER
+ if (gba->pristineRomSize <= romBufferSize) {
+ gba->memory.rom = romBuffer;
+ vf->read(vf, romBuffer, gba->pristineRomSize);
+ }
+#else
+ gba->memory.rom = vf->map(vf, gba->pristineRomSize, MAP_READ);
#endif
+ gba->memory.romSize = gba->pristineRomSize;
+ }
if (!gba->memory.rom) {
mLOG(GBA, WARN, "Couldn't map ROM");
return false;
}
gba->yankedRomSize = 0;
- gba->memory.romSize = gba->pristineRomSize;
gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
gba->memory.mirroring = false;
gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
@@ -568,16 +581,49 @@ bool GBAIsMB(struct VFile* vf) {
LOAD_32(opcode, 0, &signature);
struct ARMInstructionInfo info;
ARMDecodeARM(opcode, &info);
- if (info.branchType != ARM_BRANCH) {
- return false;
+ if (info.branchType == ARM_BRANCH) {
+ if (info.op1.immediate <= 0) {
+ return false;
+ } else if (info.op1.immediate == 28) {
+ // Ancient toolchain that is known to throw MB detection for a loop
+ return false;
+ } else if (info.op1.immediate != 24) {
+ return true;
+ }
}
- if (info.op1.immediate <= 0) {
- return false;
- } else if (info.op1.immediate == 28) {
- // Ancient toolchain that is known to throw MB detection for a loop
- return false;
- } else if (info.op1.immediate != 24) {
- return true;
+
+ uint32_t pc = GBA_MB_MAGIC_OFFSET;
+ int i;
+ for (i = 0; i < 80; ++i) {
+ if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) {
+ break;
+ }
+ pc += 4;
+ LOAD_32(opcode, 0, &signature);
+ ARMDecodeARM(opcode, &info);
+ if (info.mnemonic != ARM_MN_LDR) {
+ continue;
+ }
+ if ((info.operandFormat & ARM_OPERAND_MEMORY) && info.memory.baseReg == ARM_PC && info.memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
+ uint32_t immediate = info.memory.offset.immediate;
+ if (info.memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
+ immediate = -immediate;
+ }
+ immediate += pc + 8;
+ if (vf->seek(vf, immediate, SEEK_SET) < 0) {
+ break;
+ }
+ if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) {
+ break;
+ }
+ LOAD_32(immediate, 0, &signature);
+ if (vf->seek(vf, pc, SEEK_SET) < 0) {
+ break;
+ }
+ if ((immediate & ~0x7FF) == BASE_WORKING_RAM) {
+ return true;
+ }
+ }
}
// Found a libgba-linked cart...these are a bit harder to detect.
return false;
@@ -628,7 +674,7 @@ void GBAHitStub(struct ARMCore* cpu, uint32_t opcode) {
if (gba->debugger) {
struct mDebuggerEntryInfo info = {
.address = _ARMPCAddress(cpu),
- .opcode = opcode
+ .type.bp.opcode = opcode
};
mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
}
@@ -651,7 +697,7 @@ void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) {
if (gba->debugger) {
struct mDebuggerEntryInfo info = {
.address = _ARMPCAddress(cpu),
- .opcode = opcode
+ .type.bp.opcode = opcode
};
mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
} else
@@ -672,7 +718,7 @@ void GBABreakpoint(struct ARMCore* cpu, int immediate) {
if (gba->debugger) {
struct mDebuggerEntryInfo info = {
.address = _ARMPCAddress(cpu),
- .breakType = BREAKPOINT_SOFTWARE
+ .type.bp.breakType = BREAKPOINT_SOFTWARE
};
mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_BREAKPOINT, &info);
}
View
@@ -939,6 +939,8 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
STORE_32(gba->memory.dma[i].when, 0, &state->dma[i].when);
}
+ state->dmaTransferRegister = gba->memory.dmaTransferRegister;
+
GBAHardwareSerialize(&gba->memory.hw, state);
}
@@ -979,11 +981,12 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
LOAD_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest);
LOAD_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount);
LOAD_32(gba->memory.dma[i].when, 0, &state->dma[i].when);
- if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) {
+ if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != GBA_DMA_TIMING_NOW) {
GBADMASchedule(gba, i, &gba->memory.dma[i]);
}
}
GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[REG_SOUNDCNT_X >> 1]);
+ gba->memory.dmaTransferRegister = state->dmaTransferRegister;
GBADMAUpdate(gba);
GBAHardwareDeserialize(&gba->memory.hw, state);
}
View
@@ -0,0 +1,75 @@
+/* Copyright (c) 2013-2018 Jeffrey Pfau
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include <mgba/internal/gba/matrix.h>
+
+#include <mgba/internal/arm/macros.h>
+#include <mgba/internal/gba/gba.h>
+#include <mgba/internal/gba/memory.h>
+#include <mgba-util/vfs.h>
+
+static void _remapMatrix(struct GBA* gba) {
+ gba->romVf->seek(gba->romVf, gba->memory.matrix.paddr, SEEK_SET);
+ gba->romVf->read(gba->romVf, &gba->memory.rom[gba->memory.matrix.vaddr >> 2], gba->memory.matrix.size);
+}
+
+void GBAMatrixReset(struct GBA* gba) {
+ gba->memory.matrix.paddr = 0x200;
+ gba->memory.matrix.size = 0x1000;
+
+ gba->memory.matrix.vaddr = 0;
+ _remapMatrix(gba);
+ gba->memory.matrix.vaddr = 0x1000;
+ _remapMatrix(gba);
+
+ gba->memory.matrix.paddr = 0;
+ gba->memory.matrix.vaddr = 0;
+ gba->memory.matrix.size = 0x100;
+ _remapMatrix(gba);
+}
+
+void GBAMatrixWrite(struct GBA* gba, uint32_t address, uint32_t value) {
+ switch (address) {
+ case 0x0:
+ gba->memory.matrix.cmd = value;
+ switch (value) {
+ case 0x01:
+ case 0x11:
+ _remapMatrix(gba);
+ break;
+ default:
+ mLOG(GBA_MEM, STUB, "Unknown Matrix command: %08X", value);
+ break;
+ }
+ return;
+ case 0x4:
+ gba->memory.matrix.paddr = value & 0x03FFFFFF;
+ return;
+ case 0x8:
+ gba->memory.matrix.vaddr = value & 0x007FFFFF;
+ return;
+ case 0xC:
+ gba->memory.matrix.size = value << 9;
+ return;
+ }
+ mLOG(GBA_MEM, STUB, "Unknown Matrix write: %08X:%04X", address, value);
+}
+
+void GBAMatrixWrite16(struct GBA* gba, uint32_t address, uint16_t value) {
+ switch (address) {
+ case 0x0:
+ GBAMatrixWrite(gba, address, value | (gba->memory.matrix.cmd & 0xFFFF0000));
+ break;
+ case 0x4:
+ GBAMatrixWrite(gba, address, value | (gba->memory.matrix.paddr & 0xFFFF0000));
+ break;
+ case 0x8:
+ GBAMatrixWrite(gba, address, value | (gba->memory.matrix.vaddr & 0xFFFF0000));
+ break;
+ case 0xC:
+ GBAMatrixWrite(gba, address, value | (gba->memory.matrix.size & 0xFFFF0000));
+ break;
+ }
+}
View
@@ -22,7 +22,10 @@
mLOG_DEFINE_CATEGORY(GBA_MEM, "GBA Memory", "gba.memory");
static void _pristineCow(struct GBA* gba);
-static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb
+static void _agbPrintStore(struct GBA* gba, uint32_t address, int16_t value);
+static int16_t _agbPrintLoad(struct GBA* gba, uint32_t address);
+static uint8_t _deadbeef[4] = { 0x10, 0xB7, 0x10, 0xE7 }; // Illegal instruction on both ARM and Thumb
+static uint8_t _agbPrintFunc[4] = { 0xFA, 0xDF /* swi 0xFF */, 0x70, 0x47 /* bx lr */ };
static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t region);
static int32_t GBAMemoryStall(struct ARMCore* cpu, int32_t wait);
@@ -80,15 +83,19 @@ void GBAMemoryInit(struct GBA* gba) {
gba->memory.biosPrefetch = 0;
gba->memory.mirroring = false;
- gba->memory.iwram = anonymousMemoryMap(SIZE_WORKING_IRAM);
+ gba->memory.agbPrint = 0;
+ memset(&gba->memory.agbPrintCtx, 0, sizeof(gba->memory.agbPrintCtx));
+ gba->memory.agbPrintBuffer = NULL;
+
+ gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM + SIZE_WORKING_IRAM);
+ gba->memory.iwram = &gba->memory.wram[SIZE_WORKING_RAM >> 2];
GBADMAInit(gba);
GBAVFameInit(&gba->memory.vfame);
}
void GBAMemoryDeinit(struct GBA* gba) {
- mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM);
- mappedMemoryFree(gba->memory.iwram, SIZE_WORKING_IRAM);
+ mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM + SIZE_WORKING_IRAM);
if (gba->memory.rom) {
mappedMemoryFree(gba->memory.rom, gba->memory.romSize);
}
@@ -98,15 +105,15 @@ void GBAMemoryDeinit(struct GBA* gba) {
if (gba->memory.savedata.realVf) {
gba->memory.savedata.realVf->close(gba->memory.savedata.realVf);
}
+
+ if (gba->memory.agbPrintBuffer) {
+ mappedMemoryFree(gba->memory.agbPrintBuffer, SIZE_AGB_PRINT);
+ }
}
void GBAMemoryReset(struct GBA* gba) {
- if (gba->memory.rom || gba->memory.fullBios || !gba->memory.wram) {
- // Not multiboot
- if (gba->memory.wram) {
- mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM);
- }
- gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM);
+ if (gba->memory.wram && gba->memory.rom) {
+ memset(gba->memory.wram, 0, SIZE_WORKING_RAM);
}
if (gba->memory.iwram) {
@@ -115,6 +122,12 @@ void GBAMemoryReset(struct GBA* gba) {
memset(gba->memory.io, 0, sizeof(gba->memory.io));
+ gba->memory.agbPrint = 0;
+ memset(&gba->memory.agbPrintCtx, 0, sizeof(gba->memory.agbPrintCtx));
+ if (gba->memory.agbPrintBuffer) {
+ gba->memory.agbPrintBuffer = NULL;
+ }
+
gba->memory.prefetch = false;
gba->memory.lastPrefetchedPc = 0;
@@ -124,6 +137,7 @@ void GBAMemoryReset(struct GBA* gba) {
}
GBADMAReset(gba);
+ memset(&gba->memory.matrix, 0, sizeof(gba->memory.matrix));
}
static void _analyzeForIdleLoop(struct GBA* gba, struct ARMCore* cpu, uint32_t address) {
@@ -294,10 +308,15 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
if ((address & (SIZE_CART0 - 1)) < memory->romSize) {
break;
}
+ if ((address & (SIZE_CART0 - 1)) == AGB_PRINT_FLUSH_ADDR && memory->agbPrint == 0x20) {
+ cpu->memory.activeRegion = (uint32_t*) _agbPrintFunc;
+ cpu->memory.activeMask = sizeof(_agbPrintFunc) - 1;
+ break;
+ }
// Fall through
default:
memory->activeRegion = -1;
- cpu->memory.activeRegion = _deadbeef;
+ cpu->memory.activeRegion = (uint32_t*) _deadbeef;
cpu->memory.activeMask = 0;
if (!gba->yankedRomSize && mCoreCallbacksListSize(&gba->coreCallbacks)) {
@@ -527,6 +546,16 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
LOAD_16(value, address & memory->romMask, memory->rom);
} else if (memory->vfame.cartType) {
value = GBAVFameGetPatternValue(address, 16);
+ } else if ((address & (SIZE_CART0 - 1)) >= AGB_PRINT_BASE) {
+ uint32_t agbPrintAddr = address & 0x00FFFFFF;
+ if (agbPrintAddr == AGB_PRINT_PROTECT) {
+ value = memory->agbPrint;
+ } else if (agbPrintAddr < AGB_PRINT_TOP || (agbPrintAddr & 0x00FFFFF8) == (AGB_PRINT_STRUCT & 0x00FFFFF8)) {
+ value = _agbPrintLoad(gba, address);
+ } else {
+ mLOG(GBA_MEM, GAME_ERROR, "Out of bounds ROM Load16: 0x%08X", address);
+ value = (address >> 1) & 0xFFFF;
+ }
} else {
mLOG(GBA_MEM, GAME_ERROR, "Out of bounds ROM Load16: 0x%08X", address);
value = (address >> 1) & 0xFFFF;
@@ -720,6 +749,10 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
#define STORE_CART \
wait += waitstatesRegion[address >> BASE_OFFSET]; \
+ if (memory->matrix.size && (address & 0x01FFFF00) == 0x00800100) { \
+ GBAMatrixWrite(gba, address & 0x3C, value); \
+ break; \
+ } \
mLOG(GBA_MEM, STUB, "Unimplemented memory Store32: 0x%08X", address);
#define STORE_SRAM \
@@ -837,9 +870,27 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
if (memory->hw.devices != HW_NONE && IS_GPIO_REGISTER(address & 0xFFFFFE)) {
uint32_t reg = address & 0xFFFFFE;
GBAHardwareGPIOWrite(&memory->hw, reg, value);
- } else {
- mLOG(GBA_MEM, GAME_ERROR, "Bad cartridge Store16: 0x%08X", address);
+ break;
+ }
+ if (memory->matrix.size && (address & 0x01FFFF00) == 0x00800100) {
+ GBAMatrixWrite16(gba, address & 0x3C, value);
+ break;
}
+ // Fall through
+ case REGION_CART0_EX:
+ if ((address & 0x00FFFFFF) >= AGB_PRINT_BASE) {
+ uint32_t agbPrintAddr = address & 0x00FFFFFF;
+ if (agbPrintAddr == AGB_PRINT_PROTECT) {
+ memory->agbPrint = value;
+ _agbPrintStore(gba, address, value);
+ break;
+ }
+ if (memory->agbPrint == 0x20 && (agbPrintAddr < AGB_PRINT_TOP || (agbPrintAddr & 0x00FFFFF8) == (AGB_PRINT_STRUCT & 0x00FFFFF8))) {
+ _agbPrintStore(gba, address, value);
+ break;
+ }
+ }
+ mLOG(GBA_MEM, GAME_ERROR, "Bad cartridge Store16: 0x%08X", address);
break;
case REGION_CART2_EX:
if (memory->savedata.type == SAVEDATA_AUTODETECT) {
@@ -1531,24 +1582,23 @@ int32_t GBAMemoryStall(struct ARMCore* cpu, int32_t wait) {
int32_t previousLoads = 0;
// Don't prefetch too much if we're overlapping with a previous prefetch
- uint32_t dist = (memory->lastPrefetchedPc - cpu->gprs[ARM_PC]) >> 1;
- if (dist < 8) {
- previousLoads = dist;
+ uint32_t dist = (memory->lastPrefetchedPc - cpu->gprs[ARM_PC]);
+ int32_t maxLoads = 8;
+ if (dist < 16) {
+ previousLoads = dist >> 1;
+ maxLoads -= previousLoads;
}
- int32_t s = cpu->memory.activeSeqCycles16;
- int32_t n2s = cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16;
+ int32_t s = cpu->memory.activeSeqCycles16 + 1;
+ int32_t n2s = cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16 + 1;
// Figure out how many sequential loads we can jam in
int32_t stall = s;
int32_t loads = 1;
- if (stall < wait) {
- int32_t maxLoads = 8 - previousLoads;
- while (stall < wait && loads < maxLoads) {
- stall += s;
- ++loads;
- }
+ while (stall < wait && loads < maxLoads) {
+ stall += s;
+ ++loads;
}
if (stall > wait) {
// The wait cannot take less time than the prefetch stalls
@@ -1561,7 +1611,7 @@ int32_t GBAMemoryStall(struct ARMCore* cpu, int32_t wait) {
memory->lastPrefetchedPc = cpu->gprs[ARM_PC] + WORD_SIZE_THUMB * (loads + previousLoads - 1);
// The next |loads|S waitstates disappear entirely, so long as they're all in a row
- cpu->cycles -= stall;
+ cpu->cycles -= (s - 1) * loads;
return wait;
}
@@ -1579,19 +1629,71 @@ void _pristineCow(struct GBA* gba) {
if (!gba->isPristine) {
return;
}
+#ifndef FIXED_ROM_BUFFER
void* newRom = anonymousMemoryMap(SIZE_CART0);
memcpy(newRom, gba->memory.rom, gba->memory.romSize);
memset(((uint8_t*) newRom) + gba->memory.romSize, 0xFF, SIZE_CART0 - gba->memory.romSize);
if (gba->cpu->memory.activeRegion == gba->memory.rom) {
gba->cpu->memory.activeRegion = newRom;
}
if (gba->romVf) {
-#ifndef FIXED_ROM_BUFFER
gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->memory.romSize);
-#endif
gba->romVf->close(gba->romVf);
gba->romVf = NULL;
}
gba->memory.rom = newRom;
gba->memory.hw.gpioBase = &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1];
+#endif
+ gba->isPristine = false;
+}
+
+void GBAPrintFlush(struct GBA* gba) {
+ char oolBuf[0x101];
+ size_t i;
+ for (i = 0; gba->memory.agbPrintCtx.get != gba->memory.agbPrintCtx.put && i < 0x100; ++i) {
+ int16_t value;
+ LOAD_16(value, gba->memory.agbPrintCtx.get & -2, gba->memory.agbPrintBuffer);
+ if (gba->memory.agbPrintCtx.get & 1) {
+ value >>= 8;
+ } else {
+ value &= 0xFF;
+ }
+ oolBuf[i] = value;
+ oolBuf[i + 1] = 0;
+ ++gba->memory.agbPrintCtx.get;
+ }
+ _agbPrintStore(gba, AGB_PRINT_STRUCT + 4, gba->memory.agbPrintCtx.get);
+
+ mLOG(GBA_DEBUG, INFO, "%s", oolBuf);
+}
+
+static void _agbPrintStore(struct GBA* gba, uint32_t address, int16_t value) {
+ struct GBAMemory* memory = &gba->memory;
+ if ((address & 0x00FFFFFF) < AGB_PRINT_TOP) {
+ if (!memory->agbPrintBuffer) {
+ memory->agbPrintBuffer = anonymousMemoryMap(SIZE_AGB_PRINT);
+ }
+ STORE_16(value, address & (SIZE_AGB_PRINT - 2), memory->agbPrintBuffer);
+ } else if ((address & 0x00FFFFF8) == (AGB_PRINT_STRUCT & 0x00FFFFF8)) {
+ (&memory->agbPrintCtx.request)[(address & 7) >> 1] = value;
+ }
+ if (memory->romSize == SIZE_CART0) {
+ _pristineCow(gba);
+ memcpy(&memory->rom[AGB_PRINT_FLUSH_ADDR >> 2], _agbPrintFunc, sizeof(_agbPrintFunc));
+ STORE_16(value, address & (SIZE_CART0 - 2), memory->rom);
+ } else if (memory->agbPrintCtx.bank == 0xFD && memory->romSize >= SIZE_CART0 / 2) {
+ _pristineCow(gba);
+ STORE_16(value, address & (SIZE_CART0 / 2 - 2), memory->rom);
+ }
+}
+
+static int16_t _agbPrintLoad(struct GBA* gba, uint32_t address) {
+ struct GBAMemory* memory = &gba->memory;
+ int16_t value = 0xFFFF;
+ if (address < AGB_PRINT_TOP) {
+ LOAD_16(value, address & (SIZE_AGB_PRINT - 1), memory->agbPrintBuffer);
+ } else if ((address & 0x00FFFFF8) == (AGB_PRINT_STRUCT & 0x00FFFFF8)) {
+ value = (&memory->agbPrintCtx.request)[(address & 7) >> 1];
+ }
+ return value;
}
View
@@ -180,6 +180,9 @@ static const struct GBACartridgeOverride _overrides[] = {
{ "KYGE", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
{ "KYGP", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
+ // Aging cartridge
+ { "TCHK", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
+
{ { 0, 0, 0, 0 }, 0, 0, IDLE_LOOP_NONE, false }
};
View
@@ -57,12 +57,15 @@ void GBAVideoCacheAssociate(struct mCacheSet* cache, struct GBAVideo* video) {
}
static void mapParser0(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) {
- UNUSED(cache);
uint16_t map = *(uint16_t*) vram;
entry->tileId = GBA_TEXT_MAP_TILE(map);
entry->flags = mMapCacheEntryFlagsSetHMirror(entry->flags, !!GBA_TEXT_MAP_HFLIP(map));
entry->flags = mMapCacheEntryFlagsSetVMirror(entry->flags, !!GBA_TEXT_MAP_VFLIP(map));
- entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, GBA_TEXT_MAP_PALETTE(map));
+ if (mMapCacheSystemInfoGetPaletteBPP(cache->sysConfig) == 3) {
+ entry->flags = mMapCacheEntryFlagsClearPaletteId(entry->flags);
+ } else {
+ entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, GBA_TEXT_MAP_PALETTE(map));
+ }
}
static void mapParser2(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) {
@@ -82,10 +85,14 @@ static void GBAVideoCacheWriteDISPCNT(struct mCacheSet* cache, uint16_t value) {
mMapCacheSetGetPointer(&cache->maps, 2)->mapParser = mapParser0;
mMapCacheSetGetPointer(&cache->maps, 3)->mapParser = mapParser0;
- mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
- mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
- mMapCacheSetGetPointer(&cache->maps, 2)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
- mMapCacheSetGetPointer(&cache->maps, 3)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
+ mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles,
+ mMapCacheSystemInfoGetPaletteBPP(mMapCacheSetGetPointer(&cache->maps, 0)->sysConfig) == 3);
+ mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles,
+ mMapCacheSystemInfoGetPaletteBPP(mMapCacheSetGetPointer(&cache->maps, 1)->sysConfig) == 3);
+ mMapCacheSetGetPointer(&cache->maps, 2)->tileCache = mTileCacheSetGetPointer(&cache->tiles,
+ mMapCacheSystemInfoGetPaletteBPP(mMapCacheSetGetPointer(&cache->maps, 2)->sysConfig) == 3);
+ mMapCacheSetGetPointer(&cache->maps, 3)->tileCache = mTileCacheSetGetPointer(&cache->tiles,
+ mMapCacheSystemInfoGetPaletteBPP(mMapCacheSetGetPointer(&cache->maps, 3)->sysConfig) == 3);
break;
case 1:
case 2:
@@ -94,8 +101,11 @@ static void GBAVideoCacheWriteDISPCNT(struct mCacheSet* cache, uint16_t value) {
mMapCacheSetGetPointer(&cache->maps, 2)->mapParser = mapParser2;
mMapCacheSetGetPointer(&cache->maps, 3)->mapParser = mapParser2;
- mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
- mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
+ mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles,
+ mMapCacheSystemInfoGetPaletteBPP(mMapCacheSetGetPointer(&cache->maps, 0)->sysConfig) == 3);
+ mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles,
+ mMapCacheSystemInfoGetPaletteBPP(mMapCacheSetGetPointer(&cache->maps, 1)->sysConfig) == 3);
+
mMapCacheSetGetPointer(&cache->maps, 2)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1);
mMapCacheSetGetPointer(&cache->maps, 3)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1);
break;
@@ -113,6 +123,7 @@ static void GBAVideoCacheWriteBGCNT(struct mCacheSet* cache, size_t bg, uint16_t
int tilesHigh = 0;
mMapCacheSystemInfo sysconfig = 0;
if (map->mapParser == mapParser0) {
+ map->tileCache = mTileCacheSetGetPointer(&cache->tiles, p);
sysconfig = mMapCacheSystemInfoSetPaletteBPP(sysconfig, 2 + p);
sysconfig = mMapCacheSystemInfoSetPaletteCount(sysconfig, 4 * !p);
sysconfig = mMapCacheSystemInfoSetMacroTileSize(sysconfig, 5);
@@ -125,8 +136,9 @@ static void GBAVideoCacheWriteBGCNT(struct mCacheSet* cache, size_t bg, uint16_t
if (size & 2) {
++tilesHigh;
}
- map->tileStart = tileStart * 2;
+ map->tileStart = tileStart * (2 - p);
} else if (map->mapParser == mapParser2) {
+ map->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1);
sysconfig = mMapCacheSystemInfoSetPaletteBPP(sysconfig, 3);
sysconfig = mMapCacheSystemInfoSetPaletteCount(sysconfig, 0);
sysconfig = mMapCacheSystemInfoSetMacroTileSize(sysconfig, 4 + size);
View
@@ -8,18 +8,13 @@
#include <mgba/internal/gba/gba.h>
#define BACKGROUND_TEXT_SELECT_CHARACTER \
- localX = tileX * 8 + inX; \
xBase = localX & 0xF8; \
if (background->size & 1) { \
xBase += (localX & 0x100) << 5; \
} \
screenBase = background->screenBase + yBase + (xBase >> 2); \
uint16_t* screenBlock = renderer->d.vramBG[screenBase >> VRAM_BLOCK_OFFSET]; \
LOAD_16(mapData, screenBase & VRAM_BLOCK_MASK, screenBlock); \
- localY = inY & 0x7; \
- if (GBA_TEXT_MAP_VFLIP(mapData)) { \
- localY = 7 - localY; \
- }
#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_16(BLEND, OBJWIN) \
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
@@ -75,11 +70,21 @@
if (baseX < 0) { \
int disturbX = (16 + baseX) >> 3; \
inX -= disturbX << 3; \
+ localX = tileX * 8 + inX; \
BACKGROUND_TEXT_SELECT_CHARACTER; \
+ localY = inY & 0x7; \
+ if (GBA_TEXT_MAP_VFLIP(mapData)) { \
+ localY = 7 - localY; \
+ } \
baseX -= disturbX << 3; \
inX += disturbX << 3; \
} else { \
+ localX = tileX * 8 + inX; \
BACKGROUND_TEXT_SELECT_CHARACTER; \
+ localY = inY & 0x7; \
+ if (GBA_TEXT_MAP_VFLIP(mapData)) { \
+ localY = 7 - localY; \
+ } \
} \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
@@ -97,8 +102,14 @@
tileData |= tileData << 16; \
carryData = tileData; \
} \
+ localX = tileX * 8 + inX; \
for (; length; ++tileX) { \
- BACKGROUND_TEXT_SELECT_CHARACTER; \
+ mapData = background->mapCache[(localX >> 3) & 0x3F]; \
+ localX += 8; \
+ localY = inY & 0x7; \
+ if (GBA_TEXT_MAP_VFLIP(mapData)) { \
+ localY = 7 - localY; \
+ } \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
tileData = carryData; \
@@ -128,7 +139,12 @@
#define DRAW_BACKGROUND_MODE_0_TILES_16(BLEND, OBJWIN) \
for (; tileX < tileEnd; ++tileX) { \
- BACKGROUND_TEXT_SELECT_CHARACTER; \
+ mapData = background->mapCache[(localX >> 3) & 0x3F]; \
+ localX += 8; \
+ localY = inY & 0x7; \
+ if (GBA_TEXT_MAP_VFLIP(mapData)) { \
+ localY = 7 - localY; \
+ } \
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
palette = &mainPalette[paletteData]; \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
@@ -238,7 +254,12 @@
#define DRAW_BACKGROUND_MODE_0_TILES_256(BLEND, OBJWIN) \
for (; tileX < tileEnd; ++tileX) { \
- BACKGROUND_TEXT_SELECT_CHARACTER; \
+ mapData = background->mapCache[(localX >> 3) & 0x3F]; \
+ localX += 8; \
+ localY = inY & 0x7; \
+ if (GBA_TEXT_MAP_VFLIP(mapData)) { \
+ localY = 7 - localY; \
+ } \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
@@ -279,8 +300,14 @@
}
#define DRAW_BACKGROUND_MODE_0_MOSAIC_256(BLEND, OBJWIN) \
+ localX = tileX * 8 + inX; \
for (; tileX < tileEnd; ++tileX) { \
- BACKGROUND_TEXT_SELECT_CHARACTER; \
+ mapData = background->mapCache[(localX >> 3) & 0x3F]; \
+ localX += 8; \
+ localY = inY & 0x7; \
+ if (GBA_TEXT_MAP_VFLIP(mapData)) { \
+ localY = 7 - localY; \
+ } \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
tileData = carryData; \
@@ -398,9 +425,14 @@
#define DRAW_BACKGROUND_MODE_0_TILES_256EXT(BLEND, OBJWIN) \
for (; tileX < tileEnd; ++tileX) { \
- BACKGROUND_TEXT_SELECT_CHARACTER; \
+ mapData = background->mapCache[(localX >> 3) & 0x3F]; \
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \
palette = &mainPalette[paletteData]; \
+ localX += 8; \
+ localY = inY & 0x7; \
+ if (GBA_TEXT_MAP_VFLIP(mapData)) { \
+ localY = 7 - localY; \
+ } \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
@@ -441,8 +473,14 @@
}
#define DRAW_BACKGROUND_MODE_0_MOSAIC_256EXT(BLEND, OBJWIN) \
+ localX = tileX * 8 + inX; \
for (; tileX < tileEnd; ++tileX) { \
- BACKGROUND_TEXT_SELECT_CHARACTER; \
+ mapData = background->mapCache[(localX >> 3) & 0x3F]; \
+ localX += 8; \
+ localY = inY & 0x7; \
+ if (GBA_TEXT_MAP_VFLIP(mapData)) { \
+ localY = 7 - localY; \
+ } \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
tileData = carryData; \
@@ -490,8 +528,12 @@
} \
\
if (inX & 0x7) { \
+ localX = tileX * 8 + inX; \
BACKGROUND_TEXT_SELECT_CHARACTER; \
- \
+ localY = inY & 0x7; \
+ if (GBA_TEXT_MAP_VFLIP(mapData)) { \
+ localY = 7 - localY; \
+ } \
int mod8 = inX & 0x7; \
int end = outX + 0x8 - mod8; \
if (end > renderer->end) { \
@@ -514,10 +556,15 @@
} \
length -= end - renderer->start; \
} \
+ localX = (tileX * 8 + inX) & 0x1FF; \
DRAW_BACKGROUND_MODE_0_TILES_ ## BPP (BLEND, OBJWIN) \
if (length & 0x7) { \
+ localX = tileX * 8 + inX; \
BACKGROUND_TEXT_SELECT_CHARACTER; \
- \
+ localY = inY & 0x7; \
+ if (GBA_TEXT_MAP_VFLIP(mapData)) { \
+ localY = 7 - localY; \
+ } \
int mod8 = length & 0x7; \
if (VIDEO_CHECKS && UNLIKELY(outX + mod8 != renderer->end)) { \
mLOG(GBA_VIDEO, FATAL, "Invariant doesn't hold in background draw!"); \
@@ -531,7 +578,7 @@
}
void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y) {
- int inX = renderer->start + background->x;
+ int inX = (renderer->start + background->x) & 0x1FF;
int length = renderer->end - renderer->start;
if (background->mosaic) {
int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1;
@@ -587,10 +634,20 @@ void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer
uint32_t current;
int pixelData;
int paletteData;
- int tileX = 0;
+ int tileX;
int tileEnd = ((length + inX) >> 3) - (inX >> 3);
uint16_t* vram = NULL;
+ if (background->yCache != inY >> 3) {
+ localX = 0;
+ for (tileX = 0; tileX < 64; ++tileX, localX += 8) {
+ BACKGROUND_TEXT_SELECT_CHARACTER;
+ background->mapCache[tileX] = mapData;
+ }
+ background->yCache = inY >> 3;
+ }
+
+ tileX = 0;
if (!objwinSlowPath) {
if (!(flags & FLAG_TARGET_2)) {
if (!background->multipalette) {
View
@@ -245,26 +245,26 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re
return 0;
}
+ int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt) && GBAWindowControlGetBlendEnable(renderer->objwin.packed) != GBAWindowControlIsBlendEnable(renderer->currentWindow.packed);
int variant = renderer->target1Obj &&
GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) &&
(renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN);
- if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) {
- int target2 = renderer->target2Bd << 4;
- target2 |= renderer->bg[0].target2 << (renderer->bg[0].priority);
- target2 |= renderer->bg[1].target2 << (renderer->bg[1].priority);
- target2 |= renderer->bg[2].target2 << (renderer->bg[2].priority);
- target2 |= renderer->bg[3].target2 << (renderer->bg[3].priority);
- if ((1 << GBAObjAttributesCGetPriority(sprite->c)) <= target2) {
+ if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT || objwinSlowPath) {
+ int target2 = renderer->target2Bd;
+ target2 |= renderer->bg[0].target2;
+ target2 |= renderer->bg[1].target2;
+ target2 |= renderer->bg[2].target2;
+ target2 |= renderer->bg[3].target2;
+ if (target2) {
flags |= FLAG_REBLEND;
variant = 0;
- } else if (!target2) {
+ } else {
flags &= ~FLAG_TARGET_1;
}
}
color_t* palette = &renderer->normalPalette[0x100];
color_t* objwinPalette = palette;
- int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt) && GBAWindowControlGetBlendEnable(renderer->objwin.packed) != GBAWindowControlIsBlendEnable(renderer->currentWindow.packed);
if (GBAObjAttributesAIs256Color(sprite->a) && renderer->objExtPalette) {
if (!variant) {
View
@@ -47,7 +47,7 @@ static inline void _compositeBlendObjwin(struct GBAVideoSoftwareRenderer* render
if (current & FLAG_TARGET_1 && color & FLAG_TARGET_2) {
color = _mix(renderer->alphaA[x], current, renderer->alphaB[x], color);
} else {
- color = (current & 0x00FFFFFF) | (current & FLAG_REBLEND);
+ color = (current & 0x00FFFFFF) | (current & (FLAG_REBLEND | FLAG_OBJWIN));
}
} else {
color = (color & ~FLAG_TARGET_2) | (current & FLAG_OBJWIN);
@@ -63,7 +63,7 @@ static inline void _compositeBlendNoObjwin(struct GBAVideoSoftwareRenderer* rend
if (current & FLAG_TARGET_1 && color & FLAG_TARGET_2) {
color = _mix(renderer->alphaA[x], current, renderer->alphaB[x], color);
} else {
- color = (current & 0x00FFFFFF) | (current & FLAG_REBLEND);
+ color = (current & 0x00FFFFFF) | (current & (FLAG_REBLEND | FLAG_OBJWIN));
}
} else {
color = color & ~FLAG_TARGET_2;
@@ -77,7 +77,7 @@ static inline void _compositeNoBlendObjwin(struct GBAVideoSoftwareRenderer* rend
if (color < current) {
color |= (current & FLAG_OBJWIN);
} else {
- color = (current & 0x00FFFFFF) | (current & FLAG_REBLEND);
+ color = (current & 0x00FFFFFF) | (current & (FLAG_REBLEND | FLAG_OBJWIN));
}
renderer->row[x] = color;
}
@@ -86,7 +86,7 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
uint32_t current) {
UNUSED(renderer);
if (color >= current) {
- color = (current & 0x00FFFFFF) | (current & FLAG_REBLEND);
+ color = (current & 0x00FFFFFF) | (current & (FLAG_REBLEND | FLAG_OBJWIN));
}
renderer->row[x] = color;
}
View
@@ -149,6 +149,7 @@ static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer) {
bg->dmy = 256;
bg->sx = 0;
bg->sy = 0;
+ bg->yCache = -1;
bg->extPalette = NULL;
bg->variantPalette = NULL;
}
@@ -167,6 +168,7 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
switch (address) {
case REG_DISPCNT:
+ value &= 0xFFF7;
softwareRenderer->dispcnt = value;
GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer);
break;
@@ -407,6 +409,10 @@ static void GBAVideoSoftwareRendererWriteVRAM(struct GBAVideoRenderer* renderer,
mCacheSetWriteVRAM(renderer->cache, address);
}
memset(softwareRenderer->scanlineDirty, 0xFFFFFFFF, sizeof(softwareRenderer->scanlineDirty));
+ softwareRenderer->bg[0].yCache = -1;
+ softwareRenderer->bg[1].yCache = -1;
+ softwareRenderer->bg[2].yCache = -1;
+ softwareRenderer->bg[3].yCache = -1;
}
static void GBAVideoSoftwareRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
@@ -586,6 +592,10 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
GBAVideoSoftwareRendererPreprocessBuffer(softwareRenderer, y);
int spriteLayers = GBAVideoSoftwareRendererPreprocessSpriteLayer(softwareRenderer, y);
softwareRenderer->d.vramOBJ[0] = objVramBase;
+ if (softwareRenderer->blendDirty) {
+ _updatePalettes(softwareRenderer);
+ softwareRenderer->blendDirty = false;
+ }
int w;
unsigned priority;
@@ -636,13 +646,58 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
}
}
}
+ if (softwareRenderer->target1Obj && (softwareRenderer->blendEffect == BLEND_DARKEN || softwareRenderer->blendEffect == BLEND_BRIGHTEN)) {
+ int x = 0;
+ uint32_t mask = 0xFF000000 & ~FLAG_OBJWIN;
+ uint32_t match = FLAG_REBLEND;
+ if (GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt)) {
+ mask |= FLAG_OBJWIN;
+ if (GBAWindowControlIsBlendEnable(softwareRenderer->objwin.packed)) {
+ match |= FLAG_OBJWIN;
+ }
+ }
+ for (w = 0; w < softwareRenderer->nWindows; ++w) {
+ if (!GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed)) {
+ continue;
+ }
+ int end = softwareRenderer->windows[w].endX;
+ if (softwareRenderer->blendEffect == BLEND_DARKEN) {
+ for (; x < end; ++x) {
+ uint32_t color = softwareRenderer->row[x];
+ if ((color & mask) == match) {
+ softwareRenderer->row[x] = _darken(color, softwareRenderer->bldy);
+ }
+ }
+ } else if (softwareRenderer->blendEffect == BLEND_BRIGHTEN) {
+ for (; x < end; ++x) {
+ uint32_t color = softwareRenderer->row[x];
+ if ((color & mask) == match) {
+ softwareRenderer->row[x] = _brighten(color, softwareRenderer->bldy);
+ }
+ }
+ }
+ }
+ }
if (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt) != 0) {
softwareRenderer->bg[2].sx += softwareRenderer->bg[2].dmx;
softwareRenderer->bg[2].sy += softwareRenderer->bg[2].dmy;
softwareRenderer->bg[3].sx += softwareRenderer->bg[3].dmx;
softwareRenderer->bg[3].sy += softwareRenderer->bg[3].dmy;
}
+ if (softwareRenderer->bg[0].enabled > 0 && softwareRenderer->bg[0].enabled < 4) {
+ ++softwareRenderer->bg[0].enabled;
+ }
+ if (softwareRenderer->bg[1].enabled > 0 && softwareRenderer->bg[1].enabled < 4) {
+ ++softwareRenderer->bg[1].enabled;
+ }
+ if (softwareRenderer->bg[2].enabled > 0 && softwareRenderer->bg[2].enabled < 4) {
+ ++softwareRenderer->bg[2].enabled;
+ }
+ if (softwareRenderer->bg[3].enabled > 0 && softwareRenderer->bg[3].enabled < 4) {
+ ++softwareRenderer->bg[3].enabled;
+ }
+
GBAVideoSoftwareRendererPostprocessBuffer(softwareRenderer);
#ifdef COLOR_16_BIT
@@ -671,6 +726,19 @@ static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* rendere
softwareRenderer->bg[2].sy = softwareRenderer->bg[2].refy;
softwareRenderer->bg[3].sx = softwareRenderer->bg[3].refx;
softwareRenderer->bg[3].sy = softwareRenderer->bg[3].refy;
+
+ if (softwareRenderer->bg[0].enabled > 0) {
+ softwareRenderer->bg[0].enabled = 4;
+ }
+ if (softwareRenderer->bg[1].enabled > 0) {
+ softwareRenderer->bg[1].enabled = 4;
+ }
+ if (softwareRenderer->bg[2].enabled > 0) {
+ softwareRenderer->bg[2].enabled = 4;
+ }
+ if (softwareRenderer->bg[3].enabled > 0) {
+ softwareRenderer->bg[3].enabled = 4;
+ }
}
static void GBAVideoSoftwareRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
@@ -689,11 +757,23 @@ static void GBAVideoSoftwareRendererPutPixels(struct GBAVideoRenderer* renderer,
}
}
+static void _enableBg(struct GBAVideoSoftwareRenderer* renderer, int bg, bool active) {
+ if (renderer->d.disableBG[bg] || !active) {
+ renderer->bg[bg].enabled = 0;
+ } else if (!renderer->bg[bg].enabled && active) {
+ if (renderer->nextY == 0) {
+ renderer->bg[bg].enabled = 4;
+ } else {
+ renderer->bg[bg].enabled = 1;
+ }
+ }
+}
+
static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRenderer* renderer) {
- renderer->bg[0].enabled = GBARegisterDISPCNTGetBg0Enable(renderer->dispcnt) && !renderer->d.disableBG[0];
- renderer->bg[1].enabled = GBARegisterDISPCNTGetBg1Enable(renderer->dispcnt) && !renderer->d.disableBG[1];
- renderer->bg[2].enabled = GBARegisterDISPCNTGetBg2Enable(renderer->dispcnt) && !renderer->d.disableBG[2];
- renderer->bg[3].enabled = GBARegisterDISPCNTGetBg3Enable(renderer->dispcnt) && !renderer->d.disableBG[3];
+ _enableBg(renderer, 0, GBARegisterDISPCNTGetBg0Enable(renderer->dispcnt));
+ _enableBg(renderer, 1, GBARegisterDISPCNTGetBg1Enable(renderer->dispcnt));
+ _enableBg(renderer, 2, GBARegisterDISPCNTGetBg2Enable(renderer->dispcnt));
+ _enableBg(renderer, 3, GBARegisterDISPCNTGetBg3Enable(renderer->dispcnt));
}
static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* bg, uint16_t value) {
View
@@ -576,9 +576,15 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
if (bank > 0 && savedata->type == SAVEDATA_FLASH512) {
mLOG(GBA_SAVE, INFO, "Updating flash chip from 512kb to 1Mb");
savedata->type = SAVEDATA_FLASH1M;
- if (savedata->vf && savedata->vf->size(savedata->vf) == SIZE_CART_FLASH512) {
- savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
- memset(&savedata->data[SIZE_CART_FLASH512], 0xFF, SIZE_CART_FLASH512);
+ if (savedata->vf) {
+ savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH512);
+ if (savedata->vf->size(savedata->vf) == SIZE_CART_FLASH512) {
+ savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
+ savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, MAP_WRITE);
+ memset(&savedata->data[SIZE_CART_FLASH512], 0xFF, SIZE_CART_FLASH512);
+ } else {
+ savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, MAP_WRITE);
+ }
}
}
}
View
@@ -0,0 +1,76 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include <mgba/internal/gba/sio.h>
+
+#include <mgba/internal/gba/gba.h>
+#include <mgba/internal/gba/io.h>
+
+static uint16_t GBASIOJOYWriteRegister(struct GBASIODriver* sio, uint32_t address, uint16_t value);
+
+void GBASIOJOYCreate(struct GBASIODriver* sio) {
+ sio->init = NULL;
+ sio->deinit = NULL;
+ sio->load = NULL;
+ sio->unload = NULL;
+ sio->writeRegister = GBASIOJOYWriteRegister;
+}
+
+uint16_t GBASIOJOYWriteRegister(struct GBASIODriver* sio, uint32_t address, uint16_t value) {
+ switch (address) {
+ case REG_JOYCNT:
+ return (value & 0x0040) | (sio->p->p->memory.io[REG_JOYCNT >> 1] & ~(value & 0x7) & ~0x0040);
+ case REG_JOYSTAT:
+ return (value & 0x0030) | (sio->p->p->memory.io[REG_JOYSTAT >> 1] & ~0x30);
+ case REG_JOY_TRANS_LO:
+ case REG_JOY_TRANS_HI:
+ sio->p->p->memory.io[REG_JOYSTAT >> 1] |= 8;
+ break;
+ }
+ return value;
+}
+
+int GBASIOJOYSendCommand(struct GBASIODriver* sio, enum GBASIOJOYCommand command, uint8_t* data) {
+ switch (command) {
+ case JOY_RESET:
+ sio->p->p->memory.io[REG_JOYCNT >> 1] |= 1;
+ if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) {
+ GBARaiseIRQ(sio->p->p, IRQ_SIO);
+ }
+ // Fall through
+ case JOY_POLL:
+ data[0] = 0x00;
+ data[1] = 0x04;
+ data[2] = sio->p->p->memory.io[REG_JOYSTAT >> 1];
+ return 3;
+ case JOY_RECV:
+ sio->p->p->memory.io[REG_JOYCNT >> 1] |= 2;
+ sio->p->p->memory.io[REG_JOYSTAT >> 1] |= 2;
+
+ sio->p->p->memory.io[REG_JOY_RECV_LO >> 1] = data[0] | (data[1] << 8);
+ sio->p->p->memory.io[REG_JOY_RECV_HI >> 1] = data[2] | (data[3] << 8);
+
+ data[0] = sio->p->p->memory.io[REG_JOYSTAT >> 1];
+
+ if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) {
+ GBARaiseIRQ(sio->p->p, IRQ_SIO);
+ }
+ return 1;
+ case JOY_TRANS:
+ sio->p->p->memory.io[REG_JOYCNT >> 1] |= 4;
+ sio->p->p->memory.io[REG_JOYSTAT >> 1] &= ~8;
+ data[0] = sio->p->p->memory.io[REG_JOY_TRANS_LO >> 1];
+ data[1] = sio->p->p->memory.io[REG_JOY_TRANS_LO >> 1] >> 8;
+ data[2] = sio->p->p->memory.io[REG_JOY_TRANS_HI >> 1];
+ data[3] = sio->p->p->memory.io[REG_JOY_TRANS_HI >> 1] >> 8;
+ data[4] = sio->p->p->memory.io[REG_JOYSTAT >> 1];
+
+ if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) {
+ GBARaiseIRQ(sio->p->p, IRQ_SIO);
+ }
+ return 5;
+ }
+ return 0;
+}
View
@@ -75,6 +75,93 @@ M_TEST_DEFINE(doPARv3Assign) {
set->deinit(set);
}
+M_TEST_DEFINE(doPARv3Slide1) {
+ struct mCore* core = *state;
+ struct mCheatDevice* device = core->cheatDevice(core);
+ assert_non_null(device);
+ struct mCheatSet* set = device->createSet(device, NULL);
+ assert_non_null(set);
+ GBACheatSetGameSharkVersion((struct GBACheatSet*) set, GBA_GS_PARV3_RAW);
+ assert_true(set->addLine(set, "00000000 80300000", GBA_CHEAT_PRO_ACTION_REPLAY));
+ assert_true(set->addLine(set, "00000001 01020002", GBA_CHEAT_PRO_ACTION_REPLAY));
+
+ core->reset(core);
+ assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0);
+ assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0);
+ assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0);
+ assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0);
+ assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0);
+ assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0);
+
+ mCheatRefresh(device, set);
+ assert_int_equal(core->rawRead8(core, 0x03000000, -1), 1);
+ assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0);
+ assert_int_equal(core->rawRead8(core, 0x03000002, -1), 2);
+ assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0);
+ assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0);
+ assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0);
+
+ set->deinit(set);
+}
+
+M_TEST_DEFINE(doPARv3Slide2) {
+ struct mCore* core = *state;
+ struct mCheatDevice* device = core->cheatDevice(core);
+ assert_non_null(device);
+ struct mCheatSet* set = device->createSet(device, NULL);
+ assert_non_null(set);
+ GBACheatSetGameSharkVersion((struct GBACheatSet*) set, GBA_GS_PARV3_RAW);
+ assert_true(set->addLine(set, "00000000 82300000", GBA_CHEAT_PRO_ACTION_REPLAY));
+ assert_true(set->addLine(set, "00000001 01020002", GBA_CHEAT_PRO_ACTION_REPLAY));
+
+ core->reset(core);
+ assert_int_equal(core->rawRead16(core, 0x03000000, -1), 0);
+ assert_int_equal(core->rawRead16(core, 0x03000002, -1), 0);
+ assert_int_equal(core->rawRead16(core, 0x03000004, -1), 0);
+ assert_int_equal(core->rawRead16(core, 0x03000006, -1), 0);
+ assert_int_equal(core->rawRead16(core, 0x03000008, -1), 0);
+ assert_int_equal(core->rawRead16(core, 0x0300000A, -1), 0);
+
+ mCheatRefresh(device, set);
+ assert_int_equal(core->rawRead16(core, 0x03000000, -1), 1);
+ assert_int_equal(core->rawRead16(core, 0x03000002, -1), 0);
+ assert_int_equal(core->rawRead16(core, 0x03000004, -1), 2);
+ assert_int_equal(core->rawRead16(core, 0x03000006, -1), 0);
+ assert_int_equal(core->rawRead16(core, 0x03000008, -1), 0);
+ assert_int_equal(core->rawRead16(core, 0x0300000A, -1), 0);
+
+ set->deinit(set);
+}
+
+M_TEST_DEFINE(doPARv3Slide4) {
+ struct mCore* core = *state;
+ struct mCheatDevice* device = core->cheatDevice(core);
+ assert_non_null(device);
+ struct mCheatSet* set = device->createSet(device, NULL);
+ assert_non_null(set);
+ GBACheatSetGameSharkVersion((struct GBACheatSet*) set, GBA_GS_PARV3_RAW);
+ assert_true(set->addLine(set, "00000000 84300000", GBA_CHEAT_PRO_ACTION_REPLAY));
+ assert_true(set->addLine(set, "00000001 01020002", GBA_CHEAT_PRO_ACTION_REPLAY));
+
+ core->reset(core);
+ assert_int_equal(core->rawRead32(core, 0x03000000, -1), 0);
+ assert_int_equal(core->rawRead32(core, 0x03000004, -1), 0);
+ assert_int_equal(core->rawRead32(core, 0x03000008, -1), 0);
+ assert_int_equal(core->rawRead32(core, 0x0300000C, -1), 0);
+ assert_int_equal(core->rawRead32(core, 0x03000010, -1), 0);
+ assert_int_equal(core->rawRead32(core, 0x03000014, -1), 0);
+
+ mCheatRefresh(device, set);
+ assert_int_equal(core->rawRead16(core, 0x03000000, -1), 1);
+ assert_int_equal(core->rawRead16(core, 0x03000004, -1), 0);
+ assert_int_equal(core->rawRead16(core, 0x03000008, -1), 2);
+ assert_int_equal(core->rawRead16(core, 0x0300000C, -1), 0);
+ assert_int_equal(core->rawRead16(core, 0x03000010, -1), 0);
+ assert_int_equal(core->rawRead16(core, 0x03000014, -1), 0);
+
+ set->deinit(set);
+}
+
M_TEST_DEFINE(doPARv3If1) {
struct mCore* core = *state;
struct mCheatDevice* device = core->cheatDevice(core);
@@ -334,6 +421,7 @@ M_TEST_DEFINE(doPARv3IfX) {
mCheatRefresh(device, set);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11);
+ set->deinit(set);
}
M_TEST_DEFINE(doPARv3IfXxX) {
@@ -396,6 +484,7 @@ M_TEST_DEFINE(doPARv3IfXxX) {
assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21);
assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x32);
assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x41);
+ set->deinit(set);
}
M_TEST_DEFINE(doPARv3IfXElse) {
@@ -430,6 +519,7 @@ M_TEST_DEFINE(doPARv3IfXElse) {
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11);
assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x22);
+ set->deinit(set);
}
M_TEST_DEFINE(doPARv3IfXElsexX) {
@@ -500,6 +590,7 @@ M_TEST_DEFINE(doPARv3IfXElsexX) {
assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x32);
assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x42);
assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0x51);
+ set->deinit(set);
}
M_TEST_DEFINE(doPARv3IfXElsexXElse) {
@@ -577,6 +668,7 @@ M_TEST_DEFINE(doPARv3IfXElsexXElse) {
assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x42);
assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0x51);
assert_int_equal(core->rawRead8(core, 0x03000006, -1), 0x62);
+ set->deinit(set);
}
M_TEST_DEFINE(doPARv3IfXContain1) {
@@ -638,6 +730,7 @@ M_TEST_DEFINE(doPARv3IfXContain1) {
assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21);
assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x31);
assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x41);
+ set->deinit(set);
}
M_TEST_DEFINE(doPARv3IfXContain1Else) {
@@ -707,6 +800,7 @@ M_TEST_DEFINE(doPARv3IfXContain1Else) {
assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x31);
assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x41);
assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0x52);
+ set->deinit(set);
}
M_TEST_DEFINE(doPARv3IfXElseContain1) {
@@ -776,6 +870,7 @@ M_TEST_DEFINE(doPARv3IfXElseContain1) {
assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x32);
assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x41);
assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0x52);
+ set->deinit(set);
}
M_TEST_DEFINE(doPARv3IfXContain1ElseContain1) {
@@ -921,12 +1016,46 @@ M_TEST_DEFINE(doPARv3IfXContain1ElseContain1) {
assert_int_equal(core->rawRead8(core, 0x03000006, -1), 0x62);
assert_int_equal(core->rawRead8(core, 0x03000007, -1), 0x71);
assert_int_equal(core->rawRead8(core, 0x03000008, -1), 0x82);
+ set->deinit(set);
+}
+
+M_TEST_DEFINE(doPARv3IfButton) {
+ struct mCore* core = *state;
+ struct mCheatDevice* device = core->cheatDevice(core);
+ assert_non_null(device);
+ struct mCheatSet* set = device->createSet(device, NULL);
+ assert_non_null(set);
+ GBACheatSetGameSharkVersion((struct GBACheatSet*) set, GBA_GS_PARV3_RAW);
+ assert_true(set->addLine(set, "00000000 10300000", GBA_CHEAT_PRO_ACTION_REPLAY));
+ assert_true(set->addLine(set, "00000001 00000000", GBA_CHEAT_PRO_ACTION_REPLAY));
+
+ core->reset(core);
+ assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0);
+
+ mCheatRefresh(device, set);
+ assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0);
+
+ mCheatPressButton(device, true);
+ mCheatRefresh(device, set);
+ assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);
+
+ mCheatPressButton(device, false);
+ mCheatRefresh(device, set);
+ assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);
+
+ core->rawWrite8(core, 0x03000000, -1, 0);
+ mCheatRefresh(device, set);
+ assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0);
+ set->deinit(set);
}
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(GBACheats,
cmocka_unit_test(createSet),
cmocka_unit_test(addRawPARv3),
cmocka_unit_test(doPARv3Assign),
+ cmocka_unit_test(doPARv3Slide1),
+ cmocka_unit_test(doPARv3Slide2),
+ cmocka_unit_test(doPARv3Slide4),
cmocka_unit_test(doPARv3If1),
cmocka_unit_test(doPARv3If1x1),
cmocka_unit_test(doPARv3If2),
@@ -940,4 +1069,5 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(GBACheats,
cmocka_unit_test(doPARv3IfXContain1),
cmocka_unit_test(doPARv3IfXContain1Else),
cmocka_unit_test(doPARv3IfXElseContain1),
- cmocka_unit_test(doPARv3IfXContain1ElseContain1))
+ cmocka_unit_test(doPARv3IfXContain1ElseContain1),
+ cmocka_unit_test(doPARv3IfButton))
View
@@ -71,7 +71,7 @@ static struct GBAVideoRenderer dummyRenderer = {
void GBAVideoInit(struct GBAVideo* video) {
video->renderer = &dummyRenderer;
video->renderer->cache = NULL;
- video->vram = 0;
+ video->vram = anonymousMemoryMap(SIZE_VRAM);
video->frameskip = 0;
video->event.name = "GBA Video";
video->event.callback = NULL;
@@ -94,10 +94,6 @@ void GBAVideoReset(struct GBAVideo* video) {
video->frameCounter = 0;
video->frameskipCounter = 0;
- if (video->vram) {
- mappedMemoryFree(video->vram, SIZE_VRAM);
- }
- video->vram = anonymousMemoryMap(SIZE_VRAM);
memset(video->renderer->vramBG, 0, sizeof(video->renderer->vramBG));
video->renderer->vramBG[0] = &video->vram[0x0000];
video->renderer->vramBG[1] = &video->vram[0x2000];
@@ -207,6 +203,9 @@ void _startHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) {
if (video->vcount < VIDEO_VERTICAL_PIXELS) {
GBADMARunHblank(video->p, -cyclesLate);
}
+ if (video->vcount >= 2 && video->vcount < VIDEO_VERTICAL_PIXELS + 2) {
+ GBADMARunDisplayStart(video->p, -cyclesLate);
+ }
if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) {
GBARaiseIRQ(video->p, IRQ_HBLANK);
}
@@ -239,6 +238,9 @@ static uint16_t GBAVideoDummyRendererWriteVideoRegister(struct GBAVideoRenderer*
GBAVideoCacheWriteVideoRegister(renderer->cache, address, value);
}
switch (address) {
+ case REG_DISPCNT:
+ value &= 0xFFF7;
+ break;
case REG_BG0CNT:
case REG_BG1CNT:
value &= 0xDFFF;
View
@@ -100,58 +100,9 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
_printLine(debugger->p, cpu->pc, cpu->memory.currentSegment(cpu, cpu->pc));
}
-static uint32_t _lookupPlatformIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
- struct LR35902Core* cpu = debugger->p->d.core->cpu;
- if (strcmp(name, "a") == 0) {
- return cpu->a;
- }
- if (strcmp(name, "b") == 0) {
- return cpu->b;
- }
- if (strcmp(name, "c") == 0) {
- return cpu->c;
- }
- if (strcmp(name, "d") == 0) {
- return cpu->d;
- }
- if (strcmp(name, "e") == 0) {
- return cpu->e;
- }
- if (strcmp(name, "h") == 0) {
- return cpu->h;
- }
- if (strcmp(name, "l") == 0) {
- return cpu->l;
- }
- if (strcmp(name, "bc") == 0) {
- return cpu->bc;
- }
- if (strcmp(name, "de") == 0) {
- return cpu->de;
- }
- if (strcmp(name, "hl") == 0) {
- return cpu->hl;
- }
- if (strcmp(name, "af") == 0) {
- return cpu->af;
- }
- if (strcmp(name, "pc") == 0) {
- return cpu->pc;
- }
- if (strcmp(name, "sp") == 0) {
- return cpu->sp;
- }
- if (strcmp(name, "f") == 0) {
- return cpu->f.packed;
- }
- dv->type = CLIDV_ERROR_TYPE;
- return 0;
-}
-
void LR35902CLIDebuggerCreate(struct CLIDebuggerSystem* debugger) {
debugger->printStatus = _printStatus;
debugger->disassemble = _disassemble;
- debugger->lookupPlatformIdentifier = _lookupPlatformIdentifier;
debugger->platformName = "GB-Z80";
debugger->platformCommands = _lr35902Commands;
}
View
@@ -6,6 +6,7 @@
#include <mgba/internal/lr35902/debugger/debugger.h>
#include <mgba/core/core.h>
+#include <mgba/internal/debugger/parser.h>
#include <mgba/internal/lr35902/decoder.h>
#include <mgba/internal/lr35902/lr35902.h>
#include <mgba/internal/lr35902/debugger/memory-debugger.h>
@@ -23,6 +24,20 @@ static struct LR35902DebugBreakpoint* _lookupBreakpoint(struct LR35902DebugBreak
return 0;
}
+static void _destroyBreakpoint(struct LR35902DebugBreakpoint* breakpoint) {
+ if (breakpoint->condition) {
+ parseFree(breakpoint->condition);
+ free(breakpoint->condition);
+ }
+}
+
+static void _destroyWatchpoint(struct LR35902DebugWatchpoint* watchpoint) {
+ if (watchpoint->condition) {
+ parseFree(watchpoint->condition);
+ free(watchpoint->condition);
+ }
+}
+
static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
struct LR35902DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->pc);
@@ -32,6 +47,13 @@ static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
if (breakpoint->segment >= 0 && debugger->cpu->memory.currentSegment(debugger->cpu, breakpoint->address) != breakpoint->segment) {
return;
}
+ if (breakpoint->condition) {
+ int32_t value;
+ int segment;
+ if (!mDebuggerEvaluateParseTree(d->p, breakpoint->condition, &value, &segment) || !(value || segment >= 0)) {
+ return;
+ }
+ }
struct mDebuggerEntryInfo info = {
.address = breakpoint->address
};
@@ -44,25 +66,33 @@ static void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform);
static void LR35902DebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
+static void LR35902DebuggerSetConditionalBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition);
static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
+static void LR35902DebuggerSetConditionalWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition);
static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*);
static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*);
static void LR35902DebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length);
+static bool LR35902DebuggerGetRegister(struct mDebuggerPlatform*, const char* name, int32_t* value);
+static bool LR35902DebuggerSetRegister(struct mDebuggerPlatform*, const char* name, int32_t value);
struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct LR35902Debugger));
platform->entered = LR35902DebuggerEnter;
platform->init = LR35902DebuggerInit;
platform->deinit = LR35902DebuggerDeinit;
platform->setBreakpoint = LR35902DebuggerSetBreakpoint;
+ platform->setConditionalBreakpoint = LR35902DebuggerSetConditionalBreakpoint;
platform->clearBreakpoint = LR35902DebuggerClearBreakpoint;
platform->setWatchpoint = LR35902DebuggerSetWatchpoint;
+ platform->setConditionalWatchpoint = LR35902DebuggerSetConditionalWatchpoint;
platform->clearWatchpoint = LR35902DebuggerClearWatchpoint;
platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
platform->trace = LR35902DebuggerTrace;
+ platform->getRegister = LR35902DebuggerGetRegister;
+ platform->setRegister = LR35902DebuggerSetRegister;
return platform;
}
@@ -75,7 +105,15 @@ void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
+ size_t i;
+ for (i = 0; i < LR35902DebugBreakpointListSize(&debugger->breakpoints); ++i) {
+ _destroyBreakpoint(LR35902DebugBreakpointListGetPointer(&debugger->breakpoints, i));
+ }
LR35902DebugBreakpointListDeinit(&debugger->breakpoints);
+
+ for (i = 0; i < LR35902DebugWatchpointListSize(&debugger->watchpoints); ++i) {
+ _destroyWatchpoint(LR35902DebugWatchpointListGetPointer(&debugger->watchpoints, i));
+ }
LR35902DebugWatchpointListDeinit(&debugger->watchpoints);
}
@@ -92,10 +130,15 @@ static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebug
}
static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
+ LR35902DebuggerSetConditionalBreakpoint(d, address, segment, NULL);
+}
+
+static void LR35902DebuggerSetConditionalBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, struct ParseTree* condition) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListAppend(&debugger->breakpoints);
breakpoint->address = address;
breakpoint->segment = segment;
+ breakpoint->condition = condition;
}
static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
@@ -105,6 +148,7 @@ static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t
for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) {
struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListGetPointer(breakpoints, i);
if (breakpoint->address == address && breakpoint->segment == segment) {
+ _destroyBreakpoint(LR35902DebugBreakpointListGetPointer(breakpoints, i));
LR35902DebugBreakpointListShift(breakpoints, i, 1);
}
}
@@ -116,6 +160,10 @@ static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
}
static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) {
+ LR35902DebuggerSetConditionalWatchpoint(d, address, segment, type, NULL);
+}
+
+static void LR35902DebuggerSetConditionalWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
LR35902DebuggerInstallMemoryShim(debugger);
@@ -124,6 +172,7 @@ static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t a
watchpoint->address = address;
watchpoint->type = type;
watchpoint->segment = segment;
+ watchpoint->condition = condition;
}
static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
@@ -168,3 +217,131 @@ static void LR35902DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t*
cpu->d, cpu->e, cpu->h, cpu->l,
cpu->sp, cpu->pc, disassembly);
}
+
+bool LR35902DebuggerGetRegister(struct mDebuggerPlatform* d, const char* name, int32_t* value) {
+ struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
+ struct LR35902Core* cpu = debugger->cpu;
+
+ if (strcmp(name, "a") == 0) {
+ *value = cpu->a;
+ return true;
+ }
+ if (strcmp(name, "b") == 0) {
+ *value = cpu->b;
+ return true;
+ }
+ if (strcmp(name, "c") == 0) {
+ *value = cpu->c;
+ return true;
+ }
+ if (strcmp(name, "d") == 0) {
+ *value = cpu->d;
+ return true;
+ }
+ if (strcmp(name, "e") == 0) {
+ *value = cpu->e;
+ return true;
+ }
+ if (strcmp(name, "h") == 0) {
+ *value = cpu->h;
+ return true;
+ }
+ if (strcmp(name, "l") == 0) {
+ *value = cpu->l;
+ return true;
+ }
+ if (strcmp(name, "bc") == 0) {
+ *value = cpu->bc;
+ return true;
+ }
+ if (strcmp(name, "de") == 0) {
+ *value = cpu->de;
+ return true;
+ }
+ if (strcmp(name, "hl") == 0) {
+ *value = cpu->hl;
+ return true;
+ }
+ if (strcmp(name, "af") == 0) {
+ *value = cpu->af;
+ return true;
+ }
+ if (strcmp(name, "pc") == 0) {
+ *value = cpu->pc;
+ return true;
+ }
+ if (strcmp(name, "sp") == 0) {
+ *value = cpu->sp;
+ return true;
+ }
+ if (strcmp(name, "f") == 0) {
+ *value = cpu->f.packed;
+ return true;
+ }
+ return false;
+}
+
+bool LR35902DebuggerSetRegister(struct mDebuggerPlatform* d, const char* name, int32_t value) {
+ struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
+ struct LR35902Core* cpu = debugger->cpu;
+
+ if (strcmp(name, "a") == 0) {
+ cpu->a = value;
+ return true;
+ }
+ if (strcmp(name, "b") == 0) {
+ cpu->b = value;
+ return true;
+ }
+ if (strcmp(name, "c") == 0) {
+ cpu->c = value;
+ return true;
+ }
+ if (strcmp(name, "d") == 0) {
+ cpu->d = value;
+ return true;
+ }
+ if (strcmp(name, "e") == 0) {
+ cpu->e = value;
+ return true;
+ }
+ if (strcmp(name, "h") == 0) {
+ cpu->h = value;
+ return true;
+ }
+ if (strcmp(name, "l") == 0) {
+ cpu->l = value;
+ return true;
+ }
+ if (strcmp(name, "bc") == 0) {
+ cpu->bc = value;
+ return true;
+ }
+ if (strcmp(name, "de") == 0) {
+ cpu->de = value;
+ return true;
+ }
+ if (strcmp(name, "hl") == 0) {
+ cpu->hl = value;
+ return true;
+ }
+ if (strcmp(name, "af") == 0) {
+ cpu->af = value;
+ cpu->f.packed &= 0xF0;
+ return true;
+ }
+ if (strcmp(name, "pc") == 0) {
+ cpu->pc = value;
+ cpu->memory.setActiveRegion(cpu, cpu->pc);
+ return true;
+ }
+ if (strcmp(name, "sp") == 0) {
+ cpu->sp = value;
+ return true;
+ }
+ if (strcmp(name, "f") == 0) {
+ cpu->f.packed = value & 0xF0;
+ return true;
+ }
+ return false;
+}
Oops, something went wrong.