2020-02-14 18:26:52 +00:00
|
|
|
/*
|
2020-02-14 19:18:08 +00:00
|
|
|
Copyright 2016-2020 Arisotura
|
2020-02-14 18:26:52 +00:00
|
|
|
|
|
|
|
This file is part of melonDS.
|
|
|
|
|
|
|
|
melonDS is free software: you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU General Public License as published by the Free
|
|
|
|
Software Foundation, either version 3 of the License, or (at your option)
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
|
|
with melonDS. If not, see http://www.gnu.org/licenses/.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "NDS.h"
|
|
|
|
#include "AREngine.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace AREngine
|
|
|
|
{
|
|
|
|
|
2020-02-14 19:13:06 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
u32 Code[2 * 64]; // TODO: more sensible size for this? allocate on demand?
|
|
|
|
bool Enabled;
|
|
|
|
|
|
|
|
} CheatEntry;
|
|
|
|
|
2020-02-14 18:26:52 +00:00
|
|
|
// TODO: more sensible size for this? allocate on demand?
|
2020-02-14 19:13:06 +00:00
|
|
|
CheatEntry CheatCodes[64];
|
|
|
|
u32 NumCheatCodes;
|
2020-02-14 18:26:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
bool Init()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeInit()
|
|
|
|
{
|
|
|
|
//
|
|
|
|
}
|
|
|
|
|
|
|
|
void Reset()
|
|
|
|
{
|
2020-02-14 19:13:06 +00:00
|
|
|
memset(CheatCodes, 0, sizeof(CheatCodes));
|
|
|
|
NumCheatCodes = 0;
|
2020-02-14 18:26:52 +00:00
|
|
|
|
|
|
|
// TODO: acquire codes from a sensible source!
|
2020-02-14 20:19:36 +00:00
|
|
|
#define TEMP_PUTCODE(a, b) *ptr++ = a; *ptr++ = b;
|
2020-02-14 19:13:06 +00:00
|
|
|
CheatEntry* entry = &CheatCodes[0];
|
|
|
|
u32* ptr = &entry->Code[0];
|
2020-02-14 20:19:36 +00:00
|
|
|
/*// NSMBDS EUR - giant fucking Mario
|
2020-02-14 19:13:06 +00:00
|
|
|
TEMP_PUTCODE(0x1209DBD0, 0x0000027C);
|
|
|
|
TEMP_PUTCODE(0x2209DBC0, 0x00000003);
|
|
|
|
TEMP_PUTCODE(0x94000130, 0xFFFD0000);
|
|
|
|
TEMP_PUTCODE(0x1209DBD0, 0x00000000);
|
|
|
|
TEMP_PUTCODE(0x2209DBC0, 0x00000003);
|
|
|
|
entry->Enabled = true;
|
|
|
|
NumCheatCodes++;
|
2020-02-14 20:19:36 +00:00
|
|
|
|
|
|
|
entry = &CheatCodes[1];
|
|
|
|
ptr = &entry->Code[0];*/
|
|
|
|
// NSMBDS EUR - jump to the sky
|
|
|
|
/*TEMP_PUTCODE(0x9209DC90, 0xFFFD0002);
|
|
|
|
TEMP_PUTCODE(0x920DC910, 0x00000000);
|
|
|
|
TEMP_PUTCODE(0x021C1944, 0x00004000);
|
|
|
|
TEMP_PUTCODE(0xD2000000, 0x00000000);
|
|
|
|
TEMP_PUTCODE(0x9209DC90, 0xFFFE0001);
|
|
|
|
TEMP_PUTCODE(0x920DC910, 0x00000000);
|
|
|
|
TEMP_PUTCODE(0x021C1944, 0x00004000);
|
|
|
|
TEMP_PUTCODE(0xD2000000, 0x00000000);*/
|
|
|
|
// SM64DS EUR redcoin
|
|
|
|
/*TEMP_PUTCODE(0x0210CC3E, 0x00000121);
|
|
|
|
TEMP_PUTCODE(0x5209F30C, 0x00000008);
|
|
|
|
TEMP_PUTCODE(0x0209F30C, 0x00000000);
|
|
|
|
TEMP_PUTCODE(0xD2000000, 0x00000000);*/
|
|
|
|
// SM64DS EUR shroom-o-matic
|
|
|
|
/*TEMP_PUTCODE(0x9209D09A , 0x00000000);
|
|
|
|
TEMP_PUTCODE(0x6209B468 , 0x00000000);
|
|
|
|
TEMP_PUTCODE(0xB209B468 , 0x00000000);
|
|
|
|
TEMP_PUTCODE(0x10000672 , 0x000003FF);
|
|
|
|
TEMP_PUTCODE(0xD2000000 , 0x00000000);
|
|
|
|
TEMP_PUTCODE(0x9209D09A , 0x00000000);
|
|
|
|
TEMP_PUTCODE(0x94000130 , 0xFCBF0000);
|
|
|
|
TEMP_PUTCODE(0x6209B468 , 0x00000000);
|
|
|
|
TEMP_PUTCODE(0xB209B468 , 0x00000000);
|
|
|
|
TEMP_PUTCODE(0x200006B3 , 0x00000001);
|
|
|
|
TEMP_PUTCODE(0x200006B4 , 0x00000001);
|
|
|
|
TEMP_PUTCODE(0xD2000000 , 0x00000000);
|
|
|
|
TEMP_PUTCODE(0x9209D09A , 0x00000000);
|
|
|
|
TEMP_PUTCODE(0x94000130 , 0xFC7F0000);
|
|
|
|
TEMP_PUTCODE(0x6209B468 , 0x00000000);
|
|
|
|
TEMP_PUTCODE(0xB209B468 , 0x00000000);
|
|
|
|
TEMP_PUTCODE(0x10000672 , 0x00000000);
|
|
|
|
TEMP_PUTCODE(0xD2000000 , 0x00000000);*/
|
2020-02-14 22:34:26 +00:00
|
|
|
// SM64DS EUR swim through floor
|
|
|
|
TEMP_PUTCODE(0x927FFFA8 , 0xFBFF0000); // IF 0000 = ((~FBFF) & u16[027FFFA8])
|
|
|
|
TEMP_PUTCODE(0x823FDFF8 , 0xFBFF0000); // IF 0000 < ((~FBFF) & u16[023FDFF8])
|
|
|
|
TEMP_PUTCODE(0xDA000000 , 0x023FDFFA); // datareg = u16[023FDFFA + offset]
|
|
|
|
TEMP_PUTCODE(0xD4000000 , 0x00000001); // datareg += 1
|
|
|
|
TEMP_PUTCODE(0xD7000000 , 0x023FDFFA); // u16[023FDFFA + offset] = datareg; offset += 2
|
|
|
|
TEMP_PUTCODE(0xD2000000 , 0x00000000); // NEXT/FLUSH
|
|
|
|
TEMP_PUTCODE(0xD3000000 , 0x027FFFA8); // offset = 027FFFA8
|
|
|
|
TEMP_PUTCODE(0xF23FDFF8 , 0x00000002); // copy offset->023FDFF8, 2
|
|
|
|
TEMP_PUTCODE(0xD2000000 , 0x00000000); // NEXT/FLUSH
|
|
|
|
TEMP_PUTCODE(0x923FDFFA , 0xFFFE0000); // IF 0000 = ((~FFFE) & u16[023FDFFA])
|
|
|
|
TEMP_PUTCODE(0x02037E7C , 0xE2000020); // u32[02037E7C] = E2000020
|
|
|
|
TEMP_PUTCODE(0xD0000000 , 0x00000000); // ENDIF
|
|
|
|
TEMP_PUTCODE(0x923FDFFA , 0xFFFE0001); // IF 0001 = ((~FFFE) & u16[023FDFFA])
|
|
|
|
TEMP_PUTCODE(0x02037E7C , 0xE2000000); // u32[02037E7C] = E2000000
|
|
|
|
TEMP_PUTCODE(0xD0000000 , 0x00000000); // ENDIF
|
|
|
|
TEMP_PUTCODE(0x927FFFA8 , 0xFBFF0000); // IF 0000 = ((~FBFF) & u16[027FFFA8])
|
|
|
|
TEMP_PUTCODE(0x02037E7C , 0xE3A000FF); // u32[02037E7C] = E3A000FF
|
|
|
|
TEMP_PUTCODE(0xD2000000 , 0x00000000); // NEXT/FLUSH
|
2020-02-14 20:19:36 +00:00
|
|
|
entry->Enabled = true;
|
|
|
|
NumCheatCodes++;
|
2020-02-14 18:26:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-14 19:13:06 +00:00
|
|
|
#define case16(x) \
|
|
|
|
case ((x)+0x00): case ((x)+0x01): case ((x)+0x02): case ((x)+0x03): \
|
|
|
|
case ((x)+0x04): case ((x)+0x05): case ((x)+0x06): case ((x)+0x07): \
|
|
|
|
case ((x)+0x08): case ((x)+0x09): case ((x)+0x0A): case ((x)+0x0B): \
|
|
|
|
case ((x)+0x0C): case ((x)+0x0D): case ((x)+0x0E): case ((x)+0x0F)
|
|
|
|
|
|
|
|
void RunCheat(CheatEntry* entry)
|
|
|
|
{
|
|
|
|
u32* code = &entry->Code[0];
|
|
|
|
|
2020-02-14 20:19:36 +00:00
|
|
|
u32 offset = 0;
|
|
|
|
u32 datareg = 0;
|
2020-02-14 19:13:06 +00:00
|
|
|
u32 cond = 1;
|
|
|
|
u32 condstack = 0;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
u32 a = *code++;
|
|
|
|
u32 b = *code++;
|
|
|
|
if ((a|b) == 0) break;
|
|
|
|
|
|
|
|
u8 op = a >> 24;
|
|
|
|
|
|
|
|
if ((op < 0xD0 && op != 0xC5) || op > 0xD2)
|
|
|
|
{
|
|
|
|
if (!cond)
|
|
|
|
{
|
2020-02-14 22:34:26 +00:00
|
|
|
if ((op & 0xF0) == 0xE0)
|
|
|
|
{
|
|
|
|
for (u32 i = 0; i < b; i += 8)
|
|
|
|
*code += 2;
|
|
|
|
}
|
|
|
|
|
2020-02-14 19:13:06 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (op)
|
|
|
|
{
|
|
|
|
case16(0x00): // 32-bit write
|
2020-02-14 20:19:36 +00:00
|
|
|
NDS::ARM7Write32((a & 0x0FFFFFFF) + offset, b);
|
2020-02-14 19:13:06 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case16(0x10): // 16-bit write
|
2020-02-14 20:19:36 +00:00
|
|
|
NDS::ARM7Write16((a & 0x0FFFFFFF) + offset, b & 0xFFFF);
|
2020-02-14 19:13:06 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case16(0x20): // 8-bit write
|
2020-02-14 20:19:36 +00:00
|
|
|
NDS::ARM7Write8((a & 0x0FFFFFFF) + offset, b & 0xFF);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case16(0x30): // IF b > u32[a]
|
|
|
|
{
|
|
|
|
condstack <<= 1;
|
|
|
|
condstack |= cond;
|
|
|
|
|
|
|
|
u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF);
|
|
|
|
|
|
|
|
cond = (b > chk) ? 1:0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case16(0x40): // IF b < u32[a]
|
|
|
|
{
|
|
|
|
condstack <<= 1;
|
|
|
|
condstack |= cond;
|
|
|
|
|
|
|
|
u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF);
|
|
|
|
|
|
|
|
cond = (b < chk) ? 1:0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case16(0x50): // IF b == u32[a]
|
|
|
|
{
|
|
|
|
condstack <<= 1;
|
|
|
|
condstack |= cond;
|
|
|
|
|
|
|
|
u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF);
|
|
|
|
|
|
|
|
cond = (b == chk) ? 1:0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case16(0x60): // IF b != u32[a]
|
|
|
|
{
|
|
|
|
condstack <<= 1;
|
|
|
|
condstack |= cond;
|
|
|
|
|
|
|
|
u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF);
|
|
|
|
|
|
|
|
cond = (b != chk) ? 1:0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case16(0x70): // IF b.l > ((~b.h) & u16[a])
|
|
|
|
{
|
|
|
|
condstack <<= 1;
|
|
|
|
condstack |= cond;
|
|
|
|
|
|
|
|
u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF);
|
|
|
|
u16 chk = ~(b >> 16);
|
|
|
|
chk &= val;
|
|
|
|
|
|
|
|
cond = ((b & 0xFFFF) > chk) ? 1:0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case16(0x80): // IF b.l < ((~b.h) & u16[a])
|
|
|
|
{
|
|
|
|
condstack <<= 1;
|
|
|
|
condstack |= cond;
|
|
|
|
|
|
|
|
u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF);
|
|
|
|
u16 chk = ~(b >> 16);
|
|
|
|
chk &= val;
|
|
|
|
|
|
|
|
cond = ((b & 0xFFFF) < chk) ? 1:0;
|
|
|
|
}
|
2020-02-14 19:13:06 +00:00
|
|
|
break;
|
|
|
|
|
2020-02-14 20:19:36 +00:00
|
|
|
case16(0x90): // IF b.l == ((~b.h) & u16[a])
|
2020-02-14 19:13:06 +00:00
|
|
|
{
|
|
|
|
condstack <<= 1;
|
|
|
|
condstack |= cond;
|
|
|
|
|
|
|
|
u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF);
|
|
|
|
u16 chk = ~(b >> 16);
|
|
|
|
chk &= val;
|
|
|
|
|
|
|
|
cond = ((b & 0xFFFF) == chk) ? 1:0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2020-02-14 20:19:36 +00:00
|
|
|
case16(0xA0): // IF b.l != ((~b.h) & u16[a])
|
|
|
|
{
|
|
|
|
condstack <<= 1;
|
|
|
|
condstack |= cond;
|
|
|
|
|
|
|
|
u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF);
|
|
|
|
u16 chk = ~(b >> 16);
|
|
|
|
chk &= val;
|
|
|
|
|
|
|
|
cond = ((b & 0xFFFF) != chk) ? 1:0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case16(0xB0): // offset = u32[a + offset]
|
|
|
|
offset = NDS::ARM7Read32((a & 0x0FFFFFFF) + offset);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xD0: // ENDIF
|
|
|
|
cond = condstack & 0x1;
|
|
|
|
condstack >>= 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xD2: // NEXT+FLUSH
|
|
|
|
// TODO: loop shenanigans!
|
|
|
|
offset = 0;
|
|
|
|
datareg = 0;
|
|
|
|
condstack = 0;
|
|
|
|
cond = 1;
|
|
|
|
break;
|
|
|
|
|
2020-02-14 22:34:26 +00:00
|
|
|
case 0xD3: // offset = b
|
|
|
|
offset = b;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xD4: // datareg += b
|
|
|
|
datareg += b;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xD5: // datareg = b
|
|
|
|
datareg = b;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xD6: // u32[b+offset] = datareg / offset += 4
|
|
|
|
NDS::ARM7Write32(b + offset, datareg);
|
|
|
|
offset += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xD7: // u16[b+offset] = datareg / offset += 2
|
|
|
|
NDS::ARM7Write16(b + offset, datareg & 0xFFFF);
|
|
|
|
offset += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xD8: // u8[b+offset] = datareg / offset += 1
|
|
|
|
NDS::ARM7Write8(b + offset, datareg & 0xFF);
|
|
|
|
offset += 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xD9: // datareg = u32[b+offset]
|
|
|
|
datareg = NDS::ARM7Read32(b + offset);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xDA: // datareg = u16[b+offset]
|
|
|
|
datareg = NDS::ARM7Read16(b + offset);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xDB: // datareg = u8[b+offset]
|
|
|
|
datareg = NDS::ARM7Read8(b + offset);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xDC: // offset += b
|
|
|
|
offset += b;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case16(0xE0): // copy b param bytes to address a+offset
|
|
|
|
{
|
|
|
|
// TODO: check for bad alignment of dstaddr
|
|
|
|
|
|
|
|
u32 dstaddr = (a & 0x0FFFFFFF) + offset;
|
|
|
|
u32 bytesleft = b;
|
|
|
|
while (bytesleft >= 8)
|
|
|
|
{
|
|
|
|
NDS::ARM7Write32(dstaddr, *code++); dstaddr += 4;
|
|
|
|
NDS::ARM7Write32(dstaddr, *code++); dstaddr += 4;
|
|
|
|
bytesleft -= 8;
|
|
|
|
}
|
|
|
|
if (bytesleft > 0)
|
|
|
|
{
|
|
|
|
u8* leftover = (u8*)code;
|
|
|
|
*code += 2;
|
|
|
|
if (bytesleft >= 4)
|
|
|
|
{
|
|
|
|
NDS::ARM7Write32(dstaddr, *(u32*)leftover); dstaddr += 4;
|
|
|
|
leftover += 4;
|
|
|
|
bytesleft -= 4;
|
|
|
|
}
|
|
|
|
while (bytesleft > 0)
|
|
|
|
{
|
|
|
|
NDS::ARM7Write8(dstaddr, *leftover++); dstaddr++;
|
|
|
|
bytesleft--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case16(0xF0): // copy b bytes from address offset to address a
|
|
|
|
{
|
|
|
|
// TODO: check for bad alignment of srcaddr/dstaddr
|
|
|
|
|
|
|
|
u32 srcaddr = offset;
|
|
|
|
u32 dstaddr = (a & 0x0FFFFFFF);
|
|
|
|
u32 bytesleft = b;
|
|
|
|
while (bytesleft >= 4)
|
|
|
|
{
|
|
|
|
NDS::ARM7Write32(dstaddr, NDS::ARM7Read32(srcaddr));
|
|
|
|
srcaddr += 4;
|
|
|
|
dstaddr += 4;
|
|
|
|
bytesleft -= 4;
|
|
|
|
}
|
|
|
|
while (bytesleft > 0)
|
|
|
|
{
|
|
|
|
NDS::ARM7Write8(dstaddr, NDS::ARM7Read8(srcaddr));
|
|
|
|
srcaddr++;
|
|
|
|
dstaddr++;
|
|
|
|
bytesleft--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2020-02-14 19:13:06 +00:00
|
|
|
default:
|
|
|
|
printf("!! bad AR opcode %08X %08X\n", a, b);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 18:26:52 +00:00
|
|
|
void RunCheats()
|
|
|
|
{
|
2020-02-14 19:13:06 +00:00
|
|
|
// TODO: make it disableable in general
|
|
|
|
|
|
|
|
for (u32 i = 0; i < NumCheatCodes; i++)
|
|
|
|
{
|
|
|
|
CheatEntry* entry = &CheatCodes[i];
|
|
|
|
if (entry->Enabled)
|
|
|
|
RunCheat(entry);
|
|
|
|
}
|
2020-02-14 18:26:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|