Exemple #1
0
bool GBASDLInitAudio(struct GBASDLAudio* context, struct GBAThread* threadContext) {
	if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
		GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system");
		return false;
	}

	context->desiredSpec.freq = 44100;
	context->desiredSpec.format = AUDIO_S16SYS;
	context->desiredSpec.channels = 2;
	context->desiredSpec.samples = context->samples;
	context->desiredSpec.callback = _GBASDLAudioCallback;
	context->desiredSpec.userdata = context;
#if RESAMPLE_LIBRARY == RESAMPLE_NN
	context->drift = 0.f;
#endif
	if (SDL_OpenAudio(&context->desiredSpec, &context->obtainedSpec) < 0) {
		GBALog(0, GBA_LOG_ERROR, "Could not open SDL sound system");
		return false;
	}
	context->thread = threadContext;
	context->samples = context->obtainedSpec.samples;
	float ratio = GBAAudioCalculateRatio(0x8000, threadContext->fpsTarget, 44100);
	threadContext->audioBuffers = context->samples / ratio;
	if (context->samples > threadContext->audioBuffers) {
		threadContext->audioBuffers = context->samples * 2;
	}

	SDL_PauseAudio(0);
	return true;
}
Exemple #2
0
bool GBASDLInitAudio(struct GBASDLAudio* context, struct GBAThread* threadContext) {
	if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
		GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system: %s", SDL_GetError());
		return false;
	}

	context->desiredSpec.freq = 44100;
	context->desiredSpec.format = AUDIO_S16SYS;
	context->desiredSpec.channels = 2;
	context->desiredSpec.samples = context->samples;
	context->desiredSpec.callback = _GBASDLAudioCallback;
	context->desiredSpec.userdata = context;
#if RESAMPLE_LIBRARY == RESAMPLE_NN
	context->drift = 0.f;
#endif

#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
		GBALog(0, GBA_LOG_ERROR, "Could not open SDL sound system");
		return false;
	}
	context->thread = threadContext;
	context->samples = context->obtainedSpec.samples;
	float ratio = GBAAudioCalculateRatio(0x8000, threadContext->fpsTarget, 44100);
	threadContext->audioBuffers = context->samples / ratio;
	if (context->samples > threadContext->audioBuffers) {
		threadContext->audioBuffers = context->samples * 2;
	}

#if SDL_VERSION_ATLEAST(2, 0, 0)
	SDL_PauseAudioDevice(context->deviceId, 0);
#else
	SDL_PauseAudio(0);
#endif
	return true;
}

void GBASDLDeinitAudio(struct GBASDLAudio* 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);
}
Exemple #3
0
static uint16_t GBASIOLockstepNodeWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
    struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver;
    if (address == REG_SIOCNT) {
        GBALog(node->d.p->p, GBA_LOG_SIO, "Lockstep %i: SIOCNT <- %04x", node->id, value);
        if (value & 0x0080) {
            if (!node->id) {
                GBALog(node->d.p->p, GBA_LOG_SIO, "Lockstep %i: Transfer initiated", node->id);
                MutexLock(&node->p->mutex);
                node->p->transferActive = true;
                node->p->transferCycles = GBASIOCyclesPerTransfer[node->d.p->multiplayerControl.baud][node->p->attached - 1];
                node->multiSend = node->d.p->p->memory.io[REG_SIOMLT_SEND >> 1];
                MutexUnlock(&node->p->mutex);
            } else {
Exemple #4
0
bool GBASaveState(struct GBAThread* threadContext, struct VDir* dir, int slot, bool screenshot) {
	struct VFile* vf = GBAGetState(threadContext->gba, dir, slot, true);
	if (!vf) {
		return false;
	}
	bool success = GBASaveStateNamed(threadContext->gba, vf, screenshot);
	vf->close(vf);
	if (success) {
		GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i saved", slot);
	} else {
		GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i failed to save", slot);
	}
	return success;
}
Exemple #5
0
bool GBALoadState(struct GBAThread* threadContext, struct VDir* dir, int slot) {
	struct VFile* vf = GBAGetState(threadContext->gba, dir, slot, false);
	if (!vf) {
		return false;
	}
	threadContext->rewindBufferSize = 0;
	bool success = GBALoadStateNamed(threadContext->gba, vf);
	vf->close(vf);
	if (success) {
		GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i loaded", slot);
	} else {
		GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i failed to load", slot);
	}
	return success;
}
Exemple #6
0
uint16_t GBARRQueryInput(struct GBARRContext* rr) {
	if (!GBARRIsPlaying(rr)) {
		return 0;
	}

	if (rr->peekedTag == TAG_INPUT) {
		_readTag(rr, rr->movieStream);
	}
	rr->inputThisFrame = true;
	if (rr->currentInput == INVALID_INPUT) {
		GBALog(0, GBA_LOG_WARN, "[RR] Stream did not specify input");
	}
	GBALog(0, GBA_LOG_DEBUG, "[RR] Input replay: %03X", rr->currentInput);
	return rr->currentInput;
}
Exemple #7
0
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) {
		GBALog(0, GBA_LOG_WARN, "[RR] Stream did not specify input");
	}
	GBALog(0, GBA_LOG_DEBUG, "[RR] Input replay: %03X", mgm->currentInput);
	return mgm->currentInput;
}
Exemple #8
0
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);
		}
	}
	GBALog(0, GBA_LOG_DEBUG, "[RR] Loading segment: %u", streamId);
	mgm->d.frames = 0;
	mgm->d.lagFrames = 0;
	return true;
}
Exemple #9
0
bool GBARRLoadStream(struct GBARRContext* rr, uint32_t streamId) {
	if (rr->movieStream && !rr->movieStream->close(rr->movieStream)) {
		return false;
	}
	rr->movieStream = 0;
	rr->streamId = streamId;
	rr->currentInput = INVALID_INPUT;
	char buffer[14];
	snprintf(buffer, sizeof(buffer), "%u" BINARY_EXT, streamId);
	if (GBARRIsRecording(rr)) {
		int flags = O_CREAT | O_RDWR;
		if (streamId > rr->maxStreamId) {
			flags |= O_TRUNC;
		}
		rr->movieStream = rr->streamDir->openFile(rr->streamDir, buffer, flags);
	} else if (GBARRIsPlaying(rr)) {
		rr->movieStream = rr->streamDir->openFile(rr->streamDir, buffer, O_RDONLY);
		rr->peekedTag = TAG_INVALID;
		if (!rr->movieStream || !_verifyMagic(rr, rr->movieStream) || !_seekTag(rr, rr->movieStream, TAG_BEGIN)) {
			GBARRStopPlaying(rr);
		}
	}
	GBALog(0, GBA_LOG_DEBUG, "[RR] Loading segment: %u", streamId);
	rr->frames = 0;
	rr->lagFrames = 0;
	return true;
}
Exemple #10
0
bool GBASIOLockstepNodeInit(struct GBASIODriver* driver) {
    struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver;
    node->nextEvent = LOCKSTEP_INCREMENT;
    node->d.p->multiplayerControl.slave = node->id > 0;
    GBALog(node->d.p->p, GBA_LOG_SIO, "Lockstep %i: Node init", node->id);
    return true;
}
Exemple #11
0
void _rtcProcessByte(struct GBACartridgeHardware* hw) {
	--hw->rtc.bytesRemaining;
	if (!hw->rtc.commandActive) {
		union RTCCommandData command;
		command.packed = hw->rtc.bits;
		if (command.magic == 0x06) {
			hw->rtc.command = command;

			hw->rtc.bytesRemaining = RTC_BYTES[hw->rtc.command.command];
			hw->rtc.commandActive = hw->rtc.bytesRemaining > 0;
			switch (command.command) {
			case RTC_RESET:
				hw->rtc.control.packed = 0;
				break;
			case RTC_DATETIME:
			case RTC_TIME:
				_rtcUpdateClock(hw);
				break;
			case RTC_FORCE_IRQ:
			case RTC_CONTROL:
				break;
			}
		} else {
			GBALog(hw->p, GBA_LOG_WARN, "Invalid RTC command byte: %02X", hw->rtc.bits);
		}
	} else {
		switch (hw->rtc.command.command) {
		case RTC_CONTROL:
			hw->rtc.control.packed = hw->rtc.bits;
			break;
		case RTC_FORCE_IRQ:
			GBALog(hw->p, GBA_LOG_STUB, "Unimplemented RTC command %u", hw->rtc.command.command);
			break;
		case RTC_RESET:
		case RTC_DATETIME:
		case RTC_TIME:
			break;
		}
	}

	hw->rtc.bits = 0;
	hw->rtc.bitsRead = 0;
	if (!hw->rtc.bytesRemaining) {
		hw->rtc.commandActive = 0;
		hw->rtc.command.reading = 0;
	}
}
Exemple #12
0
void GBATakeScreenshot(struct GBA* gba, struct VDir* dir) {
#ifdef USE_PNG
	unsigned stride;
	const void* pixels = 0;
	struct VFile* vf = VDirOptionalOpenIncrementFile(dir, gba->activeFile, "screenshot", "-", ".png", O_CREAT | O_TRUNC | O_WRONLY);
	bool success = false;
	if (vf) {
		gba->video.renderer->getPixels(gba->video.renderer, &stride, &pixels);
		png_structp png = PNGWriteOpen(vf);
		png_infop info = PNGWriteHeader(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
		success = PNGWritePixels(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, stride, pixels);
		PNGWriteClose(png, info);
		vf->close(vf);
	}
	if (success) {
		GBALog(gba, GBA_LOG_STATUS, "Screenshot saved");
		return;
	}
#endif
	GBALog(gba, GBA_LOG_STATUS, "Failed to take screenshot");
}
Exemple #13
0
void GBARRLogInput(struct GBARRContext* rr, uint16_t keys) {
	if (!GBARRIsRecording(rr)) {
		return;
	}

	if (keys != rr->currentInput) {
		_emitTag(rr, rr->movieStream, TAG_INPUT);
		rr->movieStream->write(rr->movieStream, &keys, sizeof(keys));
		rr->currentInput = keys;
	}
	GBALog(0, GBA_LOG_DEBUG, "[RR] Input log: %03X", rr->currentInput);
	rr->inputThisFrame = true;
}
Exemple #14
0
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);
			GBALog(0, GBA_LOG_WARN, "[RR] Desync detected!");
		}
		if (mgm->peekedTag == TAG_LAG) {
			GBALog(0, GBA_LOG_DEBUG, "[RR] Lag frame marked in stream");
			if (mgm->inputThisFrame) {
				GBALog(0, GBA_LOG_WARN, "[RR] Lag frame in stream does not match movie");
			}
		}
	}

	++mgm->d.frames;
	GBALog(0, GBA_LOG_DEBUG, "[RR] Frame: %u", mgm->d.frames);
	if (!mgm->inputThisFrame) {
		++mgm->d.lagFrames;
		GBALog(0, GBA_LOG_DEBUG, "[RR] 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);
		}
	}
}
Exemple #15
0
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;
	}
	GBALog(0, GBA_LOG_DEBUG, "[RR] Input log: %03X", mgm->currentInput);
	mgm->inputThisFrame = true;
}
Exemple #16
0
bool _incrementStream(struct GBAMGMContext* mgm, bool recursive) {
	uint32_t newStreamId = mgm->maxStreamId + 1;
	uint32_t oldStreamId = mgm->streamId;
	if (mgm->d.isRecording(&mgm->d) && mgm->movieStream) {
		if (!_markStreamNext(mgm, newStreamId, recursive)) {
			return false;
		}
	}
	if (!_loadStream(mgm, newStreamId)) {
		return false;
	}
	GBALog(0, GBA_LOG_DEBUG, "[RR] New segment: %u", newStreamId);
	_emitMagic(mgm, mgm->movieStream);
	mgm->maxStreamId = newStreamId;
	_emitTag(mgm, mgm->movieStream, TAG_PREVIOUSLY);
	mgm->movieStream->write(mgm->movieStream, &oldStreamId, sizeof(oldStreamId));
	_emitTag(mgm, mgm->movieStream, TAG_BEGIN);

	mgm->metadataFile->seek(mgm->metadataFile, mgm->maxStreamIdOffset, SEEK_SET);
	mgm->metadataFile->write(mgm->metadataFile, &mgm->maxStreamId, sizeof(mgm->maxStreamId));
	mgm->previously = oldStreamId;
	return true;
}
Exemple #17
0
bool GBARRIncrementStream(struct GBARRContext* rr, bool recursive) {
	uint32_t newStreamId = rr->maxStreamId + 1;
	uint32_t oldStreamId = rr->streamId;
	if (GBARRIsRecording(rr) && rr->movieStream) {
		if (!_markStreamNext(rr, newStreamId, recursive)) {
			return false;
		}
	}
	if (!GBARRLoadStream(rr, newStreamId)) {
		return false;
	}
	GBALog(0, GBA_LOG_DEBUG, "[RR] New segment: %u", newStreamId);
	_emitMagic(rr, rr->movieStream);
	rr->maxStreamId = newStreamId;
	_emitTag(rr, rr->movieStream, TAG_PREVIOUSLY);
	rr->movieStream->write(rr->movieStream, &oldStreamId, sizeof(oldStreamId));
	_emitTag(rr, rr->movieStream, TAG_BEGIN);

	rr->metadataFile->seek(rr->metadataFile, rr->maxStreamIdOffset, SEEK_SET);
	rr->metadataFile->write(rr->metadataFile, &rr->maxStreamId, sizeof(rr->maxStreamId));
	rr->previously = oldStreamId;
	return true;
}
Exemple #18
0
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:
		GBALog(hw->p, GBA_LOG_WARN, "Invalid GPIO address");
	}
	if (hw->readWrite) {
		uint16_t old = hw->gpioBase[0];
		old &= ~hw->direction;
		hw->gpioBase[0] = old | hw->pinState;
	} else {
		hw->gpioBase[0] = 0;
	}
}
Exemple #19
0
bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
	bool error = false;
	if (state->versionMagic != GBA_SAVESTATE_MAGIC) {
		GBALog(gba, GBA_LOG_WARN, "Invalid or too new savestate");
		error = true;
	}
	if (state->biosChecksum != gba->biosChecksum) {
		GBALog(gba, GBA_LOG_WARN, "Savestate created using a different version of the BIOS");
		if (state->cpu.gprs[ARM_PC] < SIZE_BIOS && state->cpu.gprs[ARM_PC] >= 0x20) {
			error = true;
		}
	}
	if (gba->memory.rom && (state->id != ((struct GBACartridge*) gba->memory.rom)->id || memcmp(state->title, ((struct GBACartridge*) gba->memory.rom)->title, sizeof(state->title)))) {
		GBALog(gba, GBA_LOG_WARN, "Savestate is for a different game");
		error = true;
	} else if (!gba->memory.rom && state->id != 0) {
		GBALog(gba, GBA_LOG_WARN, "Savestate is for a game, but no game loaded");
		error = true;
	}
	if (state->romCrc32 != gba->romCrc32) {
		GBALog(gba, GBA_LOG_WARN, "Savestate is for a different version of the game");
	}
	if (state->cpu.cycles < 0) {
		GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: CPU cycles are negative");
		error = true;
	}
	if (state->cpu.cycles >= (int32_t) GBA_ARM7TDMI_FREQUENCY) {
		GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: CPU cycles are too high");
		error = true;
	}
	if (state->video.eventDiff < 0) {
		GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: video eventDiff is negative");
		error = true;
	}
	int region = (state->cpu.gprs[ARM_PC] >> BASE_OFFSET);
	if ((region == REGION_CART0 || region == REGION_CART1 || region == REGION_CART2) && ((state->cpu.gprs[ARM_PC] - WORD_SIZE_ARM) & SIZE_CART0) >= gba->memory.romSize - WORD_SIZE_ARM) {
		GBALog(gba, GBA_LOG_WARN, "Savestate created using a differently sized version of the ROM");
		error = true;
	}
	if (error) {
		return false;
	}
	memcpy(gba->cpu->gprs, state->cpu.gprs, sizeof(gba->cpu->gprs));
	gba->cpu->cpsr = state->cpu.cpsr;
	gba->cpu->spsr = state->cpu.spsr;
	gba->cpu->cycles = state->cpu.cycles;
	gba->cpu->nextEvent = state->cpu.nextEvent;
	memcpy(gba->cpu->bankedRegisters, state->cpu.bankedRegisters, 6 * 7 * sizeof(int32_t));
	memcpy(gba->cpu->bankedSPSRs, state->cpu.bankedSPSRs, 6 * sizeof(int32_t));
	gba->cpu->privilegeMode = gba->cpu->cpsr.priv;
	gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
	if (state->biosPrefetch) {
		gba->memory.biosPrefetch = state->biosPrefetch;
	}
	if (gba->cpu->cpsr.t) {
		gba->cpu->executionMode = MODE_THUMB;
		if (state->cpuPrefetch[0] && state->cpuPrefetch[1]) {
			gba->cpu->prefetch[0] = state->cpuPrefetch[0] & 0xFFFF;
			gba->cpu->prefetch[1] = state->cpuPrefetch[1] & 0xFFFF;
		} else {
			// Maintain backwards compat
			LOAD_16(gba->cpu->prefetch[0], (gba->cpu->gprs[ARM_PC] - WORD_SIZE_THUMB) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);
			LOAD_16(gba->cpu->prefetch[1], (gba->cpu->gprs[ARM_PC]) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);
		}
	} else {
		gba->cpu->executionMode = MODE_ARM;
		if (state->cpuPrefetch[0] && state->cpuPrefetch[1]) {
			gba->cpu->prefetch[0] = state->cpuPrefetch[0];
			gba->cpu->prefetch[1] = state->cpuPrefetch[1];
		} else {
			// Maintain backwards compat
			LOAD_32(gba->cpu->prefetch[0], (gba->cpu->gprs[ARM_PC] - WORD_SIZE_ARM) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);
			LOAD_32(gba->cpu->prefetch[1], (gba->cpu->gprs[ARM_PC]) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);
		}
	}

	GBAMemoryDeserialize(&gba->memory, state);
	GBAIODeserialize(gba, state);
	GBAVideoDeserialize(&gba->video, state);
	GBAAudioDeserialize(&gba->audio, state);
	GBASavedataDeserialize(&gba->memory.savedata, state, false);

	if (gba->rr) {
		gba->rr->stateLoaded(gba->rr, state);
	}
	return true;
}
Exemple #20
0
bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) {
	char line[14] = "XXXXXXXX XXXX";
	snprintf(line, sizeof(line), "%08X %04X", op1, op2);
	GBACheatRegisterLine(cheats, line);

	enum GBACodeBreakerType type = op1 >> 28;
	struct GBACheat* cheat = 0;

	if (cheats->incompleteCheat) {
		cheats->incompleteCheat->repeat = op1 & 0xFFFF;
		cheats->incompleteCheat->addressOffset = op2;
		cheats->incompleteCheat->operandOffset = 0;
		cheats->incompleteCheat = 0;
		return true;
	}

	switch (type) {
	case CB_GAME_ID:
		// TODO: Run checksum
		return true;
	case CB_HOOK:
		if (cheats->hook) {
			return false;
		}
		cheats->hook = malloc(sizeof(*cheats->hook));
		cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
		cheats->hook->mode = MODE_THUMB;
		cheats->hook->refs = 1;
		cheats->hook->reentries = 0;
		return true;
	case CB_OR_2:
		cheat = GBACheatListAppend(&cheats->list);
		cheat->type = CHEAT_OR;
		cheat->width = 2;
		break;
	case CB_ASSIGN_1:
		cheat = GBACheatListAppend(&cheats->list);
		cheat->type = CHEAT_ASSIGN;
		cheat->width = 1;
		break;
	case CB_FILL:
		cheat = GBACheatListAppend(&cheats->list);
		cheat->type = CHEAT_ASSIGN;
		cheat->width = 2;
		cheats->incompleteCheat = cheat;
		break;
	case CB_FILL_8:
		GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
		return false;
	case CB_AND_2:
		cheat = GBACheatListAppend(&cheats->list);
		cheat->type = CHEAT_AND;
		cheat->width = 2;
		break;
	case CB_IF_EQ:
		cheat = GBACheatListAppend(&cheats->list);
		cheat->type = CHEAT_IF_EQ;
		cheat->width = 2;
		break;
	case CB_ASSIGN_2:
		cheat = GBACheatListAppend(&cheats->list);
		cheat->type = CHEAT_ASSIGN;
		cheat->width = 2;
		break;
	case CB_ENCRYPT:
		GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker encryption not supported");
		return false;
	case CB_IF_NE:
		cheat = GBACheatListAppend(&cheats->list);
		cheat->type = CHEAT_IF_NE;
		cheat->width = 2;
		break;
	case CB_IF_GT:
		cheat = GBACheatListAppend(&cheats->list);
		cheat->type = CHEAT_IF_GT;
		cheat->width = 2;
		break;
	case CB_IF_LT:
		cheat = GBACheatListAppend(&cheats->list);
		cheat->type = CHEAT_IF_LT;
		cheat->width = 2;
		break;
	case CB_IF_SPECIAL:
		switch (op1 & 0x0FFFFFFF) {
		case 0x20:
			cheat = GBACheatListAppend(&cheats->list);
			cheat->type = CHEAT_IF_AND;
			cheat->width = 2;
			cheat->address = BASE_IO | REG_JOYSTAT;
			cheat->operand = op2;
			cheat->repeat = 1;
			return true;
		default:
			GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
			return false;
		}
	case CB_ADD_2:
		cheat = GBACheatListAppend(&cheats->list);
		cheat->type = CHEAT_ADD;
		cheat->width = 2;
		break;
	case CB_IF_AND:
		cheat = GBACheatListAppend(&cheats->list);
		cheat->type = CHEAT_IF_AND;
		cheat->width = 2;
		break;
	}

	cheat->address = op1 & 0x0FFFFFFF;
	cheat->operand = op2;
	cheat->repeat = 1;
	cheat->negativeRepeat = 0;
	return true;
}
Exemple #21
0
void _rtcReadPins(struct GBACartridgeHardware* hw) {
	// Transfer sequence:
	// P: 0 | 1 |  2 | 3
	// == Initiate
	// > HI | - | LO | -
	// > HI | - | HI | -
	// == Transfer bit (x8)
	// > LO | x | HI | -
	// > HI | - | HI | -
	// < ?? | x | ?? | -
	// == Terminate
	// >  - | - | LO | -
	switch (hw->rtc.transferStep) {
	case 0:
		if ((hw->pinState & 5) == 1) {
			hw->rtc.transferStep = 1;
		}
		break;
	case 1:
		if ((hw->pinState & 5) == 5) {
			hw->rtc.transferStep = 2;
		}
		break;
	case 2:
		if (!hw->p0) {
			hw->rtc.bits &= ~(1 << hw->rtc.bitsRead);
			hw->rtc.bits |= hw->p1 << hw->rtc.bitsRead;
		} else {
			if (hw->p2) {
				// GPIO direction should always != reading
				if (hw->dir1) {
					if (hw->rtc.command.reading) {
						GBALog(hw->p, GBA_LOG_GAME_ERROR, "Attempting to write to RTC while in read mode");
					}
					++hw->rtc.bitsRead;
					if (hw->rtc.bitsRead == 8) {
						_rtcProcessByte(hw);
					}
				} else {
					_outputPins(hw, 5 | (_rtcOutput(hw) << 1));
					++hw->rtc.bitsRead;
					if (hw->rtc.bitsRead == 8) {
						--hw->rtc.bytesRemaining;
						if (hw->rtc.bytesRemaining <= 0) {
							hw->rtc.commandActive = 0;
							hw->rtc.command.reading = 0;
						}
						hw->rtc.bitsRead = 0;
					}
				}
			} else {
				hw->rtc.bitsRead = 0;
				hw->rtc.bytesRemaining = 0;
				hw->rtc.commandActive = 0;
				hw->rtc.command.reading = 0;
				hw->rtc.transferStep = 0;
			}
		}
		break;
	}
}