all repos — mgba @ 8636b81f13514538200a7113304cce7fb87261c9

mGBA Game Boy Advance Emulator

src/gba/cheats/codebreaker.c (view raw)

  1/* Copyright (c) 2013-2015 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "gba/cheats.h"
  7
  8#include "gba/cheats/cheats-private.h"
  9#include "gba/gba.h"
 10#include "gba/io.h"
 11#include "util/string.h"
 12
 13bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) {
 14	char line[14] = "XXXXXXXX XXXX";
 15	snprintf(line, sizeof(line), "%08X %04X", op1, op2);
 16	GBACheatRegisterLine(cheats, line);
 17
 18	enum GBACodeBreakerType type = op1 >> 28;
 19	struct GBACheat* cheat = 0;
 20
 21	if (cheats->incompleteCheat) {
 22		cheats->incompleteCheat->repeat = op1 & 0xFFFF;
 23		cheats->incompleteCheat->addressOffset = op2;
 24		cheats->incompleteCheat->operandOffset = 0;
 25		cheats->incompleteCheat = 0;
 26		return true;
 27	}
 28
 29	switch (type) {
 30	case CB_GAME_ID:
 31		// TODO: Run checksum
 32		return true;
 33	case CB_HOOK:
 34		if (cheats->hook) {
 35			return false;
 36		}
 37		cheats->hook = malloc(sizeof(*cheats->hook));
 38		cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
 39		cheats->hook->mode = MODE_THUMB;
 40		cheats->hook->refs = 1;
 41		cheats->hook->reentries = 0;
 42		return true;
 43	case CB_OR_2:
 44		cheat = GBACheatListAppend(&cheats->list);
 45		cheat->type = CHEAT_OR;
 46		cheat->width = 2;
 47		break;
 48	case CB_ASSIGN_1:
 49		cheat = GBACheatListAppend(&cheats->list);
 50		cheat->type = CHEAT_ASSIGN;
 51		cheat->width = 1;
 52		break;
 53	case CB_FILL:
 54		cheat = GBACheatListAppend(&cheats->list);
 55		cheat->type = CHEAT_ASSIGN;
 56		cheat->width = 2;
 57		cheats->incompleteCheat = cheat;
 58		break;
 59	case CB_FILL_8:
 60		GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
 61		return false;
 62	case CB_AND_2:
 63		cheat = GBACheatListAppend(&cheats->list);
 64		cheat->type = CHEAT_AND;
 65		cheat->width = 2;
 66		break;
 67	case CB_IF_EQ:
 68		cheat = GBACheatListAppend(&cheats->list);
 69		cheat->type = CHEAT_IF_EQ;
 70		cheat->width = 2;
 71		break;
 72	case CB_ASSIGN_2:
 73		cheat = GBACheatListAppend(&cheats->list);
 74		cheat->type = CHEAT_ASSIGN;
 75		cheat->width = 2;
 76		break;
 77	case CB_ENCRYPT:
 78		GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker encryption not supported");
 79		return false;
 80	case CB_IF_NE:
 81		cheat = GBACheatListAppend(&cheats->list);
 82		cheat->type = CHEAT_IF_NE;
 83		cheat->width = 2;
 84		break;
 85	case CB_IF_GT:
 86		cheat = GBACheatListAppend(&cheats->list);
 87		cheat->type = CHEAT_IF_GT;
 88		cheat->width = 2;
 89		break;
 90	case CB_IF_LT:
 91		cheat = GBACheatListAppend(&cheats->list);
 92		cheat->type = CHEAT_IF_LT;
 93		cheat->width = 2;
 94		break;
 95	case CB_IF_SPECIAL:
 96		switch (op1 & 0x0FFFFFFF) {
 97		case 0x20:
 98			cheat = GBACheatListAppend(&cheats->list);
 99			cheat->type = CHEAT_IF_AND;
100			cheat->width = 2;
101			cheat->address = BASE_IO | REG_JOYSTAT;
102			cheat->operand = op2;
103			cheat->repeat = 1;
104			return true;
105		default:
106			GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
107			return false;
108		}
109	case CB_ADD_2:
110		cheat = GBACheatListAppend(&cheats->list);
111		cheat->type = CHEAT_ADD;
112		cheat->width = 2;
113		break;
114	case CB_IF_AND:
115		cheat = GBACheatListAppend(&cheats->list);
116		cheat->type = CHEAT_IF_AND;
117		cheat->width = 2;
118		break;
119	}
120
121	cheat->address = op1 & 0x0FFFFFFF;
122	cheat->operand = op2;
123	cheat->repeat = 1;
124	cheat->negativeRepeat = 0;
125	return true;
126}
127
128bool GBACheatAddCodeBreakerLine(struct GBACheatSet* cheats, const char* line) {
129	uint32_t op1;
130	uint16_t op2;
131	line = hex32(line, &op1);
132	if (!line) {
133		return false;
134	}
135	while (*line == ' ') {
136		++line;
137	}
138	line = hex16(line, &op2);
139	if (!line) {
140		return false;
141	}
142	return GBACheatAddCodeBreaker(cheats, op1, op2);
143}