1 /** EMULib Emulation Library *********************************/
2 /** **/
3 /** Hunt.c **/
4 /** **/
5 /** This file implements mechanism for searching possible **/
6 /** cheats inside running game data. Also see Hunt.h. **/
7 /** **/
8 /** Copyright (C) Marat Fayzullin 2013-2016 **/
9 /** You are not allowed to distribute this software **/
10 /** commercially. Please, notify me, if you make any **/
11 /** changes to this file. **/
12 /*************************************************************/
13 #include "Hunt.h"
14 #include <stdio.h>
15
16 #if defined(VGBA)
17 #include "ARM.h"
18 #define MEMREAD32(A) QRdARM(A)
19 #define MEMREAD16(A) WRdARM(A)
20 #define MEMREAD8(A) BRdARM(A)
21 #elif defined(INES)
22 #include "M6502.h"
23 #define MEMREAD32(A) (Rd6502(A)+((int)Rd6502(A+1)<<8)+((int)Rd6502(A+2)<<16)+((int)Rd6502(A+3)<<24))
24 #define MEMREAD16(A) (Rd6502(A)+((int)Rd6502(A+1)<<8))
25 #define MEMREAD8(A) Rd6502(A)
26 #elif defined(VGB) || defined(MG) || defined(COLEM) || defined(SPECCY) || defined(FMSX)
27 #include "Z80.h"
28 #define MEMREAD32(A) (RdZ80(A)+((int)RdZ80(A+1)<<8)+((int)RdZ80(A+2)<<16)+((int)RdZ80(A+3)<<24))
29 #define MEMREAD16(A) (RdZ80(A)+((int)RdZ80(A+1)<<8))
30 #define MEMREAD8(A) RdZ80(A)
31 #else
32 #define MEMREAD32(A) (0)
33 #define MEMREAD16(A) (0)
34 #define MEMREAD8(A) (0)
35 #endif
36
37 static HUNTEntry Buf[HUNT_BUFSIZE];
38 static int Count;
39
40 /** InitHUNT() ***********************************************/
41 /** Initialize cheat search, clearing all data. **/
42 /*************************************************************/
InitHUNT(void)43 void InitHUNT(void) { Count=0; }
44
45 /** TotalHUNT() **********************************************/
46 /** Get total number of currently watched locations. **/
47 /*************************************************************/
TotalHUNT(void)48 int TotalHUNT(void) { return(Count); }
49
50 /** GetHUNT() ************************************************/
51 /** Get Nth memory location. Returns 0 for invalid N. **/
52 /*************************************************************/
GetHUNT(int N)53 HUNTEntry *GetHUNT(int N)
54 { return((N>=0)&&(N<Count)? &Buf[N]:0); }
55
56 /** AddHUNT() ************************************************/
57 /** Add a new value to search for, with the address range **/
58 /** to search in. Returns number of memory locations found. **/
59 /*************************************************************/
AddHUNT(unsigned int Addr,unsigned int Size,unsigned int Value,unsigned int NewValue,unsigned int Flags)60 int AddHUNT(unsigned int Addr,unsigned int Size,unsigned int Value,unsigned int NewValue,unsigned int Flags)
61 {
62 unsigned int J,M;
63 int I;
64
65 /* Force 32bit/16bit mode for large values */
66 if((Value>=0x10000)||(NewValue>=0x10000))
67 Flags = (Flags&~HUNT_MASK_SIZE)|HUNT_32BIT;
68 else if((Value>=0x100)||(NewValue>=0x100))
69 Flags = (Flags&~HUNT_MASK_SIZE)|HUNT_16BIT;
70
71 /* Compute mask for given value size and truncate value */
72 M = Flags&HUNT_32BIT? 0xFFFFFFFF:Flags&HUNT_16BIT? 0xFFFF:0x00FF;
73
74 #ifdef VGBA
75 /* ARM aligns data to the size boundary */
76 if(M>0xFFFF) Addr&=~3; else if(M>0xFF) Addr&=~1;
77 #endif
78
79 /* Scan memory for given value */
80 for(Size+=Addr,I=0;(Addr<Size)&&(Count<HUNT_BUFSIZE);++Addr)
81 {
82 J = (M>0xFFFF? MEMREAD32(Addr):M>0xFF? MEMREAD16(Addr):MEMREAD8(Addr))&M;
83
84 if((J==Value)||(J==((Value-1)&M)))
85 {
86 Buf[Count].Addr = Addr;
87 Buf[Count].Flags = Flags;
88 Buf[Count].Value = J;
89 Buf[Count].Orig = J==Value? NewValue:((NewValue-1)&M);
90 Buf[Count].Count = 0;
91 ++Count;
92 ++I;
93 }
94
95 #ifdef VGBA
96 /* ARM aligns data to the size boundary */
97 if(M>0xFFFF) Addr+=3; else if(M>0xFF) Addr+=1;
98 #endif
99 }
100
101 /* Return the number of matches found */
102 return(I);
103 }
104
105 /** ScanHUNT() ***********************************************/
106 /** Scan memory for changed values and update search data. **/
107 /** Returns number of memory locations updated. **/
108 /*************************************************************/
ScanHUNT(void)109 int ScanHUNT(void)
110 {
111 unsigned int K,L;
112 int J,I;
113
114 /* Scan active search entries */
115 for(J=I=0;J<Count;++J)
116 {
117 L = Buf[J].Flags&HUNT_32BIT? 0xFFFFFFFF:Buf[J].Flags&HUNT_16BIT? 0xFFFF:0x00FF;
118 K = (L>0xFFFF? MEMREAD32(Buf[J].Addr):L>0xFF? MEMREAD16(Buf[J].Addr):MEMREAD8(Buf[J].Addr))&L;
119
120 /* Check for expected changes */
121 switch(Buf[J].Flags&HUNT_MASK_CHANGE)
122 {
123 case HUNT_PLUSONE: L = K==((Buf[J].Value+1)&L);break;
124 case HUNT_PLUSMANY: L = K>Buf[J].Value;break;
125 case HUNT_MINUSONE: L = K==((Buf[J].Value-1)&L);break;
126 case HUNT_MINUSMANY: L = K<Buf[J].Value;break;
127 default:
128 case HUNT_CONSTANT: L = K==Buf[J].Value;break;
129 }
130
131 /* Delete any entry that does not change as expected */
132 if(L)
133 {
134 if(Buf[J].Count<(1<<(sizeof(Buf[J].Count)<<3))-1) ++Buf[J].Count;
135 Buf[J].Value = K;
136 Buf[I++] = Buf[J];
137 }
138 }
139
140 /* Return number of successfully updated entries */
141 return(Count=I);
142 }
143
144 /** HUNT2Cheat() *********************************************/
145 /** Create cheat code from Nth hunt entry. Returns 0 if the **/
146 /** entry is invalid. **/
147 /*************************************************************/
HUNT2Cheat(int N,unsigned int Type)148 const char *HUNT2Cheat(int N,unsigned int Type)
149 {
150 static char Buf[32];
151 HUNTEntry *HE;
152
153 /* Must have a valid entry */
154 if(!(HE=GetHUNT(N))) return(0);
155
156 /* Depending on cheat type... */
157 switch(Type)
158 {
159 /** GameBoy Advance ******************************************/
160 /** There are two versions of GameShark (v1/v3) differing **/
161 /** by encryption and CodeBreaker. Not encrypting here. **/
162 /*************************************************************/
163 case HUNT_GBA_GS:
164 /* 00AAAAAA NNNNNNDD - Multiple 8bit RAM Write */
165 /* 02AAAAAA NNNNDDDD - Multiple 816bit RAM Write */
166 sprintf(Buf,"0%c%06X 0000%04X",
167 HE->Flags&HUNT_16BIT? '2':'0',
168 (HE->Addr&0x000FFFFF)|((HE->Addr&0x0F000000)>>4),
169 HE->Orig
170 );
171 return(Buf);
172
173 case HUNT_GBA_CB:
174 /* 2AAAAAAA XXXX - 16bit RAM Write */
175 /* 3AAAAAAA 00XX - 8bit RAM Write */
176 sprintf(Buf,"%c%07X %04X",
177 HE->Flags&HUNT_16BIT? '2':'3',
178 HE->Addr&0x0FFFFFFF,
179 HE->Orig
180 );
181 return(Buf);
182
183 /** GameBoy **************************************************/
184 /** GameBoy has GameShark and GameGenie, but only GameShark **/
185 /** can modify RAM. **/
186 /*************************************************************/
187 case HUNT_GB_GS:
188 /* 00DDAAAA - 8bit RAM Write, No Bank */
189 sprintf(Buf,"00%02X%02X%02X",(HE->Orig)&0xFF,HE->Addr&0x00FF,(HE->Addr&0xFF00)>>8);
190 if(HE->Flags&HUNT_16BIT)
191 sprintf(Buf+8,";00%02X%02X%02X",HE->Orig>>8,(HE->Addr+1)&0x00FF,((HE->Addr+1)&0xFF00)>>8);
192 return(Buf);
193
194 /** NES ******************************************************/
195 /** NES has both Pro Action Replay and GameGenie, but only **/
196 /** Pro Action Replay can modify RAM. **/
197 /*************************************************************/
198 case HUNT_NES_AR:
199 /* 00AAAADD - 8bit RAM Write */
200 sprintf(Buf,"00%04X%02X",HE->Addr&0xFFFF,HE->Orig&0xFF);
201 if(HE->Flags&HUNT_16BIT)
202 sprintf(Buf+8,";00%04X%02X",(HE->Addr+1)&0xFFFF,HE->Orig>>8);
203 return(Buf);
204
205 /** Sega MasterSystem and GameGear ***************************/
206 /** MasterSystem has Pro Action Replay, while GameGear has **/
207 /** GameGenie. Only Pro Action Replay can modify RAM. **/
208 /*************************************************************/
209 case HUNT_SMS_AR:
210 /* 00AA-AADD - 8bit RAM Write */
211 sprintf(Buf,"00%02X-%02X%02X",(HE->Addr&0xFF00)>>8,HE->Addr&0x00FF,HE->Orig&0xFF);
212 if(HE->Flags&HUNT_16BIT)
213 sprintf(Buf+9,";00%02X-%02X%02X",((HE->Addr+1)&0xFF00)>>8,(HE->Addr+1)&0x00FF,HE->Orig>>8);
214 return(Buf);
215
216 /** ColecoVision, MSX, ZX Spectrum ***************************/
217 /** There was no official cheating hardware for these **/
218 /** systems, so we come up with our own "hardware". **/
219 /*************************************************************/
220 case HUNT_MSX:
221 case HUNT_ZXS:
222 case HUNT_COLECO:
223 /* AAAA-DD[DD] - 8bit[16bit] RAM Write */
224 if(HE->Flags&HUNT_16BIT)
225 sprintf(Buf,"%04X-%04X",HE->Addr,HE->Orig&0xFFFF);
226 else
227 sprintf(Buf,"%04X-%02X",HE->Addr,HE->Orig&0x00FF);
228 return(Buf);
229 }
230
231 /* Invalid cheat type */
232 return(0);
233 }
234