void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) { struct GBMemory* memory = &gb->memory; int bank = value & 0xF; switch (address >> 13) { case 0x0: switch (value) { case 0: memory->sramAccess = false; break; case 0xA: memory->sramAccess = true; GBMBCSwitchSramBank(gb, memory->sramCurrentBank); break; default: // TODO mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value); break; } break; case 0x1: if (!bank) { ++bank; } GBMBCSwitchBank(gb, bank); break; default: // TODO mLOG(GB_MBC, STUB, "MBC2 unknown address: %04X:%02X", address, value); break; }}
bool GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAddress) { if (!SOCKET_FAILED(stub->socket)) { GDBStubShutdown(stub); } stub->socket = SocketOpenTCP(port, bindAddress); if (SOCKET_FAILED(stub->socket)) { mLOG(DEBUGGER, ERROR, "Couldn't open socket"); return false; } if (!SocketSetBlocking(stub->socket, false)) { goto cleanup; } int err = SocketListen(stub->socket, 1); if (err) { goto cleanup; } return true; cleanup: mLOG(DEBUGGER, ERROR, "Couldn't listen on port"); SocketClose(stub->socket); stub->socket = INVALID_SOCKET; return false; }
void mCoreTakeScreenshot(struct mCore* core) { #ifdef USE_PNG size_t stride; color_t* pixels = 0; unsigned width, height; core->desiredVideoDimensions(core, &width, &height); struct VFile* vf = VDirFindNextAvailable(core->dirs.screenshot, core->dirs.baseName, "-", ".png", O_CREAT | O_TRUNC | O_WRONLY); bool success = false; if (vf) { core->getVideoBuffer(core, &pixels, &stride); png_structp png = PNGWriteOpen(vf); png_infop info = PNGWriteHeader(png, width, height); success = PNGWritePixels(png, width, height, stride, pixels); PNGWriteClose(png, info); vf->close(vf); } if (success) { mLOG(STATUS, INFO, "Screenshot saved"); return; } #else UNUSED(core); #endif mLOG(STATUS, WARN, "Failed to take screenshot"); }
void GDBStubUpdate(struct GDBStub* stub) { if (stub->socket == INVALID_SOCKET) { if (stub->d.state == DEBUGGER_PAUSED) { stub->d.state = DEBUGGER_RUNNING; } return; } if (stub->connection == INVALID_SOCKET) { if (stub->shouldBlock) { Socket reads = stub->socket; SocketPoll(1, &reads, 0, 0, SOCKET_TIMEOUT); } stub->connection = SocketAccept(stub->socket, 0); if (!SOCKET_FAILED(stub->connection)) { if (!SocketSetBlocking(stub->connection, false)) { goto connectionLost; } mDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED, 0); } else if (SocketWouldBlock()) { return; } else { goto connectionLost; } } while (true) { if (stub->shouldBlock) { Socket reads = stub->connection; SocketPoll(1, &reads, 0, 0, SOCKET_TIMEOUT); } ssize_t messageLen = SocketRecv(stub->connection, stub->line, GDB_STUB_MAX_LINE - 1); if (messageLen == 0) { goto connectionLost; } if (messageLen == -1) { if (SocketWouldBlock()) { return; } goto connectionLost; } stub->line[messageLen] = '\0'; mLOG(DEBUGGER, DEBUG, "< %s", stub->line); ssize_t position = 0; while (position < messageLen) { position += _parseGDBMessage(stub, &stub->line[position]); } } connectionLost: mLOG(DEBUGGER, WARN, "Connection lost"); GDBStubHangup(stub); }
bool mSDLInitAudio(struct mSDLAudio* context, struct mCoreThread* threadContext) { if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { mLOG(SDL_AUDIO, ERROR, "Could not initialize SDL sound system: %s", SDL_GetError()); return false; } context->desiredSpec.freq = context->sampleRate; context->desiredSpec.format = AUDIO_S16SYS; context->desiredSpec.channels = 2; context->desiredSpec.samples = context->samples; context->desiredSpec.callback = _mSDLAudioCallback; context->desiredSpec.userdata = context; #if SDL_VERSION_ATLEAST(2, 0, 0) context->deviceId = SDL_OpenAudioDevice(0, 0, &context->desiredSpec, &context->obtainedSpec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); if (context->deviceId == 0) { #else if (SDL_OpenAudio(&context->desiredSpec, &context->obtainedSpec) < 0) { #endif mLOG(SDL_AUDIO, ERROR, "Could not open SDL sound system"); return false; } context->core = 0; if (threadContext) { context->core = threadContext->core; context->sync = &threadContext->impl->sync; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_PauseAudioDevice(context->deviceId, 0); #else SDL_PauseAudio(0); #endif } return true; } void mSDLDeinitAudio(struct mSDLAudio* context) { UNUSED(context); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_PauseAudioDevice(context->deviceId, 1); SDL_CloseAudioDevice(context->deviceId); #else SDL_PauseAudio(1); SDL_CloseAudio(); #endif SDL_QuitSubSystem(SDL_INIT_AUDIO); }
bool mCoreLoadState(struct mCore* core, int slot, int flags) { struct VFile* vf = mCoreGetState(core, slot, false); if (!vf) { return false; } bool success = mCoreLoadStateNamed(core, vf, flags); vf->close(vf); if (success) { mLOG(STATUS, INFO, "State %i loaded", slot); } else { mLOG(STATUS, INFO, "State %i failed to loaded", slot); } return success; }
static void _sendMessage(struct GDBStub* stub) { if (stub->lineAck != GDB_ACK_OFF) { stub->lineAck = GDB_ACK_PENDING; } uint8_t checksum = 0; int i = 1; char buffer = stub->outgoing[0]; char swap; stub->outgoing[0] = '$'; if (buffer) { for (; i < GDB_STUB_MAX_LINE - 5; ++i) { checksum += buffer; swap = stub->outgoing[i]; stub->outgoing[i] = buffer; buffer = swap; if (!buffer) { ++i; break; } } } stub->outgoing[i] = '#'; _int2hex8(checksum, &stub->outgoing[i + 1]); stub->outgoing[i + 3] = 0; mLOG(DEBUGGER, DEBUG, "> %s", stub->outgoing); SocketSend(stub->connection, stub->outgoing, i + 3); }
void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value) { switch (address) { case GPIO_REG_DATA: hw->pinState &= ~hw->direction; hw->pinState |= value; _readPins(hw); break; case GPIO_REG_DIRECTION: hw->direction = value; break; case GPIO_REG_CONTROL: hw->readWrite = value; break; default: mLOG(GBA_HW, WARN, "Invalid GPIO address"); } if (hw->readWrite) { uint16_t old; LOAD_16(old, 0, hw->gpioBase); old &= ~hw->direction; old |= hw->pinState; STORE_16(old, 0, hw->gpioBase); } else { hw->gpioBase[0] = 0; } }
uint8_t GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) { gb->memory.hdmaSource = gb->memory.io[REG_HDMA1] << 8; gb->memory.hdmaSource |= gb->memory.io[REG_HDMA2]; gb->memory.hdmaDest = gb->memory.io[REG_HDMA3] << 8; gb->memory.hdmaDest |= gb->memory.io[REG_HDMA4]; gb->memory.hdmaSource &= 0xFFF0; if (gb->memory.hdmaSource >= 0x8000 && gb->memory.hdmaSource < 0xA000) { mLOG(GB_MEM, GAME_ERROR, "Invalid HDMA source: %04X", gb->memory.hdmaSource); return value | 0x80; } gb->memory.hdmaDest &= 0x1FF0; gb->memory.hdmaDest |= 0x8000; bool wasHdma = gb->memory.isHdma; gb->memory.isHdma = value & 0x80; if ((!wasHdma && !gb->memory.isHdma) || gb->video.mode == 0) { if (gb->memory.isHdma) { gb->memory.hdmaRemaining = 0x10; } else { gb->memory.hdmaRemaining = ((value & 0x7F) + 1) * 0x10; } gb->cpuBlocked = true; mTimingSchedule(&gb->timing, &gb->memory.hdmaEvent, 0); } else if (gb->memory.isHdma && !GBRegisterLCDCIsEnable(gb->memory.io[REG_LCDC])) { return 0x80 | ((value + 1) & 0x7F); } return value & 0x7F; }
uint16_t GBAMGMQueryInput(struct GBARRContext* rr) { if (!rr->isPlaying(rr)) { return 0; } struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; if (mgm->peekedTag == TAG_INPUT) { _readTag(mgm, mgm->movieStream); } mgm->inputThisFrame = true; if (mgm->currentInput == INVALID_INPUT) { mLOG(GBA_RR, WARN, "Stream did not specify input"); } mLOG(GBA_RR, DEBUG, "Input replay: %03X", mgm->currentInput); return mgm->currentInput; }
void GBASavedataInitEEPROM(struct GBASavedata* savedata) { if (savedata->type == SAVEDATA_AUTODETECT) { savedata->type = SAVEDATA_EEPROM512; } else if (savedata->type != SAVEDATA_EEPROM512 && savedata->type != SAVEDATA_EEPROM) { mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata"); return; } int32_t eepromSize = SIZE_CART_EEPROM512; if (savedata->type == SAVEDATA_EEPROM) { eepromSize = SIZE_CART_EEPROM; } off_t end; if (!savedata->vf) { end = 0; savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM); } else { end = savedata->vf->size(savedata->vf); if (end < eepromSize) { savedata->vf->truncate(savedata->vf, eepromSize); } else if (end >= SIZE_CART_EEPROM) { eepromSize = SIZE_CART_EEPROM; savedata->type = SAVEDATA_EEPROM; } savedata->data = savedata->vf->map(savedata->vf, eepromSize, savedata->mapMode); } if (end < SIZE_CART_EEPROM512) { memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM512 - end); } }
bool _loadStream(struct GBAMGMContext* mgm, uint32_t streamId) { if (mgm->movieStream && !mgm->movieStream->close(mgm->movieStream)) { return false; } mgm->movieStream = 0; mgm->streamId = streamId; mgm->currentInput = INVALID_INPUT; char buffer[14]; snprintf(buffer, sizeof(buffer), "%u" BINARY_EXT, streamId); if (mgm->d.isRecording(&mgm->d)) { int flags = O_CREAT | O_RDWR; if (streamId > mgm->maxStreamId) { flags |= O_TRUNC; } mgm->movieStream = mgm->streamDir->openFile(mgm->streamDir, buffer, flags); } else if (mgm->d.isPlaying(&mgm->d)) { mgm->movieStream = mgm->streamDir->openFile(mgm->streamDir, buffer, O_RDONLY); mgm->peekedTag = TAG_INVALID; if (!mgm->movieStream || !_verifyMagic(mgm, mgm->movieStream) || !_seekTag(mgm, mgm->movieStream, TAG_BEGIN)) { mgm->d.stopPlaying(&mgm->d); } } mLOG(GBA_RR, DEBUG, "Loading segment: %u", streamId); mgm->d.frames = 0; mgm->d.lagFrames = 0; return true; }
void GBASavedataInitFlash(struct GBASavedata* savedata) { if (savedata->type == SAVEDATA_AUTODETECT) { savedata->type = SAVEDATA_FLASH512; } if (savedata->type != SAVEDATA_FLASH512 && savedata->type != SAVEDATA_FLASH1M) { mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata"); return; } int32_t flashSize = SIZE_CART_FLASH512; if (savedata->type == SAVEDATA_FLASH1M) { flashSize = SIZE_CART_FLASH1M; } off_t end; if (!savedata->vf) { end = 0; savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M); } else { end = savedata->vf->size(savedata->vf); if (end < flashSize) { savedata->vf->truncate(savedata->vf, flashSize); } else if (end >= SIZE_CART_FLASH1M) { flashSize = SIZE_CART_FLASH1M; savedata->type = SAVEDATA_FLASH1M; } savedata->data = savedata->vf->map(savedata->vf, flashSize, savedata->mapMode); } savedata->currentBank = savedata->data; if (end < SIZE_CART_FLASH512) { memset(&savedata->data[end], 0xFF, flashSize - end); } }
static void _GBMBCNone(struct GB* gb, uint16_t address, uint8_t value) { UNUSED(gb); UNUSED(address); UNUSED(value); mLOG(GB_MBC, GAME_ERROR, "Wrote to invalid MBC"); }
void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) { struct GBMemory* memory = &gb->memory; int bank = value & 0x1F; switch (address >> 13) { case 0x0: switch (value) { case 0: memory->sramAccess = false; break; case 0xA: memory->sramAccess = true; GBMBCSwitchSramBank(gb, memory->sramCurrentBank); break; default: // TODO mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value); break; } break; case 0x1: if (!bank) { ++bank; } GBMBCSwitchBank(gb, bank | (memory->currentBank & 0x60)); break; case 0x2: bank &= 3; if (!memory->mbcState.mbc1.mode) { GBMBCSwitchBank(gb, (bank << 5) | (memory->currentBank & 0x1F)); } else { GBMBCSwitchSramBank(gb, bank); } break; case 0x3: memory->mbcState.mbc1.mode = value & 1; if (memory->mbcState.mbc1.mode) { GBMBCSwitchBank(gb, memory->currentBank & 0x1F); } else { GBMBCSwitchSramBank(gb, 0); } break; default: // TODO mLOG(GB_MBC, STUB, "MBC1 unknown address: %04X:%02X", address, value); break; } }
void GBResizeSram(struct GB* gb, size_t size) { if (gb->memory.sram && size <= gb->sramSize) { return; } mLOG(GB, INFO, "Resizing SRAM to %"PRIz"u bytes", size); struct VFile* vf = gb->sramVf; if (vf) { if (vf == gb->sramRealVf) { ssize_t vfSize = vf->size(vf); if (vfSize >= 0 && (size_t) vfSize < size) { uint8_t extdataBuffer[0x100]; if (vfSize & 0xFF) { vf->seek(vf, -(vfSize & 0xFF), SEEK_END); vf->read(vf, extdataBuffer, vfSize & 0xFF); } if (gb->memory.sram) { vf->unmap(vf, gb->memory.sram, gb->sramSize); } vf->truncate(vf, size + (vfSize & 0xFF)); if (vfSize & 0xFF) { vf->seek(vf, size, SEEK_SET); vf->write(vf, extdataBuffer, vfSize & 0xFF); } gb->memory.sram = vf->map(vf, size, MAP_WRITE); memset(&gb->memory.sram[gb->sramSize], 0xFF, size - gb->sramSize); } else if (size > gb->sramSize || !gb->memory.sram) { if (gb->memory.sram) { vf->unmap(vf, gb->memory.sram, gb->sramSize); } gb->memory.sram = vf->map(vf, size, MAP_WRITE); } } else { if (gb->memory.sram) { vf->unmap(vf, gb->memory.sram, gb->sramSize); } gb->memory.sram = vf->map(vf, size, MAP_READ); } if (gb->memory.sram == (void*) -1) { gb->memory.sram = NULL; } } else { uint8_t* newSram = anonymousMemoryMap(size); if (gb->memory.sram) { if (size > gb->sramSize) { memcpy(newSram, gb->memory.sram, gb->sramSize); memset(&newSram[gb->sramSize], 0xFF, size - gb->sramSize); } else { memcpy(newSram, gb->memory.sram, size); } mappedMemoryFree(gb->memory.sram, gb->sramSize); } else { memset(newSram, 0xFF, size); } gb->memory.sram = newSram; } if (gb->sramSize < size) { gb->sramSize = size; } }
uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) { struct GB* gb = (struct GB*) cpu->master; struct GBMemory* memory = &gb->memory; switch (address >> 12) { case GB_REGION_CART_BANK0: case GB_REGION_CART_BANK0 + 1: case GB_REGION_CART_BANK0 + 2: case GB_REGION_CART_BANK0 + 3: return memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)]; case GB_REGION_CART_BANK1: case GB_REGION_CART_BANK1 + 1: case GB_REGION_CART_BANK1 + 2: case GB_REGION_CART_BANK1 + 3: return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)]; case GB_REGION_VRAM: case GB_REGION_VRAM + 1: return gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)]; case GB_REGION_EXTERNAL_RAM: case GB_REGION_EXTERNAL_RAM + 1: if (memory->rtcAccess) { return memory->rtcRegs[memory->activeRtcReg]; } else if (memory->sramAccess) { return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)]; } else if (memory->mbcType == GB_MBC7) { return GBMBC7Read(memory, address); } else if (memory->mbcType == GB_HuC3) { return 0x01; // TODO: Is this supposed to be the current SRAM bank? } return 0xFF; case GB_REGION_WORKING_RAM_BANK0: case GB_REGION_WORKING_RAM_BANK0 + 2: return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; case GB_REGION_WORKING_RAM_BANK1: return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; default: if (address < GB_BASE_OAM) { return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; } if (address < GB_BASE_UNUSABLE) { if (gb->video.mode < 2) { return gb->video.oam.raw[address & 0xFF]; } return 0xFF; } if (address < GB_BASE_IO) { mLOG(GB_MEM, GAME_ERROR, "Attempt to read from unusable memory: %04X", address); return 0xFF; } if (address < GB_BASE_HRAM) { return GBIORead(gb, address & (GB_SIZE_IO - 1)); } if (address < GB_BASE_IE) { return memory->hram[address & GB_SIZE_HRAM]; } return GBIORead(gb, REG_IE); } }
//============================================================================// int main() { EC_OS g_os; EC_WIDGET g_wdgt; EC_RENDER g_render; mLOG("Starting"); g_wdgt.fOnInit(L"VSGE"); g_wdgt.fRectSet(200, 200, 1024, 768); g_wdgt.fWdgtCreate(false); g_wdgt.fWdgtShow(); EC_RENDER::INIT_STRUCT ini_str; ini_str.wdgt = g_wdgt.fHandlerGet(); ini_str.bb_size.fClear(); ES_DRAW_DATA draw_data; draw_data.fOnInitIndexedQuad( -1024/2,-768/2, 1024, 768, false, true, false); draw_data.fVertexColorSet(0, ECOLOR_BLUE); draw_data.fVertexColorSet(1, ECOLOR_BLUE); draw_data.fVertexColorSet(2, ECOLOR_BLUE); draw_data.fVertexColorSet(3, ECOLOR_BLUE); ES_DRAW_DATA ano_data; ano_data.fOnInitIndexedQuad(0,0,2,2,false,false,false); ES_DRAW_OPTIONS draw_opt; draw_opt.fClear(); draw_opt.fDiffuseSet(true); g_render.fOnInit(&ini_str); g_render.fEyeSet(0,0,1000,0,1,0,0,0,0); g_render.fProjectionPerspectiveSet(1024,768); static int clcl = 0; while(true) {//1 g_os.fOnUpdate(); g_render.fFrameClear(true, clcl,false,0,false ,0); if(EDONE == g_render.fFrameLock()) {//1 g_render.fDraw(&draw_data, &draw_opt); g_render.fDraw(&ano_data, &draw_opt); g_render.fFrameUnlock(); }//1 g_render.fFramePresent(); clcl++; }//1 return EAPPNOERROR; }
void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASIOMode mode) { struct GBASIODriver** driverLoc; switch (mode) { case SIO_NORMAL_8: case SIO_NORMAL_32: driverLoc = &sio->drivers.normal; break; case SIO_MULTI: driverLoc = &sio->drivers.multiplayer; break; case SIO_JOYBUS: driverLoc = &sio->drivers.joybus; break; default: mLOG(GBA_SIO, ERROR, "Setting an unsupported SIO driver: %x", mode); return; } if (*driverLoc) { if ((*driverLoc)->unload) { (*driverLoc)->unload(*driverLoc); } if ((*driverLoc)->deinit) { (*driverLoc)->deinit(*driverLoc); } } if (driver) { driver->p = sio; if (driver->init) { if (!driver->init(driver)) { driver->deinit(driver); mLOG(GBA_SIO, ERROR, "Could not initialize SIO driver"); return; } } if (sio->mode == mode) { sio->activeDriver = driver; if (driver->load) { driver->load(driver); } } } *driverLoc = driver; }
void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) { struct GB* gb = (struct GB*) cpu->master; struct GBMemory* memory = &gb->memory; switch (address >> 12) { case GB_REGION_CART_BANK0: case GB_REGION_CART_BANK0 + 1: case GB_REGION_CART_BANK0 + 2: case GB_REGION_CART_BANK0 + 3: case GB_REGION_CART_BANK1: case GB_REGION_CART_BANK1 + 1: case GB_REGION_CART_BANK1 + 2: case GB_REGION_CART_BANK1 + 3: memory->mbc(gb, address, value); cpu->memory.setActiveRegion(cpu, cpu->pc); return; case GB_REGION_VRAM: case GB_REGION_VRAM + 1: gb->video.renderer->writeVRAM(gb->video.renderer, (address & (GB_SIZE_VRAM_BANK0 - 1)) | (GB_SIZE_VRAM_BANK0 * gb->video.vramCurrentBank)); gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)] = value; return; case GB_REGION_EXTERNAL_RAM: case GB_REGION_EXTERNAL_RAM + 1: if (memory->rtcAccess) { memory->rtcRegs[memory->activeRtcReg] = value; } else if (memory->sramAccess) { memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value; } else if (memory->mbcType == GB_MBC7) { GBMBC7Write(memory, address, value); } gb->sramDirty |= GB_SRAM_DIRT_NEW; return; case GB_REGION_WORKING_RAM_BANK0: case GB_REGION_WORKING_RAM_BANK0 + 2: memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; return; case GB_REGION_WORKING_RAM_BANK1: memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; return; default: if (address < GB_BASE_OAM) { memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; } else if (address < GB_BASE_UNUSABLE) { if (gb->video.mode < 2) { gb->video.oam.raw[address & 0xFF] = value; } } else if (address < GB_BASE_IO) { mLOG(GB_MEM, GAME_ERROR, "Attempt to write to unusable memory: %04X:%02X", address, value); } else if (address < GB_BASE_HRAM) { GBIOWrite(gb, address & (GB_SIZE_IO - 1), value); } else if (address < GB_BASE_IE) { memory->hram[address & GB_SIZE_HRAM] = value; } else { GBIOWrite(gb, REG_IE, value); } } }
void mCoreTakeScreenshot(struct mCore* core) { #ifdef USE_PNG size_t stride; const void* pixels = 0; unsigned width, height; core->desiredVideoDimensions(core, &width, &height); struct VFile* vf; #ifndef PSP2 vf = VDirFindNextAvailable(core->dirs.screenshot, core->dirs.baseName, "-", ".png", O_CREAT | O_TRUNC | O_WRONLY); #else vf = VFileMemChunk(0, 0); #endif bool success = false; if (vf) { core->getPixels(core, &pixels, &stride); png_structp png = PNGWriteOpen(vf); png_infop info = PNGWriteHeader(png, width, height); success = PNGWritePixels(png, width, height, stride, pixels); PNGWriteClose(png, info); #ifdef PSP2 void* data = vf->map(vf, 0, 0); PhotoExportParam param = { 0, NULL, NULL, NULL, { 0 } }; scePhotoExportFromData(data, vf->size(vf), ¶m, NULL, NULL, NULL, NULL, 0); #endif vf->close(vf); } if (success) { mLOG(STATUS, INFO, "Screenshot saved"); return; } #else UNUSED(core); #endif mLOG(STATUS, WARN, "Failed to take screenshot"); }
void _GBMBC5(struct GB* gb, uint16_t address, uint8_t value) { struct GBMemory* memory = &gb->memory; int bank; switch (address >> 12) { case 0x0: case 0x1: switch (value) { case 0: memory->sramAccess = false; break; case 0xA: memory->sramAccess = true; GBMBCSwitchSramBank(gb, memory->sramCurrentBank); break; default: // TODO mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value); break; } break; case 0x2: bank = (memory->currentBank & 0x100) | value; GBMBCSwitchBank(gb, bank); break; case 0x3: bank = (memory->currentBank & 0xFF) | ((value & 1) << 8); GBMBCSwitchBank(gb, bank); break; case 0x4: case 0x5: if (memory->mbcType == GB_MBC5_RUMBLE && memory->rumble) { memory->rumble->setRumble(memory->rumble, (value >> 3) & 1); value &= ~8; } GBMBCSwitchSramBank(gb, value & 0xF); break; default: // TODO mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value); break; }
void GBAMGMNextFrame(struct GBARRContext* rr) { if (!rr->isRecording(rr) && !rr->isPlaying(rr)) { return; } struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; if (rr->isPlaying(rr)) { while (mgm->peekedTag == TAG_INPUT) { _readTag(mgm, mgm->movieStream); mLOG(GBA_RR, WARN, "Desync detected!"); } if (mgm->peekedTag == TAG_LAG) { mLOG(GBA_RR, DEBUG, "Lag frame marked in stream"); if (mgm->inputThisFrame) { mLOG(GBA_RR, WARN, "Lag frame in stream does not match movie"); } } } ++mgm->d.frames; mLOG(GBA_RR, DEBUG, "Frame: %u", mgm->d.frames); if (!mgm->inputThisFrame) { ++mgm->d.lagFrames; mLOG(GBA_RR, DEBUG, "Lag frame: %u", mgm->d.lagFrames); } if (rr->isRecording(rr)) { if (!mgm->inputThisFrame) { _emitTag(mgm, mgm->movieStream, TAG_LAG); } _emitTag(mgm, mgm->movieStream, TAG_FRAME); mgm->inputThisFrame = false; } else { if (!_seekTag(mgm, mgm->movieStream, TAG_FRAME)) { _streamEndReached(mgm); } } }
void GBSramClean(struct GB* gb, uint32_t frameCount) { // TODO: Share with GBASavedataClean if (!gb->sramVf) { return; } if (gb->sramDirty & GB_SRAM_DIRT_NEW) { gb->sramDirtAge = frameCount; gb->sramDirty &= ~GB_SRAM_DIRT_NEW; if (!(gb->sramDirty & GB_SRAM_DIRT_SEEN)) { gb->sramDirty |= GB_SRAM_DIRT_SEEN; } } else if ((gb->sramDirty & GB_SRAM_DIRT_SEEN) && frameCount - gb->sramDirtAge > CLEANUP_THRESHOLD) { if (gb->memory.mbcType == GB_MBC3_RTC) { GBMBCRTCWrite(gb); } gb->sramDirty = 0; if (gb->memory.sram && gb->sramVf->sync(gb->sramVf, gb->memory.sram, gb->sramSize)) { mLOG(GB_MEM, INFO, "Savedata synced"); } else { mLOG(GB_MEM, INFO, "Savedata failed to sync!"); } } }
void GBAMGMLogInput(struct GBARRContext* rr, uint16_t keys) { if (!rr->isRecording(rr)) { return; } struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; if (keys != mgm->currentInput) { _emitTag(mgm, mgm->movieStream, TAG_INPUT); mgm->movieStream->write(mgm->movieStream, &keys, sizeof(keys)); mgm->currentInput = keys; } mLOG(GBA_RR, DEBUG, "Input log: %03X", mgm->currentInput); mgm->inputThisFrame = true; }
void GBMBCSwitchBank(struct GB* gb, int bank) { size_t bankStart = bank * GB_SIZE_CART_BANK0; if (bankStart + GB_SIZE_CART_BANK0 > gb->memory.romSize) { mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank); bankStart &= (gb->memory.romSize - 1); bank = bankStart / GB_SIZE_CART_BANK0; if (!bank) { ++bank; } } gb->memory.romBank = &gb->memory.rom[bankStart]; gb->memory.currentBank = bank; if (gb->cpu->pc < GB_BASE_VRAM) { gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc); } }
bool GBSIOLockstepNodeInit(struct GBSIODriver* driver) { struct GBSIOLockstepNode* node = (struct GBSIOLockstepNode*) driver; mLOG(GB_SIO, DEBUG, "Lockstep %i: Node init", node->id); node->event.context = node; node->event.name = "GB SIO Lockstep"; node->event.callback = _GBSIOLockstepNodeProcessEvents; node->event.priority = 0x80; node->nextEvent = 0; node->eventDiff = 0; mTimingSchedule(&driver->p->p->timing, &node->event, 0); #ifndef NDEBUG node->phase = node->p->d.transferActive; node->transferId = node->p->d.transferId; #endif return true; }
void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) { struct GBMemory* memory = &gb->memory; int bank = value & 0x7F; switch (address >> 13) { case 0x0: switch (value) { case 0: memory->sramAccess = false; break; case 0xA: memory->sramAccess = true; GBMBCSwitchSramBank(gb, memory->sramCurrentBank); break; default: // TODO mLOG(GB_MBC, STUB, "MBC3 unknown value %02X", value); break; } break; case 0x1: if (!bank) { ++bank; } GBMBCSwitchBank(gb, bank); break; case 0x2: if (value < 4) { GBMBCSwitchSramBank(gb, value); memory->rtcAccess = false; } else if (value >= 8 && value <= 0xC) { memory->activeRtcReg = value - 8; memory->rtcAccess = true; } break; case 0x3: if (memory->rtcLatched && value == 0) { memory->rtcLatched = false; } else if (!memory->rtcLatched && value == 1) { _latchRtc(gb->memory.rtc, gb->memory.rtcRegs, &gb->memory.rtcLastLatch); memory->rtcLatched = true; } break; } }
void GBVideoProcessDots(struct GBVideo* video) { if (video->mode != 3 || video->dotCounter < 0) { return; } int oldX = video->x; video->x = video->dotCounter + video->eventDiff + (video->p->cpu->cycles >> video->p->doubleSpeed); if (video->x > GB_VIDEO_HORIZONTAL_PIXELS) { video->x = GB_VIDEO_HORIZONTAL_PIXELS; } else if (video->x < 0) { mLOG(GB, FATAL, "Video dot clock went negative!"); video->x = oldX; } if (video->x == GB_VIDEO_HORIZONTAL_PIXELS) { video->dotCounter = INT_MIN; } if (video->frameskipCounter <= 0) { video->renderer->drawRange(video->renderer, oldX, video->x, video->ly, video->objThisLine, video->objMax); } }
void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) { gb->memory.hdmaSource = gb->memory.io[REG_HDMA1] << 8; gb->memory.hdmaSource |= gb->memory.io[REG_HDMA2]; gb->memory.hdmaDest = gb->memory.io[REG_HDMA3] << 8; gb->memory.hdmaDest |= gb->memory.io[REG_HDMA4]; gb->memory.hdmaSource &= 0xFFF0; if (gb->memory.hdmaSource >= 0x8000 && gb->memory.hdmaSource < 0xA000) { mLOG(GB_MEM, GAME_ERROR, "Invalid HDMA source: %04X", gb->memory.hdmaSource); return; } gb->memory.hdmaDest &= 0x1FF0; gb->memory.hdmaDest |= 0x8000; bool wasHdma = gb->memory.isHdma; gb->memory.isHdma = value & 0x80; if (!wasHdma && !gb->memory.isHdma) { gb->memory.hdmaRemaining = ((value & 0x7F) + 1) * 0x10; gb->memory.hdmaNext = gb->cpu->cycles; gb->cpu->nextEvent = gb->cpu->cycles; } }