rlm@1
|
1 // A few notes about this implementation of a RAM search window:
|
rlm@1
|
2 //
|
rlm@1
|
3 // Speed of update was one of the highest priories.
|
rlm@1
|
4 // This is because I wanted the RAM search window to be able to
|
rlm@1
|
5 // update every single value in RAM every single frame, and
|
rlm@1
|
6 // keep track of the exact number of frames across which each value has changed,
|
rlm@1
|
7 // without causing the emulation to run noticeably slower than normal.
|
rlm@1
|
8 //
|
rlm@1
|
9 // The data representation was changed from one entry per valid address
|
rlm@1
|
10 // to one entry per contiguous range of uneliminated addresses
|
rlm@1
|
11 // which references uniform pools of per-address properties.
|
rlm@1
|
12 // - This saves time when there are many items because
|
rlm@1
|
13 // it minimizes the amount of data that needs to be stored and processed per address.
|
rlm@1
|
14 // - It also saves time when there are few items because
|
rlm@1
|
15 // it ensures that no time is wasted in iterating through
|
rlm@1
|
16 // addresses that have already been eliminated from the search.
|
rlm@1
|
17 //
|
rlm@1
|
18 // The worst-case scenario is when every other item has been
|
rlm@1
|
19 // eliminated from the search, maximizing the number of regions.
|
rlm@1
|
20 // This implementation manages to handle even that pathological case
|
rlm@1
|
21 // acceptably well. In fact, it still updates faster than the previous implementation.
|
rlm@1
|
22 // The time spent setting up or clearing such a large number of regions
|
rlm@1
|
23 // is somewhat horrendous, but it seems reasonable to have poor worst-case speed
|
rlm@1
|
24 // during these sporadic "setup" steps to achieve an all-around faster per-update speed.
|
rlm@1
|
25 // (You can test this case by performing the search: Modulo 2 Is Specific Address 0)
|
rlm@1
|
26
|
rlm@1
|
27
|
rlm@1
|
28 #ifdef _WIN32
|
rlm@1
|
29 #include "stdafx.h"
|
rlm@1
|
30 #include "resource.h"
|
rlm@1
|
31 #include "VBA.h"
|
rlm@1
|
32 //#include <windows.h>
|
rlm@1
|
33 #include <commctrl.h>
|
rlm@1
|
34 #include "BaseTsd.h"
|
rlm@1
|
35 #include "GBACheatsDlg.h"
|
rlm@1
|
36 #include "GBCheatsDlg.h"
|
rlm@1
|
37 typedef INT_PTR intptr_t;
|
rlm@1
|
38 #else
|
rlm@1
|
39 #include "stdint.h"
|
rlm@1
|
40 #endif
|
rlm@1
|
41 #include <cassert>
|
rlm@1
|
42 #include <list>
|
rlm@1
|
43 #include <vector>
|
rlm@1
|
44
|
rlm@1
|
45 #include "ram_search.h"
|
rlm@1
|
46 #include "ramwatch.h"
|
rlm@1
|
47 #include "../gba/GBAGlobals.h"
|
rlm@1
|
48 #include "../gb/gbGlobals.h"
|
rlm@1
|
49 #include "../common/vbalua.h"
|
rlm@1
|
50 #include "Reg.h"
|
rlm@1
|
51
|
rlm@1
|
52 static inline u8* HardwareToSoftwareAddress(HWAddressType address)
|
rlm@1
|
53 {
|
rlm@1
|
54 if(!emulating)
|
rlm@1
|
55 return NULL;
|
rlm@1
|
56
|
rlm@1
|
57 // note: this currently follows the "quick" memory rules,
|
rlm@1
|
58 // meaning it will miss whatever special cases aren't handled by read/writeMemoryQuick.
|
rlm@1
|
59 // if this is made more accurate, it may be necessary to reduce regionSearchGranularity.
|
rlm@1
|
60 if(systemCartridgeType == 0)
|
rlm@1
|
61 {
|
rlm@1
|
62 // GBA
|
rlm@1
|
63 HWAddressType mask = ::map[address >> 24].mask;
|
rlm@1
|
64 if(!mask || (address & 0xFFFFFF) > mask)
|
rlm@1
|
65 return NULL;
|
rlm@1
|
66 return &::map[address >> 24].address[address & mask];
|
rlm@1
|
67 }
|
rlm@1
|
68 else
|
rlm@1
|
69 {
|
rlm@1
|
70 // GB
|
rlm@1
|
71 extern int32 gbEchoRAMFixOn;
|
rlm@1
|
72 if (gbEchoRAMFixOn)
|
rlm@1
|
73 if (address >= 0xe000 && address < 0xfe00)
|
rlm@1
|
74 address -= 0x2000;
|
rlm@1
|
75 if((address>>12) >= sizeof(gbMemoryMap)/sizeof(*gbMemoryMap))
|
rlm@1
|
76 return NULL;
|
rlm@1
|
77 return &gbMemoryMap[address>>12][address&0xfff];
|
rlm@1
|
78 }
|
rlm@1
|
79 }
|
rlm@1
|
80
|
rlm@1
|
81
|
rlm@1
|
82 struct MemoryRegion
|
rlm@1
|
83 {
|
rlm@1
|
84 HWAddressType hardwareAddress; // hardware address of the start of this region
|
rlm@1
|
85 unsigned int size; // number of bytes to the end of this region
|
rlm@1
|
86 unsigned char* softwareAddress; // pointer to the start of the live emulator source values for this region
|
rlm@1
|
87
|
rlm@1
|
88 unsigned int virtualIndex; // index into s_prevValues, s_curValues, and s_numChanges, valid after being initialized in ResetMemoryRegions()
|
rlm@1
|
89 unsigned int itemIndex; // index into listbox items, valid when s_itemIndicesInvalid is false
|
rlm@1
|
90 };
|
rlm@1
|
91
|
rlm@1
|
92 int MAX_RAM_SIZE = 0;
|
rlm@1
|
93 static unsigned char* s_prevValues = 0; // values at last search or reset
|
rlm@1
|
94 static unsigned char* s_curValues = 0; // values at last frame update
|
rlm@1
|
95 static unsigned short* s_numChanges = 0; // number of changes of the item starting at this virtual index address
|
rlm@1
|
96 static MemoryRegion** s_itemIndexToRegionPointer = 0; // used for random access into the memory list (trading memory size to get speed here, too bad it's so much memory), only valid when s_itemIndicesInvalid is false
|
rlm@1
|
97 static BOOL s_itemIndicesInvalid = true; // if true, the link from listbox items to memory regions (s_itemIndexToRegionPointer) and the link from memory regions to list box items (MemoryRegion::itemIndex) both need to be recalculated
|
rlm@1
|
98 static BOOL s_prevValuesNeedUpdate = true; // if true, the "prev" values should be updated using the "cur" values on the next frame update signaled
|
rlm@1
|
99 static unsigned int s_maxItemIndex = 0; // max currently valid item index, the listbox sometimes tries to update things past the end of the list so we need to know this to ignore those attempts
|
rlm@1
|
100 static int s_prevSelCount = -1;
|
rlm@1
|
101
|
rlm@1
|
102 HWND RamSearchHWnd;
|
rlm@1
|
103 #define hWnd AfxGetMainWnd()->GetSafeHwnd()
|
rlm@1
|
104 #define hInst AfxGetInstanceHandle()
|
rlm@1
|
105 static char Str_Tmp [1024];
|
rlm@1
|
106
|
rlm@1
|
107 int disableRamSearchUpdate = false;
|
rlm@1
|
108
|
rlm@1
|
109
|
rlm@1
|
110
|
rlm@1
|
111 //static const MemoryRegion s_prgRegion = { 0x020000, SEGACD_RAM_PRG_SIZE, (unsigned char*)Ram_Prg, true};
|
rlm@1
|
112 //static const MemoryRegion s_word1MRegion = { 0x200000, SEGACD_1M_RAM_SIZE, (unsigned char*)Ram_Word_1M, true};
|
rlm@1
|
113 //static const MemoryRegion s_word2MRegion = { 0x200000, SEGACD_2M_RAM_SIZE, (unsigned char*)Ram_Word_2M, true};
|
rlm@1
|
114 //static const MemoryRegion s_z80Region = { 0xA00000, Z80_RAM_SIZE, (unsigned char*)Ram_Z80, true};
|
rlm@1
|
115 //static const MemoryRegion s_68kRegion = { 0xFF0000, _68K_RAM_SIZE, (unsigned char*)Ram_68k, true};
|
rlm@1
|
116 //static const MemoryRegion s_32xRegion = {0x06000000, _32X_RAM_SIZE, (unsigned char*)_32X_Ram, false};
|
rlm@1
|
117
|
rlm@1
|
118 // list of contiguous uneliminated memory regions
|
rlm@1
|
119 typedef std::list<MemoryRegion> MemoryList;
|
rlm@1
|
120 static MemoryList s_activeMemoryRegions;
|
rlm@1
|
121 static CRITICAL_SECTION s_activeMemoryRegionsCS;
|
rlm@1
|
122
|
rlm@1
|
123 // for undo support (could be better, but this way was really easy)
|
rlm@1
|
124 static MemoryList s_activeMemoryRegionsBackup;
|
rlm@1
|
125 static int s_undoType = 0; // 0 means can't undo, 1 means can undo, 2 means can redo
|
rlm@1
|
126
|
rlm@1
|
127 void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg);
|
rlm@1
|
128 static const int tooManyRegionsForUndo = 10000;
|
rlm@1
|
129
|
rlm@1
|
130 void ResetMemoryRegions()
|
rlm@1
|
131 {
|
rlm@1
|
132 systemSoundClearBuffer();
|
rlm@1
|
133 EnterCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
134
|
rlm@1
|
135 s_activeMemoryRegions.clear();
|
rlm@1
|
136
|
rlm@1
|
137 // use HardwareToSoftwareAddress to figure out what all the possible memory regions are,
|
rlm@1
|
138 // split up wherever there's a discontinuity in the address in our software RAM.
|
rlm@1
|
139 static const int regionSearchGranularity = 0x100; // if this is too small, we'll waste time (in this function only), but if any region in RAM isn't evenly divisible by this, we might crash.
|
rlm@1
|
140 HWAddressType hwRegionStart = 0;
|
rlm@1
|
141 u8* regionStart = NULL;
|
rlm@1
|
142 u8* regionEnd = NULL;
|
rlm@1
|
143 for(HWAddressType addr = 0; addr != 0x10000000+regionSearchGranularity; addr += regionSearchGranularity)
|
rlm@1
|
144 {
|
rlm@1
|
145 u8* swAddr = HardwareToSoftwareAddress(addr);
|
rlm@1
|
146 if(regionEnd && swAddr != regionEnd+regionSearchGranularity)
|
rlm@1
|
147 {
|
rlm@1
|
148 // hit end of region
|
rlm@1
|
149 // check to see if it mirrors an existing one (in which case we discard it)
|
rlm@1
|
150 bool discard = false;
|
rlm@1
|
151 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)
|
rlm@1
|
152 {
|
rlm@1
|
153 MemoryRegion& region = *iter;
|
rlm@1
|
154 if(region.softwareAddress == regionStart)
|
rlm@1
|
155 {
|
rlm@1
|
156 unsigned int size = regionSearchGranularity + (regionEnd - regionStart);
|
rlm@1
|
157 if(size <= region.size)
|
rlm@1
|
158 {
|
rlm@1
|
159 discard = true;
|
rlm@1
|
160 }
|
rlm@1
|
161 else
|
rlm@1
|
162 {
|
rlm@1
|
163 hwRegionStart += region.size;
|
rlm@1
|
164 regionStart += region.size;
|
rlm@1
|
165 }
|
rlm@1
|
166 break;
|
rlm@1
|
167 }
|
rlm@1
|
168 }
|
rlm@1
|
169
|
rlm@1
|
170 // don't include ROM in our RAM search (it's too huge)
|
rlm@1
|
171 if(regionStart == rom || regionStart == gbRom)
|
rlm@1
|
172 discard = true;
|
rlm@1
|
173
|
rlm@1
|
174 // create the region
|
rlm@1
|
175 if(!discard)
|
rlm@1
|
176 {
|
rlm@1
|
177 MemoryRegion region = { hwRegionStart, regionSearchGranularity + (regionEnd - regionStart), regionStart };
|
rlm@1
|
178 s_activeMemoryRegions.push_back(region);
|
rlm@1
|
179 }
|
rlm@1
|
180
|
rlm@1
|
181 hwRegionStart = 0;
|
rlm@1
|
182 regionStart = NULL;
|
rlm@1
|
183 regionEnd = NULL;
|
rlm@1
|
184 }
|
rlm@1
|
185 if(swAddr)
|
rlm@1
|
186 {
|
rlm@1
|
187 if(regionStart)
|
rlm@1
|
188 {
|
rlm@1
|
189 // continue region
|
rlm@1
|
190 regionEnd = swAddr;
|
rlm@1
|
191 }
|
rlm@1
|
192 else
|
rlm@1
|
193 {
|
rlm@1
|
194 // start new region
|
rlm@1
|
195 hwRegionStart = addr;
|
rlm@1
|
196 regionStart = swAddr;
|
rlm@1
|
197 regionEnd = swAddr;
|
rlm@1
|
198 }
|
rlm@1
|
199 }
|
rlm@1
|
200 }
|
rlm@1
|
201
|
rlm@1
|
202
|
rlm@1
|
203 int nextVirtualIndex = 0;
|
rlm@1
|
204 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)
|
rlm@1
|
205 {
|
rlm@1
|
206 MemoryRegion& region = *iter;
|
rlm@1
|
207 region.virtualIndex = nextVirtualIndex;
|
rlm@1
|
208 assert(((intptr_t)region.softwareAddress & 1) == 0 && "somebody needs to reimplement ReadValueAtSoftwareAddress()");
|
rlm@1
|
209 nextVirtualIndex = region.virtualIndex + region.size;
|
rlm@1
|
210 }
|
rlm@1
|
211 //assert(nextVirtualIndex <= MAX_RAM_SIZE);
|
rlm@1
|
212
|
rlm@1
|
213 if(nextVirtualIndex > MAX_RAM_SIZE)
|
rlm@1
|
214 {
|
rlm@1
|
215 s_prevValues = (unsigned char*)realloc(s_prevValues, sizeof(char)*(nextVirtualIndex+4));
|
rlm@1
|
216 memset(s_prevValues, 0, sizeof(char)*(nextVirtualIndex+4));
|
rlm@1
|
217
|
rlm@1
|
218 s_curValues = (unsigned char*)realloc(s_curValues, sizeof(char)*(nextVirtualIndex+4));
|
rlm@1
|
219 memset(s_curValues, 0, sizeof(char)*(nextVirtualIndex+4));
|
rlm@1
|
220
|
rlm@1
|
221 s_numChanges = (unsigned short*)realloc(s_numChanges, sizeof(short)*(nextVirtualIndex+4));
|
rlm@1
|
222 memset(s_numChanges, 0, sizeof(short)*(nextVirtualIndex+4));
|
rlm@1
|
223
|
rlm@1
|
224 s_itemIndexToRegionPointer = (MemoryRegion**)realloc(s_itemIndexToRegionPointer, sizeof(MemoryRegion*)*(nextVirtualIndex+4));
|
rlm@1
|
225 memset(s_itemIndexToRegionPointer, 0, sizeof(MemoryRegion*)*(nextVirtualIndex+4));
|
rlm@1
|
226
|
rlm@1
|
227 MAX_RAM_SIZE = nextVirtualIndex;
|
rlm@1
|
228 }
|
rlm@1
|
229 LeaveCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
230 }
|
rlm@1
|
231
|
rlm@1
|
232 // eliminates a range of hardware addresses from the search results
|
rlm@1
|
233 // returns 2 if it changed the region and moved the iterator to another region
|
rlm@1
|
234 // returns 1 if it changed the region but didn't move the iterator
|
rlm@1
|
235 // returns 0 if it had no effect
|
rlm@1
|
236 // warning: don't call anything that takes an itemIndex in a loop that calls DeactivateRegion...
|
rlm@1
|
237 // doing so would be tremendously slow because DeactivateRegion invalidates the index cache
|
rlm@1
|
238 int DeactivateRegion(MemoryRegion& region, MemoryList::iterator& iter, HWAddressType hardwareAddress, unsigned int size)
|
rlm@1
|
239 {
|
rlm@1
|
240 if(hardwareAddress + size <= region.hardwareAddress || hardwareAddress >= region.hardwareAddress + region.size)
|
rlm@1
|
241 {
|
rlm@1
|
242 // region is unaffected
|
rlm@1
|
243 return 0;
|
rlm@1
|
244 }
|
rlm@1
|
245 else if(hardwareAddress > region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size)
|
rlm@1
|
246 {
|
rlm@1
|
247 // erase end of region
|
rlm@1
|
248 region.size = hardwareAddress - region.hardwareAddress;
|
rlm@1
|
249 return 1;
|
rlm@1
|
250 }
|
rlm@1
|
251 else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size)
|
rlm@1
|
252 {
|
rlm@1
|
253 // erase start of region
|
rlm@1
|
254 int eraseSize = (hardwareAddress + size) - region.hardwareAddress;
|
rlm@1
|
255 region.hardwareAddress += eraseSize;
|
rlm@1
|
256 region.size -= eraseSize;
|
rlm@1
|
257 region.softwareAddress += eraseSize;
|
rlm@1
|
258 region.virtualIndex += eraseSize;
|
rlm@1
|
259 return 1;
|
rlm@1
|
260 }
|
rlm@1
|
261 else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size)
|
rlm@1
|
262 {
|
rlm@1
|
263 // erase entire region
|
rlm@1
|
264 iter = s_activeMemoryRegions.erase(iter);
|
rlm@1
|
265 s_itemIndicesInvalid = TRUE;
|
rlm@1
|
266 return 2;
|
rlm@1
|
267 }
|
rlm@1
|
268 else //if(hardwareAddress > region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size)
|
rlm@1
|
269 {
|
rlm@1
|
270 // split region
|
rlm@1
|
271 int eraseSize = (hardwareAddress + size) - region.hardwareAddress;
|
rlm@1
|
272 MemoryRegion region2 = {region.hardwareAddress + eraseSize, region.size - eraseSize, region.softwareAddress + eraseSize, region.virtualIndex + eraseSize};
|
rlm@1
|
273 region.size = hardwareAddress - region.hardwareAddress;
|
rlm@1
|
274 iter = s_activeMemoryRegions.insert(++iter, region2);
|
rlm@1
|
275 s_itemIndicesInvalid = TRUE;
|
rlm@1
|
276 return 2;
|
rlm@1
|
277 }
|
rlm@1
|
278 }
|
rlm@1
|
279
|
rlm@1
|
280 /*
|
rlm@1
|
281 // eliminates a range of hardware addresses from the search results
|
rlm@1
|
282 // this is a simpler but usually slower interface for the above function
|
rlm@1
|
283 void DeactivateRegion(HWAddressType hardwareAddress, unsigned int size)
|
rlm@1
|
284 {
|
rlm@1
|
285 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )
|
rlm@1
|
286 {
|
rlm@1
|
287 MemoryRegion& region = *iter;
|
rlm@1
|
288 if(2 != DeactivateRegion(region, iter, hardwareAddress, size))
|
rlm@1
|
289 ++iter;
|
rlm@1
|
290 }
|
rlm@1
|
291 }
|
rlm@1
|
292 */
|
rlm@1
|
293
|
rlm@1
|
294 struct AutoCritSect
|
rlm@1
|
295 {
|
rlm@1
|
296 AutoCritSect(CRITICAL_SECTION* cs) : m_cs(cs) { EnterCriticalSection(m_cs); }
|
rlm@1
|
297 ~AutoCritSect() { LeaveCriticalSection(m_cs); }
|
rlm@1
|
298 CRITICAL_SECTION* m_cs;
|
rlm@1
|
299 };
|
rlm@1
|
300
|
rlm@1
|
301 // warning: can be slow
|
rlm@1
|
302 void CalculateItemIndices(int itemSize)
|
rlm@1
|
303 {
|
rlm@1
|
304 AutoCritSect cs(&s_activeMemoryRegionsCS);
|
rlm@1
|
305 unsigned int itemIndex = 0;
|
rlm@1
|
306 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)
|
rlm@1
|
307 {
|
rlm@1
|
308 MemoryRegion& region = *iter;
|
rlm@1
|
309 region.itemIndex = itemIndex;
|
rlm@1
|
310 int startSkipSize = ((unsigned int)(itemSize - (unsigned int)region.hardwareAddress)) % itemSize; // FIXME: is this still ok?
|
rlm@1
|
311 unsigned int start = startSkipSize;
|
rlm@1
|
312 unsigned int end = region.size;
|
rlm@1
|
313 for(unsigned int i = start; i < end; i += itemSize)
|
rlm@1
|
314 s_itemIndexToRegionPointer[itemIndex++] = ®ion;
|
rlm@1
|
315 }
|
rlm@1
|
316 s_maxItemIndex = itemIndex;
|
rlm@1
|
317 s_itemIndicesInvalid = FALSE;
|
rlm@1
|
318 }
|
rlm@1
|
319
|
rlm@1
|
320 template<typename stepType, typename compareType>
|
rlm@1
|
321 void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr)
|
rlm@1
|
322 {
|
rlm@1
|
323 //if(GetAsyncKeyState(VK_SHIFT) & 0x8000) // speed hack
|
rlm@1
|
324 // return;
|
rlm@1
|
325
|
rlm@1
|
326 if(s_prevValuesNeedUpdate)
|
rlm@1
|
327 memcpy(s_prevValues + region.virtualIndex, s_curValues + region.virtualIndex, region.size + sizeof(compareType) - sizeof(stepType));
|
rlm@1
|
328
|
rlm@1
|
329 unsigned int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
|
rlm@1
|
330
|
rlm@1
|
331
|
rlm@1
|
332 unsigned char* sourceAddr = region.softwareAddress - region.virtualIndex;
|
rlm@1
|
333
|
rlm@1
|
334 unsigned int indexStart = region.virtualIndex + startSkipSize;
|
rlm@1
|
335 unsigned int indexEnd = region.virtualIndex + region.size;
|
rlm@1
|
336
|
rlm@1
|
337 if(sizeof(compareType) == 1)
|
rlm@1
|
338 {
|
rlm@1
|
339 for(unsigned int i = indexStart; i < indexEnd; i++)
|
rlm@1
|
340 {
|
rlm@1
|
341 if(s_curValues[i] != sourceAddr[i]) // if value changed
|
rlm@1
|
342 {
|
rlm@1
|
343 s_curValues[i] = sourceAddr[i]; // update value
|
rlm@1
|
344 //if(s_numChanges[i] != 0xFFFF)
|
rlm@1
|
345 s_numChanges[i]++; // increase change count
|
rlm@1
|
346 }
|
rlm@1
|
347 }
|
rlm@1
|
348 }
|
rlm@1
|
349 else // it's more complicated for non-byte sizes because:
|
rlm@1
|
350 { // - more than one byte can affect a given change count entry
|
rlm@1
|
351 // - when more than one of those bytes changes simultaneously the entry's change count should only increase by 1
|
rlm@1
|
352 // - a few of those bytes can be outside the region
|
rlm@1
|
353
|
rlm@1
|
354 unsigned int endSkipSize = ((unsigned int)(startSkipSize - region.size)) % sizeof(stepType);
|
rlm@1
|
355 unsigned int lastIndexToRead = indexEnd + endSkipSize + sizeof(compareType) - sizeof(stepType);
|
rlm@1
|
356 unsigned int lastIndexToCopy = lastIndexToRead;
|
rlm@1
|
357 if(nextRegionPtr)
|
rlm@1
|
358 {
|
rlm@1
|
359 const MemoryRegion& nextRegion = *nextRegionPtr;
|
rlm@1
|
360 int nextStartSkipSize = ((unsigned int)(sizeof(stepType) - nextRegion.hardwareAddress)) % sizeof(stepType);
|
rlm@1
|
361 unsigned int nextIndexStart = nextRegion.virtualIndex + nextStartSkipSize;
|
rlm@1
|
362 if(lastIndexToCopy > nextIndexStart)
|
rlm@1
|
363 lastIndexToCopy = nextIndexStart;
|
rlm@1
|
364 }
|
rlm@1
|
365
|
rlm@1
|
366 unsigned int nextValidChange [sizeof(compareType)];
|
rlm@1
|
367 for(unsigned int i = 0; i < sizeof(compareType); i++)
|
rlm@1
|
368 nextValidChange[i] = indexStart + i;
|
rlm@1
|
369
|
rlm@1
|
370 for(unsigned int i = indexStart, j = 0; i < lastIndexToRead; i++, j++)
|
rlm@1
|
371 {
|
rlm@1
|
372 if(s_curValues[i] != sourceAddr[i]) // if value of this byte changed
|
rlm@1
|
373 {
|
rlm@1
|
374 if(i < lastIndexToCopy)
|
rlm@1
|
375 s_curValues[i] = sourceAddr[i]; // update value
|
rlm@1
|
376 for(int k = 0; k < sizeof(compareType); k++) // loop through the previous entries that contain this byte
|
rlm@1
|
377 {
|
rlm@1
|
378 if(i >= indexEnd+k)
|
rlm@1
|
379 continue;
|
rlm@1
|
380 int m = (j-k+sizeof(compareType)) & (sizeof(compareType)-1);
|
rlm@1
|
381 if(nextValidChange[m] <= i) // if we didn't already increase the change count for this entry
|
rlm@1
|
382 {
|
rlm@1
|
383 //if(s_numChanges[i-k] != 0xFFFF)
|
rlm@1
|
384 s_numChanges[i-k]++; // increase the change count for this entry
|
rlm@1
|
385 nextValidChange[m] = i-k+sizeof(compareType); // and remember not to increase it again
|
rlm@1
|
386 }
|
rlm@1
|
387 }
|
rlm@1
|
388 }
|
rlm@1
|
389 }
|
rlm@1
|
390 }
|
rlm@1
|
391 }
|
rlm@1
|
392
|
rlm@1
|
393 template<typename stepType, typename compareType>
|
rlm@1
|
394 void UpdateRegionsT()
|
rlm@1
|
395 {
|
rlm@1
|
396 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end();)
|
rlm@1
|
397 {
|
rlm@1
|
398 const MemoryRegion& region = *iter;
|
rlm@1
|
399 ++iter;
|
rlm@1
|
400 const MemoryRegion* nextRegion = (iter == s_activeMemoryRegions.end()) ? NULL : &*iter;
|
rlm@1
|
401
|
rlm@1
|
402 UpdateRegionT<stepType, compareType>(region, nextRegion);
|
rlm@1
|
403 }
|
rlm@1
|
404
|
rlm@1
|
405 s_prevValuesNeedUpdate = false;
|
rlm@1
|
406 }
|
rlm@1
|
407
|
rlm@1
|
408 template<typename stepType, typename compareType>
|
rlm@1
|
409 int CountRegionItemsT()
|
rlm@1
|
410 {
|
rlm@1
|
411 AutoCritSect cs(&s_activeMemoryRegionsCS);
|
rlm@1
|
412 if(sizeof(stepType) == 1)
|
rlm@1
|
413 {
|
rlm@1
|
414 if(s_activeMemoryRegions.empty())
|
rlm@1
|
415 return 0;
|
rlm@1
|
416
|
rlm@1
|
417 if(s_itemIndicesInvalid)
|
rlm@1
|
418 CalculateItemIndices(sizeof(stepType));
|
rlm@1
|
419
|
rlm@1
|
420 MemoryRegion& lastRegion = s_activeMemoryRegions.back();
|
rlm@1
|
421 return lastRegion.itemIndex + lastRegion.size;
|
rlm@1
|
422 }
|
rlm@1
|
423 else // the branch above is faster but won't work if the step size isn't 1
|
rlm@1
|
424 {
|
rlm@1
|
425 int total = 0;
|
rlm@1
|
426 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)
|
rlm@1
|
427 {
|
rlm@1
|
428 MemoryRegion& region = *iter;
|
rlm@1
|
429 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
|
rlm@1
|
430 total += (region.size - startSkipSize + (sizeof(stepType)-1)) / sizeof(stepType);
|
rlm@1
|
431 }
|
rlm@1
|
432 return total;
|
rlm@1
|
433 }
|
rlm@1
|
434 }
|
rlm@1
|
435
|
rlm@1
|
436 // returns information about the item in the form of a "fake" region
|
rlm@1
|
437 // that has the item in it and nothing else
|
rlm@1
|
438 template<typename stepType, typename compareType>
|
rlm@1
|
439 void ItemIndexToVirtualRegion(unsigned int itemIndex, MemoryRegion& virtualRegion)
|
rlm@1
|
440 {
|
rlm@1
|
441 if(s_itemIndicesInvalid)
|
rlm@1
|
442 CalculateItemIndices(sizeof(stepType));
|
rlm@1
|
443
|
rlm@1
|
444 if(itemIndex >= s_maxItemIndex)
|
rlm@1
|
445 {
|
rlm@1
|
446 memset(&virtualRegion, 0, sizeof(MemoryRegion));
|
rlm@1
|
447 return;
|
rlm@1
|
448 }
|
rlm@1
|
449
|
rlm@1
|
450 const MemoryRegion* regionPtr = s_itemIndexToRegionPointer[itemIndex];
|
rlm@1
|
451 const MemoryRegion& region = *regionPtr;
|
rlm@1
|
452
|
rlm@1
|
453 int bytesWithinRegion = (itemIndex - region.itemIndex) * sizeof(stepType);
|
rlm@1
|
454 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
|
rlm@1
|
455 bytesWithinRegion += startSkipSize;
|
rlm@1
|
456
|
rlm@1
|
457 virtualRegion.size = sizeof(compareType);
|
rlm@1
|
458 virtualRegion.hardwareAddress = region.hardwareAddress + bytesWithinRegion;
|
rlm@1
|
459 virtualRegion.softwareAddress = region.softwareAddress + bytesWithinRegion;
|
rlm@1
|
460 virtualRegion.virtualIndex = region.virtualIndex + bytesWithinRegion;
|
rlm@1
|
461 virtualRegion.itemIndex = itemIndex;
|
rlm@1
|
462 return;
|
rlm@1
|
463 }
|
rlm@1
|
464
|
rlm@1
|
465 template<typename stepType, typename compareType>
|
rlm@1
|
466 unsigned int ItemIndexToVirtualIndex(unsigned int itemIndex)
|
rlm@1
|
467 {
|
rlm@1
|
468 MemoryRegion virtualRegion;
|
rlm@1
|
469 ItemIndexToVirtualRegion<stepType,compareType>(itemIndex, virtualRegion);
|
rlm@1
|
470 return virtualRegion.virtualIndex;
|
rlm@1
|
471 }
|
rlm@1
|
472
|
rlm@1
|
473 template<typename T>
|
rlm@1
|
474 T ReadLocalValue(const unsigned char* data)
|
rlm@1
|
475 {
|
rlm@1
|
476 return *(const T*)data;
|
rlm@1
|
477 }
|
rlm@1
|
478 //template<> signed char ReadLocalValue(const unsigned char* data) { return *data; }
|
rlm@1
|
479 //template<> unsigned char ReadLocalValue(const unsigned char* data) { return *data; }
|
rlm@1
|
480
|
rlm@1
|
481
|
rlm@1
|
482 template<typename stepType, typename compareType>
|
rlm@1
|
483 compareType GetPrevValueFromVirtualIndex(unsigned int virtualIndex)
|
rlm@1
|
484 {
|
rlm@1
|
485 return ReadLocalValue<compareType>(s_prevValues + virtualIndex);
|
rlm@1
|
486 //return *(compareType*)(s_prevValues+virtualIndex);
|
rlm@1
|
487 }
|
rlm@1
|
488 template<typename stepType, typename compareType>
|
rlm@1
|
489 compareType GetCurValueFromVirtualIndex(unsigned int virtualIndex)
|
rlm@1
|
490 {
|
rlm@1
|
491 return ReadLocalValue<compareType>(s_curValues + virtualIndex);
|
rlm@1
|
492 // return *(compareType*)(s_curValues+virtualIndex);
|
rlm@1
|
493 }
|
rlm@1
|
494 template<typename stepType, typename compareType>
|
rlm@1
|
495 unsigned short GetNumChangesFromVirtualIndex(unsigned int virtualIndex)
|
rlm@1
|
496 {
|
rlm@1
|
497 unsigned short num = s_numChanges[virtualIndex];
|
rlm@1
|
498 //for(unsigned int i = 1; i < sizeof(stepType); i++)
|
rlm@1
|
499 // if(num < s_numChanges[virtualIndex+i])
|
rlm@1
|
500 // num = s_numChanges[virtualIndex+i];
|
rlm@1
|
501 return num;
|
rlm@1
|
502 }
|
rlm@1
|
503
|
rlm@1
|
504 template<typename stepType, typename compareType>
|
rlm@1
|
505 compareType GetPrevValueFromItemIndex(unsigned int itemIndex)
|
rlm@1
|
506 {
|
rlm@1
|
507 int virtualIndex = ItemIndexToVirtualIndex<stepType,compareType>(itemIndex);
|
rlm@1
|
508 return GetPrevValueFromVirtualIndex<stepType,compareType>(virtualIndex);
|
rlm@1
|
509 }
|
rlm@1
|
510 template<typename stepType, typename compareType>
|
rlm@1
|
511 compareType GetCurValueFromItemIndex(unsigned int itemIndex)
|
rlm@1
|
512 {
|
rlm@1
|
513 int virtualIndex = ItemIndexToVirtualIndex<stepType,compareType>(itemIndex);
|
rlm@1
|
514 return GetCurValueFromVirtualIndex<stepType,compareType>(virtualIndex);
|
rlm@1
|
515 }
|
rlm@1
|
516 template<typename stepType, typename compareType>
|
rlm@1
|
517 unsigned short GetNumChangesFromItemIndex(unsigned int itemIndex)
|
rlm@1
|
518 {
|
rlm@1
|
519 int virtualIndex = ItemIndexToVirtualIndex<stepType,compareType>(itemIndex);
|
rlm@1
|
520 return GetNumChangesFromVirtualIndex<stepType,compareType>(virtualIndex);
|
rlm@1
|
521 }
|
rlm@1
|
522 template<typename stepType, typename compareType>
|
rlm@1
|
523 unsigned int GetHardwareAddressFromItemIndex(unsigned int itemIndex)
|
rlm@1
|
524 {
|
rlm@1
|
525 MemoryRegion virtualRegion;
|
rlm@1
|
526 ItemIndexToVirtualRegion<stepType,compareType>(itemIndex, virtualRegion);
|
rlm@1
|
527 return virtualRegion.hardwareAddress;
|
rlm@1
|
528 }
|
rlm@1
|
529
|
rlm@1
|
530 // this one might be unreliable, haven't used it much
|
rlm@1
|
531 template<typename stepType, typename compareType>
|
rlm@1
|
532 unsigned int HardwareAddressToItemIndex(HWAddressType hardwareAddress)
|
rlm@1
|
533 {
|
rlm@1
|
534 if(s_itemIndicesInvalid)
|
rlm@1
|
535 CalculateItemIndices(sizeof(stepType));
|
rlm@1
|
536
|
rlm@1
|
537 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)
|
rlm@1
|
538 {
|
rlm@1
|
539 MemoryRegion& region = *iter;
|
rlm@1
|
540 if(hardwareAddress >= region.hardwareAddress && hardwareAddress < region.hardwareAddress + region.size)
|
rlm@1
|
541 {
|
rlm@1
|
542 int indexWithinRegion = (hardwareAddress - region.hardwareAddress) / sizeof(stepType);
|
rlm@1
|
543 return region.itemIndex + indexWithinRegion;
|
rlm@1
|
544 }
|
rlm@1
|
545 }
|
rlm@1
|
546
|
rlm@1
|
547 return -1;
|
rlm@1
|
548 }
|
rlm@1
|
549
|
rlm@1
|
550
|
rlm@1
|
551
|
rlm@1
|
552 // workaround for MSVC 7 that doesn't support varadic C99 macros
|
rlm@1
|
553 #define CALL_WITH_T_SIZE_TYPES_0(functionName, sizeTypeID, isSigned, requiresAligned) \
|
rlm@1
|
554 (sizeTypeID == 'b' \
|
rlm@1
|
555 ? (isSigned \
|
rlm@1
|
556 ? functionName<char, signed char>() \
|
rlm@1
|
557 : functionName<char, unsigned char>()) \
|
rlm@1
|
558 : sizeTypeID == 'w' \
|
rlm@1
|
559 ? (isSigned \
|
rlm@1
|
560 ? (requiresAligned \
|
rlm@1
|
561 ? functionName<short, signed short>() \
|
rlm@1
|
562 : functionName<char, signed short>()) \
|
rlm@1
|
563 : (requiresAligned \
|
rlm@1
|
564 ? functionName<short, unsigned short>() \
|
rlm@1
|
565 : functionName<char, unsigned short>())) \
|
rlm@1
|
566 : sizeTypeID == 'd' \
|
rlm@1
|
567 ? (isSigned \
|
rlm@1
|
568 ? (requiresAligned \
|
rlm@1
|
569 ? functionName<short, signed long>() \
|
rlm@1
|
570 : functionName<char, signed long>()) \
|
rlm@1
|
571 : (requiresAligned \
|
rlm@1
|
572 ? functionName<short, unsigned long>() \
|
rlm@1
|
573 : functionName<char, unsigned long>())) \
|
rlm@1
|
574 : functionName<char, signed char>())
|
rlm@1
|
575
|
rlm@1
|
576 #define CALL_WITH_T_SIZE_TYPES_1(functionName, sizeTypeID, isSigned, requiresAligned, p0) \
|
rlm@1
|
577 (sizeTypeID == 'b' \
|
rlm@1
|
578 ? (isSigned \
|
rlm@1
|
579 ? functionName<char, signed char>(p0) \
|
rlm@1
|
580 : functionName<char, unsigned char>(p0)) \
|
rlm@1
|
581 : sizeTypeID == 'w' \
|
rlm@1
|
582 ? (isSigned \
|
rlm@1
|
583 ? (requiresAligned \
|
rlm@1
|
584 ? functionName<short, signed short>(p0) \
|
rlm@1
|
585 : functionName<char, signed short>(p0)) \
|
rlm@1
|
586 : (requiresAligned \
|
rlm@1
|
587 ? functionName<short, unsigned short>(p0) \
|
rlm@1
|
588 : functionName<char, unsigned short>(p0))) \
|
rlm@1
|
589 : sizeTypeID == 'd' \
|
rlm@1
|
590 ? (isSigned \
|
rlm@1
|
591 ? (requiresAligned \
|
rlm@1
|
592 ? functionName<short, signed long>(p0) \
|
rlm@1
|
593 : functionName<char, signed long>(p0)) \
|
rlm@1
|
594 : (requiresAligned \
|
rlm@1
|
595 ? functionName<short, unsigned long>(p0) \
|
rlm@1
|
596 : functionName<char, unsigned long>(p0))) \
|
rlm@1
|
597 : functionName<char, signed char>(p0))
|
rlm@1
|
598
|
rlm@1
|
599 #define CALL_WITH_T_SIZE_TYPES_3(functionName, sizeTypeID, isSigned, requiresAligned, p0, p1, p2) \
|
rlm@1
|
600 (sizeTypeID == 'b' \
|
rlm@1
|
601 ? (isSigned \
|
rlm@1
|
602 ? functionName<char, signed char>(p0, p1, p2) \
|
rlm@1
|
603 : functionName<char, unsigned char>(p0, p1, p2)) \
|
rlm@1
|
604 : sizeTypeID == 'w' \
|
rlm@1
|
605 ? (isSigned \
|
rlm@1
|
606 ? (requiresAligned \
|
rlm@1
|
607 ? functionName<short, signed short>(p0, p1, p2) \
|
rlm@1
|
608 : functionName<char, signed short>(p0, p1, p2)) \
|
rlm@1
|
609 : (requiresAligned \
|
rlm@1
|
610 ? functionName<short, unsigned short>(p0, p1, p2) \
|
rlm@1
|
611 : functionName<char, unsigned short>(p0, p1, p2))) \
|
rlm@1
|
612 : sizeTypeID == 'd' \
|
rlm@1
|
613 ? (isSigned \
|
rlm@1
|
614 ? (requiresAligned \
|
rlm@1
|
615 ? functionName<short, signed long>(p0, p1, p2) \
|
rlm@1
|
616 : functionName<char, signed long>(p0, p1, p2)) \
|
rlm@1
|
617 : (requiresAligned \
|
rlm@1
|
618 ? functionName<short, unsigned long>(p0, p1, p2) \
|
rlm@1
|
619 : functionName<char, unsigned long>(p0, p1, p2))) \
|
rlm@1
|
620 : functionName<char, signed char>(p0, p1, p2))
|
rlm@1
|
621
|
rlm@1
|
622 #define CALL_WITH_T_SIZE_TYPES_4(functionName, sizeTypeID, isSigned, requiresAligned, p0, p1, p2, p3) \
|
rlm@1
|
623 (sizeTypeID == 'b' \
|
rlm@1
|
624 ? (isSigned \
|
rlm@1
|
625 ? functionName<char, signed char>(p0, p1, p2, p3) \
|
rlm@1
|
626 : functionName<char, unsigned char>(p0, p1, p2, p3)) \
|
rlm@1
|
627 : sizeTypeID == 'w' \
|
rlm@1
|
628 ? (isSigned \
|
rlm@1
|
629 ? (requiresAligned \
|
rlm@1
|
630 ? functionName<short, signed short>(p0, p1, p2, p3) \
|
rlm@1
|
631 : functionName<char, signed short>(p0, p1, p2, p3)) \
|
rlm@1
|
632 : (requiresAligned \
|
rlm@1
|
633 ? functionName<short, unsigned short>(p0, p1, p2, p3) \
|
rlm@1
|
634 : functionName<char, unsigned short>(p0, p1, p2, p3))) \
|
rlm@1
|
635 : sizeTypeID == 'd' \
|
rlm@1
|
636 ? (isSigned \
|
rlm@1
|
637 ? (requiresAligned \
|
rlm@1
|
638 ? functionName<short, signed long>(p0, p1, p2, p3) \
|
rlm@1
|
639 : functionName<char, signed long>(p0, p1, p2, p3)) \
|
rlm@1
|
640 : (requiresAligned \
|
rlm@1
|
641 ? functionName<short, unsigned long>(p0, p1, p2, p3) \
|
rlm@1
|
642 : functionName<char, unsigned long>(p0, p1, p2, p3))) \
|
rlm@1
|
643 : functionName<char, signed char>(p0, p1, p2, p3))
|
rlm@1
|
644
|
rlm@1
|
645 // version that takes a forced comparison type
|
rlm@1
|
646 #define CALL_WITH_T_STEP_3(functionName, sizeTypeID, type, requiresAligned, p0, p1, p2) \
|
rlm@1
|
647 (sizeTypeID == 'b' \
|
rlm@1
|
648 ? functionName<char, type>(p0, p1, p2) \
|
rlm@1
|
649 : sizeTypeID == 'w' \
|
rlm@1
|
650 ? (requiresAligned \
|
rlm@1
|
651 ? functionName<short, type>(p0, p1, p2) \
|
rlm@1
|
652 : functionName<char, type>(p0, p1, p2)) \
|
rlm@1
|
653 : sizeTypeID == 'd' \
|
rlm@1
|
654 ? (requiresAligned \
|
rlm@1
|
655 ? functionName<short, type>(p0, p1, p2) \
|
rlm@1
|
656 : functionName<char, type>(p0, p1, p2)) \
|
rlm@1
|
657 : functionName<char, type>(p0, p1, p2))
|
rlm@1
|
658
|
rlm@1
|
659 // version that takes a forced comparison type
|
rlm@1
|
660 #define CALL_WITH_T_STEP_4(functionName, sizeTypeID, type, requiresAligned, p0, p1, p2, p3) \
|
rlm@1
|
661 (sizeTypeID == 'b' \
|
rlm@1
|
662 ? functionName<char, type>(p0, p1, p2, p3) \
|
rlm@1
|
663 : sizeTypeID == 'w' \
|
rlm@1
|
664 ? (requiresAligned \
|
rlm@1
|
665 ? functionName<short, type>(p0, p1, p2, p3) \
|
rlm@1
|
666 : functionName<char, type>(p0, p1, p2, p3)) \
|
rlm@1
|
667 : sizeTypeID == 'd' \
|
rlm@1
|
668 ? (requiresAligned \
|
rlm@1
|
669 ? functionName<short, type>(p0, p1, p2, p3) \
|
rlm@1
|
670 : functionName<char, type>(p0, p1, p2, p3)) \
|
rlm@1
|
671 : functionName<char, type>(p0, p1, p2, p3))
|
rlm@1
|
672
|
rlm@1
|
673 // basic comparison functions:
|
rlm@1
|
674 template <typename T> inline bool LessCmp (T x, T y, T i) { return x < y; }
|
rlm@1
|
675 template <typename T> inline bool MoreCmp (T x, T y, T i) { return x > y; }
|
rlm@1
|
676 template <typename T> inline bool LessEqualCmp (T x, T y, T i) { return x <= y; }
|
rlm@1
|
677 template <typename T> inline bool MoreEqualCmp (T x, T y, T i) { return x >= y; }
|
rlm@1
|
678 template <typename T> inline bool EqualCmp (T x, T y, T i) { return x == y; }
|
rlm@1
|
679 template <typename T> inline bool UnequalCmp (T x, T y, T i) { return x != y; }
|
rlm@1
|
680 template <typename T> inline bool DiffByCmp (T x, T y, T p) { return x - y == p || y - x == p; }
|
rlm@1
|
681 template <typename T> inline bool ModIsCmp (T x, T y, T p) { return p && x % p == y; }
|
rlm@1
|
682
|
rlm@1
|
683 // compare-to type functions:
|
rlm@1
|
684 template<typename stepType, typename T>
|
rlm@1
|
685 void SearchRelative (bool(*cmpFun)(T,T,T), T ignored, T param)
|
rlm@1
|
686 {
|
rlm@1
|
687 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )
|
rlm@1
|
688 {
|
rlm@1
|
689 MemoryRegion& region = *iter;
|
rlm@1
|
690 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
|
rlm@1
|
691 unsigned int start = region.virtualIndex + startSkipSize;
|
rlm@1
|
692 unsigned int end = region.virtualIndex + region.size;
|
rlm@1
|
693 for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType))
|
rlm@1
|
694 if(!cmpFun(GetCurValueFromVirtualIndex<stepType,T>(i), GetPrevValueFromVirtualIndex<stepType,T>(i), param))
|
rlm@1
|
695 if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType)))
|
rlm@1
|
696 goto outerContinue;
|
rlm@1
|
697 ++iter;
|
rlm@1
|
698 outerContinue:
|
rlm@1
|
699 continue;
|
rlm@1
|
700 }
|
rlm@1
|
701 }
|
rlm@1
|
702 template<typename stepType, typename T>
|
rlm@1
|
703 void SearchSpecific (bool(*cmpFun)(T,T,T), T value, T param)
|
rlm@1
|
704 {
|
rlm@1
|
705 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )
|
rlm@1
|
706 {
|
rlm@1
|
707 MemoryRegion& region = *iter;
|
rlm@1
|
708 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
|
rlm@1
|
709 unsigned int start = region.virtualIndex + startSkipSize;
|
rlm@1
|
710 unsigned int end = region.virtualIndex + region.size;
|
rlm@1
|
711 for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType))
|
rlm@1
|
712 if(!cmpFun(GetCurValueFromVirtualIndex<stepType,T>(i), value, param))
|
rlm@1
|
713 if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType)))
|
rlm@1
|
714 goto outerContinue;
|
rlm@1
|
715 ++iter;
|
rlm@1
|
716 outerContinue:
|
rlm@1
|
717 continue;
|
rlm@1
|
718 }
|
rlm@1
|
719 }
|
rlm@1
|
720 template<typename stepType, typename T>
|
rlm@1
|
721 void SearchAddress (bool(*cmpFun)(T,T,T), T address, T param)
|
rlm@1
|
722 {
|
rlm@1
|
723 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )
|
rlm@1
|
724 {
|
rlm@1
|
725 MemoryRegion& region = *iter;
|
rlm@1
|
726 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
|
rlm@1
|
727 unsigned int start = region.virtualIndex + startSkipSize;
|
rlm@1
|
728 unsigned int end = region.virtualIndex + region.size;
|
rlm@1
|
729 for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType))
|
rlm@1
|
730 if(!cmpFun(hwaddr, address, param))
|
rlm@1
|
731 if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType)))
|
rlm@1
|
732 goto outerContinue;
|
rlm@1
|
733 ++iter;
|
rlm@1
|
734 outerContinue:
|
rlm@1
|
735 continue;
|
rlm@1
|
736 }
|
rlm@1
|
737 }
|
rlm@1
|
738 template<typename stepType, typename T>
|
rlm@1
|
739 void SearchChanges (bool(*cmpFun)(T,T,T), T changes, T param)
|
rlm@1
|
740 {
|
rlm@1
|
741 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )
|
rlm@1
|
742 {
|
rlm@1
|
743 MemoryRegion& region = *iter;
|
rlm@1
|
744 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
|
rlm@1
|
745 unsigned int start = region.virtualIndex + startSkipSize;
|
rlm@1
|
746 unsigned int end = region.virtualIndex + region.size;
|
rlm@1
|
747 for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType))
|
rlm@1
|
748 if(!cmpFun(GetNumChangesFromVirtualIndex<stepType,T>(i), changes, param))
|
rlm@1
|
749 if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType)))
|
rlm@1
|
750 goto outerContinue;
|
rlm@1
|
751 ++iter;
|
rlm@1
|
752 outerContinue:
|
rlm@1
|
753 continue;
|
rlm@1
|
754 }
|
rlm@1
|
755 }
|
rlm@1
|
756
|
rlm@1
|
757 char rs_c='s';
|
rlm@1
|
758 char rs_o='=';
|
rlm@1
|
759 char rs_t='s';
|
rlm@1
|
760 int rs_param=0, rs_val=0, rs_val_valid=0;
|
rlm@1
|
761 char rs_type_size = 'b', rs_last_type_size = rs_type_size;
|
rlm@1
|
762 bool noMisalign = true, rs_last_no_misalign = noMisalign;
|
rlm@1
|
763 //bool littleEndian = false;
|
rlm@1
|
764 int last_rs_possible = -1;
|
rlm@1
|
765 int last_rs_regions = -1;
|
rlm@1
|
766
|
rlm@1
|
767 void prune(char c,char o,char t,int v,int p)
|
rlm@1
|
768 {
|
rlm@1
|
769 // repetition-reducing macros
|
rlm@1
|
770 #define DO_SEARCH(sf) \
|
rlm@1
|
771 switch (o) \
|
rlm@1
|
772 { \
|
rlm@1
|
773 case '<': DO_SEARCH_2(LessCmp,sf); break; \
|
rlm@1
|
774 case '>': DO_SEARCH_2(MoreCmp,sf); break; \
|
rlm@1
|
775 case '=': DO_SEARCH_2(EqualCmp,sf); break; \
|
rlm@1
|
776 case '!': DO_SEARCH_2(UnequalCmp,sf); break; \
|
rlm@1
|
777 case 'l': DO_SEARCH_2(LessEqualCmp,sf); break; \
|
rlm@1
|
778 case 'm': DO_SEARCH_2(MoreEqualCmp,sf); break; \
|
rlm@1
|
779 case 'd': DO_SEARCH_2(DiffByCmp,sf); break; \
|
rlm@1
|
780 case '%': DO_SEARCH_2(ModIsCmp,sf); break; \
|
rlm@1
|
781 default: assert(!"Invalid operator for this search type."); break; \
|
rlm@1
|
782 }
|
rlm@1
|
783
|
rlm@1
|
784 // perform the search, eliminating nonmatching values
|
rlm@1
|
785 switch (c)
|
rlm@1
|
786 {
|
rlm@1
|
787 #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_SIZE_TYPES_3(sf, rs_type_size, t, noMisalign, CmpFun,v,p)
|
rlm@1
|
788 case 'r': DO_SEARCH(SearchRelative); break;
|
rlm@1
|
789 case 's': DO_SEARCH(SearchSpecific); break;
|
rlm@1
|
790
|
rlm@1
|
791 #undef DO_SEARCH_2
|
rlm@1
|
792 #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP_3(sf, rs_type_size, unsigned int, noMisalign, CmpFun,v,p)
|
rlm@1
|
793 case 'a': DO_SEARCH(SearchAddress); break;
|
rlm@1
|
794
|
rlm@1
|
795 #undef DO_SEARCH_2
|
rlm@1
|
796 #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP_3(sf, rs_type_size, unsigned short, noMisalign, CmpFun,v,p)
|
rlm@1
|
797 case 'n': DO_SEARCH(SearchChanges); break;
|
rlm@1
|
798
|
rlm@1
|
799 default: assert(!"Invalid search comparison type."); break;
|
rlm@1
|
800 }
|
rlm@1
|
801
|
rlm@1
|
802 s_prevValuesNeedUpdate = true;
|
rlm@1
|
803
|
rlm@1
|
804 int prevNumItems = last_rs_possible;
|
rlm@1
|
805
|
rlm@1
|
806 CompactAddrs();
|
rlm@1
|
807
|
rlm@1
|
808 if(prevNumItems == last_rs_possible)
|
rlm@1
|
809 {
|
rlm@1
|
810 SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo
|
rlm@1
|
811 }
|
rlm@1
|
812 }
|
rlm@1
|
813
|
rlm@1
|
814
|
rlm@1
|
815
|
rlm@1
|
816
|
rlm@1
|
817 template<typename stepType, typename T>
|
rlm@1
|
818 bool CompareRelativeAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T ignored, T param)
|
rlm@1
|
819 {
|
rlm@1
|
820 return cmpFun(GetCurValueFromItemIndex<stepType,T>(itemIndex), GetPrevValueFromItemIndex<stepType,T>(itemIndex), param);
|
rlm@1
|
821 }
|
rlm@1
|
822 template<typename stepType, typename T>
|
rlm@1
|
823 bool CompareSpecificAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T value, T param)
|
rlm@1
|
824 {
|
rlm@1
|
825 return cmpFun(GetCurValueFromItemIndex<stepType,T>(itemIndex), value, param);
|
rlm@1
|
826 }
|
rlm@1
|
827 template<typename stepType, typename T>
|
rlm@1
|
828 bool CompareAddressAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T address, T param)
|
rlm@1
|
829 {
|
rlm@1
|
830 return cmpFun(GetHardwareAddressFromItemIndex<stepType,T>(itemIndex), address, param);
|
rlm@1
|
831 }
|
rlm@1
|
832 template<typename stepType, typename T>
|
rlm@1
|
833 bool CompareChangesAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T changes, T param)
|
rlm@1
|
834 {
|
rlm@1
|
835 return cmpFun(GetNumChangesFromItemIndex<stepType,T>(itemIndex), changes, param);
|
rlm@1
|
836 }
|
rlm@1
|
837
|
rlm@1
|
838 int ReadControlInt(int controlID, bool forceHex, BOOL& success)
|
rlm@1
|
839 {
|
rlm@1
|
840 int rv = 0;
|
rlm@1
|
841 BOOL ok = false;
|
rlm@1
|
842
|
rlm@1
|
843 if(!forceHex)
|
rlm@1
|
844 {
|
rlm@1
|
845 rv = GetDlgItemInt(RamSearchHWnd,controlID,&ok,(rs_t == 's'));
|
rlm@1
|
846 }
|
rlm@1
|
847
|
rlm@1
|
848 if(!ok)
|
rlm@1
|
849 {
|
rlm@1
|
850 if(GetDlgItemText(RamSearchHWnd,controlID,Str_Tmp,16))
|
rlm@1
|
851 {
|
rlm@1
|
852 for(int i = 0; Str_Tmp[i]; i++) {if(toupper(Str_Tmp[i]) == 'O') Str_Tmp[i] = '0';}
|
rlm@1
|
853 const char* strPtr = Str_Tmp;
|
rlm@1
|
854 bool negate = false;
|
rlm@1
|
855 while(strPtr[0] == '-')
|
rlm@1
|
856 strPtr++, negate = !negate;
|
rlm@1
|
857 if(strPtr[0] == '+')
|
rlm@1
|
858 strPtr++;
|
rlm@1
|
859 if(strPtr[0] == '0' && tolower(strPtr[1]) == 'x')
|
rlm@1
|
860 strPtr += 2, forceHex = true;
|
rlm@1
|
861 if(strPtr[0] == '$')
|
rlm@1
|
862 strPtr++, forceHex = true;
|
rlm@1
|
863 if(!forceHex)
|
rlm@1
|
864 {
|
rlm@1
|
865 const char* strSearchPtr = strPtr;
|
rlm@1
|
866 while(*strSearchPtr)
|
rlm@1
|
867 {
|
rlm@1
|
868 int c = tolower(*strSearchPtr++);
|
rlm@1
|
869 if(c >= 'a' && c <= 'f')
|
rlm@1
|
870 forceHex = true;
|
rlm@1
|
871 }
|
rlm@1
|
872 }
|
rlm@1
|
873 const char* formatString = forceHex ? "%X" : ((rs_t=='s') ? "%d" : "%u");
|
rlm@1
|
874 if(sscanf(strPtr, formatString, &rv) > 0)
|
rlm@1
|
875 ok = true;
|
rlm@1
|
876 if(negate)
|
rlm@1
|
877 rv = -rv;
|
rlm@1
|
878 }
|
rlm@1
|
879 }
|
rlm@1
|
880
|
rlm@1
|
881 success = ok;
|
rlm@1
|
882 return rv;
|
rlm@1
|
883 }
|
rlm@1
|
884
|
rlm@1
|
885
|
rlm@1
|
886 bool Set_RS_Val()
|
rlm@1
|
887 {
|
rlm@1
|
888 BOOL success;
|
rlm@1
|
889
|
rlm@1
|
890 // update rs_val
|
rlm@1
|
891 switch(rs_c)
|
rlm@1
|
892 {
|
rlm@1
|
893 case 'r':
|
rlm@1
|
894 default:
|
rlm@1
|
895 rs_val = 0;
|
rlm@1
|
896 break;
|
rlm@1
|
897 case 's':
|
rlm@1
|
898 rs_val = ReadControlInt(IDC_EDIT_COMPAREVALUE, rs_t == 'h', success);
|
rlm@1
|
899 if(!success)
|
rlm@1
|
900 return false;
|
rlm@1
|
901 if((rs_type_size == 'b' && rs_t == 's' && (rs_val < -128 || rs_val > 127)) ||
|
rlm@1
|
902 (rs_type_size == 'b' && rs_t != 's' && (rs_val < 0 || rs_val > 255)) ||
|
rlm@1
|
903 (rs_type_size == 'w' && rs_t == 's' && (rs_val < -32768 || rs_val > 32767)) ||
|
rlm@1
|
904 (rs_type_size == 'w' && rs_t != 's' && (rs_val < 0 || rs_val > 65535)))
|
rlm@1
|
905 return false;
|
rlm@1
|
906 break;
|
rlm@1
|
907 case 'a':
|
rlm@1
|
908 rs_val = ReadControlInt(IDC_EDIT_COMPAREADDRESS, true, success);
|
rlm@1
|
909 if(!success || rs_val < 0 || rs_val > 0x06040000)
|
rlm@1
|
910 return false;
|
rlm@1
|
911 break;
|
rlm@1
|
912 case 'n': {
|
rlm@1
|
913 rs_val = ReadControlInt(IDC_EDIT_COMPARECHANGES, false, success);
|
rlm@1
|
914 if(!success || rs_val < 0 || rs_val > 0xFFFF)
|
rlm@1
|
915 return false;
|
rlm@1
|
916 } break;
|
rlm@1
|
917 }
|
rlm@1
|
918
|
rlm@1
|
919 // also update rs_param
|
rlm@1
|
920 switch(rs_o)
|
rlm@1
|
921 {
|
rlm@1
|
922 default:
|
rlm@1
|
923 rs_param = 0;
|
rlm@1
|
924 break;
|
rlm@1
|
925 case 'd':
|
rlm@1
|
926 rs_param = ReadControlInt(IDC_EDIT_DIFFBY, false, success);
|
rlm@1
|
927 if(!success)
|
rlm@1
|
928 return false;
|
rlm@1
|
929 if(rs_param < 0)
|
rlm@1
|
930 rs_param = -rs_param;
|
rlm@1
|
931 break;
|
rlm@1
|
932 case '%':
|
rlm@1
|
933 rs_param = ReadControlInt(IDC_EDIT_MODBY, false, success);
|
rlm@1
|
934 if(!success || rs_param == 0)
|
rlm@1
|
935 return false;
|
rlm@1
|
936 break;
|
rlm@1
|
937 }
|
rlm@1
|
938
|
rlm@1
|
939 // validate that rs_param fits in the comparison data type
|
rlm@1
|
940 {
|
rlm@1
|
941 int appliedSize = rs_type_size;
|
rlm@1
|
942 int appliedSign = rs_t;
|
rlm@1
|
943 if(rs_c == 'n')
|
rlm@1
|
944 appliedSize = 'w', appliedSign = 'u';
|
rlm@1
|
945 if(rs_c == 'a')
|
rlm@1
|
946 appliedSize = 'd', appliedSign = 'u';
|
rlm@1
|
947 if((appliedSize == 'b' && appliedSize == 's' && (rs_param < -128 || rs_param > 127)) ||
|
rlm@1
|
948 (appliedSize == 'b' && appliedSize != 's' && (rs_param < 0 || rs_param > 255)) ||
|
rlm@1
|
949 (appliedSize == 'w' && appliedSize == 's' && (rs_param < -32768 || rs_param > 32767)) ||
|
rlm@1
|
950 (appliedSize == 'w' && appliedSize != 's' && (rs_param < 0 || rs_param > 65535)))
|
rlm@1
|
951 return false;
|
rlm@1
|
952 }
|
rlm@1
|
953
|
rlm@1
|
954 return true;
|
rlm@1
|
955 }
|
rlm@1
|
956
|
rlm@1
|
957 bool IsSatisfied(int itemIndex)
|
rlm@1
|
958 {
|
rlm@1
|
959 if(!rs_val_valid)
|
rlm@1
|
960 return true;
|
rlm@1
|
961 int o = rs_o;
|
rlm@1
|
962 switch (rs_c)
|
rlm@1
|
963 {
|
rlm@1
|
964 #undef DO_SEARCH_2
|
rlm@1
|
965 #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_SIZE_TYPES_4(sf, rs_type_size,(rs_t=='s'),noMisalign, CmpFun,itemIndex,rs_val,rs_param);
|
rlm@1
|
966 case 'r': DO_SEARCH(CompareRelativeAtItem); break;
|
rlm@1
|
967 case 's': DO_SEARCH(CompareSpecificAtItem); break;
|
rlm@1
|
968
|
rlm@1
|
969 #undef DO_SEARCH_2
|
rlm@1
|
970 #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_STEP_4(sf, rs_type_size, unsigned int, noMisalign, CmpFun,itemIndex,rs_val,rs_param);
|
rlm@1
|
971 case 'a': DO_SEARCH(CompareAddressAtItem); break;
|
rlm@1
|
972
|
rlm@1
|
973 #undef DO_SEARCH_2
|
rlm@1
|
974 #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_STEP_4(sf, rs_type_size, unsigned short, noMisalign, CmpFun,itemIndex,rs_val,rs_param);
|
rlm@1
|
975 case 'n': DO_SEARCH(CompareChangesAtItem); break;
|
rlm@1
|
976 }
|
rlm@1
|
977 return false;
|
rlm@1
|
978 }
|
rlm@1
|
979
|
rlm@1
|
980
|
rlm@1
|
981
|
rlm@1
|
982 unsigned int ReadValueAtSoftwareAddress(const unsigned char* address, unsigned int size)
|
rlm@1
|
983 {
|
rlm@1
|
984 unsigned int value = 0;
|
rlm@1
|
985 if(address)
|
rlm@1
|
986 {
|
rlm@1
|
987 // assumes we're little-endian
|
rlm@1
|
988 memcpy(&value, address, size);
|
rlm@1
|
989 }
|
rlm@1
|
990 return value;
|
rlm@1
|
991 }
|
rlm@1
|
992 void WriteValueAtSoftwareAddress(unsigned char* address, unsigned int value, unsigned int size)
|
rlm@1
|
993 {
|
rlm@1
|
994 if(address)
|
rlm@1
|
995 {
|
rlm@1
|
996 // assumes we're little-endian
|
rlm@1
|
997 memcpy(address, &value, size);
|
rlm@1
|
998 }
|
rlm@1
|
999 }
|
rlm@1
|
1000 unsigned int ReadValueAtHardwareAddress(HWAddressType address, unsigned int size)
|
rlm@1
|
1001 {
|
rlm@1
|
1002 return ReadValueAtSoftwareAddress(HardwareToSoftwareAddress(address), size);
|
rlm@1
|
1003 }
|
rlm@1
|
1004 bool WriteValueAtHardwareAddress(HWAddressType address, unsigned int value, unsigned int size)
|
rlm@1
|
1005 {
|
rlm@1
|
1006 WriteValueAtSoftwareAddress(HardwareToSoftwareAddress(address), value, size);
|
rlm@1
|
1007 return true;
|
rlm@1
|
1008 }
|
rlm@1
|
1009 bool IsHardwareAddressValid(HWAddressType address)
|
rlm@1
|
1010 {
|
rlm@1
|
1011 return HardwareToSoftwareAddress(address) != NULL;
|
rlm@1
|
1012 }
|
rlm@1
|
1013
|
rlm@1
|
1014
|
rlm@1
|
1015
|
rlm@1
|
1016 int ResultCount=0;
|
rlm@1
|
1017 bool AutoSearch=false;
|
rlm@1
|
1018 bool AutoSearchAutoRetry=false;
|
rlm@1
|
1019 LRESULT CALLBACK PromptWatchNameProc(HWND, UINT, WPARAM, LPARAM);
|
rlm@1
|
1020 void UpdatePossibilities(int rs_possible, int regions);
|
rlm@1
|
1021
|
rlm@1
|
1022
|
rlm@1
|
1023 void CompactAddrs()
|
rlm@1
|
1024 {
|
rlm@1
|
1025 int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2;
|
rlm@1
|
1026 int prevResultCount = ResultCount;
|
rlm@1
|
1027
|
rlm@1
|
1028 CalculateItemIndices(size);
|
rlm@1
|
1029 ResultCount = CALL_WITH_T_SIZE_TYPES_0(CountRegionItemsT, rs_type_size,rs_t=='s',noMisalign);
|
rlm@1
|
1030
|
rlm@1
|
1031 UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size());
|
rlm@1
|
1032
|
rlm@1
|
1033 if(ResultCount != prevResultCount)
|
rlm@1
|
1034 ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount);
|
rlm@1
|
1035 }
|
rlm@1
|
1036
|
rlm@1
|
1037 void soft_reset_address_info ()
|
rlm@1
|
1038 {
|
rlm@1
|
1039 s_prevValuesNeedUpdate = false;
|
rlm@1
|
1040 ResetMemoryRegions();
|
rlm@1
|
1041 if(!RamSearchHWnd)
|
rlm@1
|
1042 {
|
rlm@1
|
1043 EnterCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
1044 s_activeMemoryRegions.clear();
|
rlm@1
|
1045 LeaveCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
1046 ResultCount = 0;
|
rlm@1
|
1047 }
|
rlm@1
|
1048 else
|
rlm@1
|
1049 {
|
rlm@1
|
1050 // force s_prevValues to be valid
|
rlm@1
|
1051 signal_new_frame();
|
rlm@1
|
1052 s_prevValuesNeedUpdate = true;
|
rlm@1
|
1053 signal_new_frame();
|
rlm@1
|
1054 }
|
rlm@1
|
1055 if(s_numChanges)
|
rlm@1
|
1056 memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE)));
|
rlm@1
|
1057 CompactAddrs();
|
rlm@1
|
1058 }
|
rlm@1
|
1059 void reset_address_info ()
|
rlm@1
|
1060 {
|
rlm@1
|
1061 SetRamSearchUndoType(RamSearchHWnd, 0);
|
rlm@1
|
1062 EnterCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
1063 s_activeMemoryRegionsBackup.clear(); // not necessary, but we'll take the time hit here instead of at the next thing that sets up an undo
|
rlm@1
|
1064 LeaveCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
1065 if(s_prevValues)
|
rlm@1
|
1066 memcpy(s_prevValues, s_curValues, (sizeof(*s_prevValues)*(MAX_RAM_SIZE)));
|
rlm@1
|
1067 s_prevValuesNeedUpdate = false;
|
rlm@1
|
1068 ResetMemoryRegions();
|
rlm@1
|
1069 if(!RamSearchHWnd)
|
rlm@1
|
1070 {
|
rlm@1
|
1071 EnterCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
1072 s_activeMemoryRegions.clear();
|
rlm@1
|
1073 LeaveCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
1074 ResultCount = 0;
|
rlm@1
|
1075 }
|
rlm@1
|
1076 else
|
rlm@1
|
1077 {
|
rlm@1
|
1078 // force s_prevValues to be valid
|
rlm@1
|
1079 signal_new_frame();
|
rlm@1
|
1080 s_prevValuesNeedUpdate = true;
|
rlm@1
|
1081 signal_new_frame();
|
rlm@1
|
1082 }
|
rlm@1
|
1083 memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE)));
|
rlm@1
|
1084 CompactAddrs();
|
rlm@1
|
1085 }
|
rlm@1
|
1086
|
rlm@1
|
1087 void signal_new_frame ()
|
rlm@1
|
1088 {
|
rlm@1
|
1089 EnterCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
1090 CALL_WITH_T_SIZE_TYPES_0(UpdateRegionsT, rs_type_size, rs_t=='s', noMisalign);
|
rlm@1
|
1091 LeaveCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
1092 }
|
rlm@1
|
1093
|
rlm@1
|
1094
|
rlm@1
|
1095
|
rlm@1
|
1096
|
rlm@1
|
1097
|
rlm@1
|
1098 bool RamSearchClosed = false;
|
rlm@1
|
1099 bool RamWatchClosed = false;
|
rlm@1
|
1100
|
rlm@1
|
1101 void ResetResults()
|
rlm@1
|
1102 {
|
rlm@1
|
1103 reset_address_info();
|
rlm@1
|
1104 ResultCount = 0;
|
rlm@1
|
1105 if (RamSearchHWnd)
|
rlm@1
|
1106 ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount);
|
rlm@1
|
1107 }
|
rlm@1
|
1108 void CloseRamWindows() //Close the Ram Search & Watch windows when rom closes
|
rlm@1
|
1109 {
|
rlm@1
|
1110 ResetWatches();
|
rlm@1
|
1111 ResetResults();
|
rlm@1
|
1112 if (RamSearchHWnd)
|
rlm@1
|
1113 {
|
rlm@1
|
1114 SendMessage(RamSearchHWnd,WM_CLOSE,NULL,NULL);
|
rlm@1
|
1115 RamSearchClosed = true;
|
rlm@1
|
1116 }
|
rlm@1
|
1117 if (RamWatchHWnd)
|
rlm@1
|
1118 {
|
rlm@1
|
1119 SendMessage(RamWatchHWnd,WM_CLOSE,NULL,NULL);
|
rlm@1
|
1120 RamWatchClosed = true;
|
rlm@1
|
1121 }
|
rlm@1
|
1122 }
|
rlm@1
|
1123 void ReopenRamWindows() //Reopen them when a new Rom is loaded
|
rlm@1
|
1124 {
|
rlm@1
|
1125 HWND hwnd = GetActiveWindow();
|
rlm@1
|
1126
|
rlm@1
|
1127 if (RamSearchClosed)
|
rlm@1
|
1128 {
|
rlm@1
|
1129 RamSearchClosed = false;
|
rlm@1
|
1130 if(!RamSearchHWnd)
|
rlm@1
|
1131 {
|
rlm@1
|
1132 reset_address_info();
|
rlm@1
|
1133 LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
rlm@1
|
1134 RamSearchHWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_RAMSEARCH), hWnd, (DLGPROC) RamSearchProc);
|
rlm@1
|
1135 }
|
rlm@1
|
1136 else
|
rlm@1
|
1137 ::SetForegroundWindow(RamSearchHWnd);
|
rlm@1
|
1138 }
|
rlm@1
|
1139 if (RamWatchClosed || AutoRWLoad)
|
rlm@1
|
1140 {
|
rlm@1
|
1141 RamWatchClosed = false;
|
rlm@1
|
1142 if(!RamWatchHWnd)
|
rlm@1
|
1143 {
|
rlm@1
|
1144 if (AutoRWLoad) OpenRWRecentFile(0);
|
rlm@1
|
1145 LRESULT CALLBACK RamWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
rlm@1
|
1146 RamWatchHWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_RAMWATCH), hWnd, (DLGPROC) RamWatchProc);
|
rlm@1
|
1147 }
|
rlm@1
|
1148 else
|
rlm@1
|
1149 ::SetForegroundWindow(RamWatchHWnd);
|
rlm@1
|
1150 }
|
rlm@1
|
1151
|
rlm@1
|
1152 if (hwnd == hWnd && hwnd != GetActiveWindow())
|
rlm@1
|
1153 SetActiveWindow(hWnd); // restore focus to the main window if it had it before
|
rlm@1
|
1154 }
|
rlm@1
|
1155
|
rlm@1
|
1156
|
rlm@1
|
1157
|
rlm@1
|
1158
|
rlm@1
|
1159
|
rlm@1
|
1160 void RefreshRamListSelectedCountControlStatus(HWND hDlg)
|
rlm@1
|
1161 {
|
rlm@1
|
1162 int selCount = ListView_GetSelectedCount(GetDlgItem(hDlg,IDC_RAMLIST));
|
rlm@1
|
1163 if(selCount != s_prevSelCount)
|
rlm@1
|
1164 {
|
rlm@1
|
1165 if(selCount < 2 || s_prevSelCount < 2)
|
rlm@1
|
1166 {
|
rlm@1
|
1167 EnableWindow(GetDlgItem(hDlg, IDC_C_WATCH), (WatchCount < MAX_WATCH_COUNT) ? TRUE : FALSE);
|
rlm@1
|
1168 EnableWindow(GetDlgItem(hDlg, IDC_C_ADDCHEAT), (selCount >= 1) ? TRUE : FALSE);
|
rlm@1
|
1169 EnableWindow(GetDlgItem(hDlg, IDC_C_ELIMINATE), (selCount >= 1) ? TRUE : FALSE);
|
rlm@1
|
1170 }
|
rlm@1
|
1171 s_prevSelCount = selCount;
|
rlm@1
|
1172 }
|
rlm@1
|
1173 }
|
rlm@1
|
1174
|
rlm@1
|
1175
|
rlm@1
|
1176
|
rlm@1
|
1177
|
rlm@1
|
1178 struct AddrRange
|
rlm@1
|
1179 {
|
rlm@1
|
1180 unsigned int addr;
|
rlm@1
|
1181 unsigned int size;
|
rlm@1
|
1182 unsigned int End() const { return addr + size; }
|
rlm@1
|
1183 AddrRange(unsigned int a, unsigned int s) : addr(a),size(s){}
|
rlm@1
|
1184 };
|
rlm@1
|
1185
|
rlm@1
|
1186 void signal_new_size ()
|
rlm@1
|
1187 {
|
rlm@1
|
1188 HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST);
|
rlm@1
|
1189
|
rlm@1
|
1190 int oldSize = (rs_last_type_size=='b' || !rs_last_no_misalign) ? 1 : 2;
|
rlm@1
|
1191 int newSize = (rs_type_size=='b' || !noMisalign) ? 1 : 2;
|
rlm@1
|
1192 bool numberOfItemsChanged = (oldSize != newSize);
|
rlm@1
|
1193
|
rlm@1
|
1194 unsigned int itemsPerPage = ListView_GetCountPerPage(lv);
|
rlm@1
|
1195 unsigned int oldTopIndex = ListView_GetTopIndex(lv);
|
rlm@1
|
1196 unsigned int oldSelectionIndex = ListView_GetSelectionMark(lv);
|
rlm@1
|
1197 unsigned int oldTopAddr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, oldTopIndex);
|
rlm@1
|
1198 unsigned int oldSelectionAddr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, oldSelectionIndex);
|
rlm@1
|
1199
|
rlm@1
|
1200 std::vector<AddrRange> selHardwareAddrs;
|
rlm@1
|
1201 if(numberOfItemsChanged)
|
rlm@1
|
1202 {
|
rlm@1
|
1203 // store selection ranges
|
rlm@1
|
1204 // unfortunately this can take a while if the user has a huge range of items selected
|
rlm@1
|
1205 systemSoundClearBuffer();
|
rlm@1
|
1206 int selCount = ListView_GetSelectedCount(lv);
|
rlm@1
|
1207 int size = (rs_last_type_size=='b' || !rs_last_no_misalign) ? 1 : 2;
|
rlm@1
|
1208 int watchIndex = -1;
|
rlm@1
|
1209 for(int i = 0; i < selCount; ++i)
|
rlm@1
|
1210 {
|
rlm@1
|
1211 watchIndex = ListView_GetNextItem(lv, watchIndex, LVNI_SELECTED);
|
rlm@1
|
1212 int addr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, watchIndex);
|
rlm@1
|
1213 if(!selHardwareAddrs.empty() && addr == selHardwareAddrs.back().End())
|
rlm@1
|
1214 selHardwareAddrs.back().size += size;
|
rlm@1
|
1215 else if (!(noMisalign && oldSize < newSize && addr % newSize != 0))
|
rlm@1
|
1216 selHardwareAddrs.push_back(AddrRange(addr,size));
|
rlm@1
|
1217 }
|
rlm@1
|
1218 }
|
rlm@1
|
1219
|
rlm@1
|
1220 CompactAddrs();
|
rlm@1
|
1221
|
rlm@1
|
1222 rs_last_type_size = rs_type_size;
|
rlm@1
|
1223 rs_last_no_misalign = noMisalign;
|
rlm@1
|
1224
|
rlm@1
|
1225 if(numberOfItemsChanged)
|
rlm@1
|
1226 {
|
rlm@1
|
1227 // restore selection ranges
|
rlm@1
|
1228 unsigned int newTopIndex = CALL_WITH_T_SIZE_TYPES_1(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, oldTopAddr);
|
rlm@1
|
1229 unsigned int newBottomIndex = newTopIndex + itemsPerPage - 1;
|
rlm@1
|
1230 SendMessage(lv, WM_SETREDRAW, FALSE, 0);
|
rlm@1
|
1231 ListView_SetItemState(lv, -1, 0, LVIS_SELECTED|LVIS_FOCUSED); // deselect all
|
rlm@1
|
1232 for(unsigned int i = 0; i < selHardwareAddrs.size(); i++)
|
rlm@1
|
1233 {
|
rlm@1
|
1234 // calculate index ranges of this selection
|
rlm@1
|
1235 const AddrRange& range = selHardwareAddrs[i];
|
rlm@1
|
1236 int selRangeTop = CALL_WITH_T_SIZE_TYPES_1(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, range.addr);
|
rlm@1
|
1237 int selRangeBottom = -1;
|
rlm@1
|
1238 for(int endAddr = range.End()-1; endAddr >= selRangeTop && selRangeBottom == -1; endAddr--)
|
rlm@1
|
1239 selRangeBottom = CALL_WITH_T_SIZE_TYPES_1(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, endAddr);
|
rlm@1
|
1240 if(selRangeBottom == -1)
|
rlm@1
|
1241 selRangeBottom = selRangeTop;
|
rlm@1
|
1242 if(selRangeTop == -1)
|
rlm@1
|
1243 continue;
|
rlm@1
|
1244
|
rlm@1
|
1245 // select the entire range
|
rlm@1
|
1246 for (int j = selRangeTop; j <= selRangeBottom; j++)
|
rlm@1
|
1247 {
|
rlm@1
|
1248 ListView_SetItemState(lv, j, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
|
rlm@1
|
1249 }
|
rlm@1
|
1250 }
|
rlm@1
|
1251
|
rlm@1
|
1252 // restore previous scroll position
|
rlm@1
|
1253 if(newBottomIndex != -1)
|
rlm@1
|
1254 ListView_EnsureVisible(lv, newBottomIndex, 0);
|
rlm@1
|
1255 if(newTopIndex != -1)
|
rlm@1
|
1256 ListView_EnsureVisible(lv, newTopIndex, 0);
|
rlm@1
|
1257
|
rlm@1
|
1258 SendMessage(lv, WM_SETREDRAW, TRUE, 0);
|
rlm@1
|
1259
|
rlm@1
|
1260 RefreshRamListSelectedCountControlStatus(RamSearchHWnd);
|
rlm@1
|
1261
|
rlm@1
|
1262 EnableWindow(GetDlgItem(RamSearchHWnd,IDC_MISALIGN), rs_type_size != 'b');
|
rlm@1
|
1263 }
|
rlm@1
|
1264 else
|
rlm@1
|
1265 {
|
rlm@1
|
1266 ListView_Update(lv, -1);
|
rlm@1
|
1267 }
|
rlm@1
|
1268 InvalidateRect(lv, NULL, TRUE);
|
rlm@1
|
1269 //SetFocus(lv);
|
rlm@1
|
1270 }
|
rlm@1
|
1271
|
rlm@1
|
1272
|
rlm@1
|
1273
|
rlm@1
|
1274
|
rlm@1
|
1275 LRESULT CustomDraw (LPARAM lParam)
|
rlm@1
|
1276 {
|
rlm@1
|
1277 LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
|
rlm@1
|
1278
|
rlm@1
|
1279 switch(lplvcd->nmcd.dwDrawStage)
|
rlm@1
|
1280 {
|
rlm@1
|
1281 case CDDS_PREPAINT :
|
rlm@1
|
1282 return CDRF_NOTIFYITEMDRAW;
|
rlm@1
|
1283
|
rlm@1
|
1284 case CDDS_ITEMPREPAINT:
|
rlm@1
|
1285 {
|
rlm@1
|
1286 int rv = CDRF_DODEFAULT;
|
rlm@1
|
1287
|
rlm@1
|
1288 if(lplvcd->nmcd.dwItemSpec % 2)
|
rlm@1
|
1289 {
|
rlm@1
|
1290 // alternate the background color slightly
|
rlm@1
|
1291 lplvcd->clrTextBk = RGB(248,248,255);
|
rlm@1
|
1292 rv = CDRF_NEWFONT;
|
rlm@1
|
1293 }
|
rlm@1
|
1294
|
rlm@1
|
1295 if(!IsSatisfied(lplvcd->nmcd.dwItemSpec))
|
rlm@1
|
1296 {
|
rlm@1
|
1297 // tint red any items that would be eliminated if a search were to run now
|
rlm@1
|
1298 lplvcd->clrText = RGB(192,64,64);
|
rlm@1
|
1299 rv = CDRF_NEWFONT;
|
rlm@1
|
1300 }
|
rlm@1
|
1301
|
rlm@1
|
1302 return rv;
|
rlm@1
|
1303 } break;
|
rlm@1
|
1304 }
|
rlm@1
|
1305 return CDRF_DODEFAULT;
|
rlm@1
|
1306 }
|
rlm@1
|
1307
|
rlm@1
|
1308 void Update_RAM_Search() //keeps RAM values up to date in the search and watch windows
|
rlm@1
|
1309 {
|
rlm@1
|
1310 if(disableRamSearchUpdate)
|
rlm@1
|
1311 return;
|
rlm@1
|
1312
|
rlm@1
|
1313 int prevValuesNeededUpdate;
|
rlm@1
|
1314 if (AutoSearch && !ResultCount)
|
rlm@1
|
1315 {
|
rlm@1
|
1316 if(!AutoSearchAutoRetry)
|
rlm@1
|
1317 {
|
rlm@1
|
1318 systemSoundClearBuffer();
|
rlm@1
|
1319 int answer = MessageBox(RamSearchHWnd,"Choosing Retry will reset the search once and continue autosearching.\nChoose Ignore will reset the search whenever necessary and continue autosearching.\nChoosing Abort will reset the search once and stop autosearching.","Autosearch - out of results.",MB_ABORTRETRYIGNORE|MB_DEFBUTTON2|MB_ICONINFORMATION);
|
rlm@1
|
1320 if(answer == IDABORT)
|
rlm@1
|
1321 {
|
rlm@1
|
1322 SendDlgItemMessage(RamSearchHWnd, IDC_C_AUTOSEARCH, BM_SETCHECK, BST_UNCHECKED, 0);
|
rlm@1
|
1323 SendMessage(RamSearchHWnd, WM_COMMAND, IDC_C_AUTOSEARCH, 0);
|
rlm@1
|
1324 }
|
rlm@1
|
1325 if(answer == IDIGNORE)
|
rlm@1
|
1326 AutoSearchAutoRetry = true;
|
rlm@1
|
1327 }
|
rlm@1
|
1328 reset_address_info();
|
rlm@1
|
1329 prevValuesNeededUpdate = s_prevValuesNeedUpdate;
|
rlm@1
|
1330 }
|
rlm@1
|
1331 else
|
rlm@1
|
1332 {
|
rlm@1
|
1333 prevValuesNeededUpdate = s_prevValuesNeedUpdate;
|
rlm@1
|
1334 if (RamSearchHWnd)
|
rlm@1
|
1335 {
|
rlm@1
|
1336 // update active RAM values
|
rlm@1
|
1337 signal_new_frame();
|
rlm@1
|
1338 }
|
rlm@1
|
1339
|
rlm@1
|
1340 if (AutoSearch && ResultCount)
|
rlm@1
|
1341 {
|
rlm@1
|
1342 systemSoundClearBuffer();
|
rlm@1
|
1343 if(!rs_val_valid)
|
rlm@1
|
1344 rs_val_valid = Set_RS_Val();
|
rlm@1
|
1345 if(rs_val_valid)
|
rlm@1
|
1346 prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param);
|
rlm@1
|
1347 }
|
rlm@1
|
1348 }
|
rlm@1
|
1349
|
rlm@1
|
1350 if(RamSearchHWnd)
|
rlm@1
|
1351 {
|
rlm@1
|
1352 HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST);
|
rlm@1
|
1353 if(prevValuesNeededUpdate != s_prevValuesNeedUpdate)
|
rlm@1
|
1354 {
|
rlm@1
|
1355 // previous values got updated, refresh everything visible
|
rlm@1
|
1356 ListView_Update(lv, -1);
|
rlm@1
|
1357 }
|
rlm@1
|
1358 else
|
rlm@1
|
1359 {
|
rlm@1
|
1360 // refresh any visible parts of the listview box that changed
|
rlm@1
|
1361 static int changes[128];
|
rlm@1
|
1362 int top = ListView_GetTopIndex(lv);
|
rlm@1
|
1363 int count = ListView_GetCountPerPage(lv);
|
rlm@1
|
1364 int start = -1;
|
rlm@1
|
1365 for(int i = top; i <= top+count; i++)
|
rlm@1
|
1366 {
|
rlm@1
|
1367 int changeNum = CALL_WITH_T_SIZE_TYPES_1(GetNumChangesFromItemIndex, rs_type_size,rs_t=='s',noMisalign, i); //s_numChanges[i];
|
rlm@1
|
1368 int changed = changeNum != changes[i-top];
|
rlm@1
|
1369 if(changed)
|
rlm@1
|
1370 changes[i-top] = changeNum;
|
rlm@1
|
1371
|
rlm@1
|
1372 if(start == -1)
|
rlm@1
|
1373 {
|
rlm@1
|
1374 if(i != top+count && changed)
|
rlm@1
|
1375 {
|
rlm@1
|
1376 start = i;
|
rlm@1
|
1377 //somethingChanged = true;
|
rlm@1
|
1378 }
|
rlm@1
|
1379 }
|
rlm@1
|
1380 else
|
rlm@1
|
1381 {
|
rlm@1
|
1382 if(i == top+count || !changed)
|
rlm@1
|
1383 {
|
rlm@1
|
1384 ListView_RedrawItems(lv, start, i-1);
|
rlm@1
|
1385 start = -1;
|
rlm@1
|
1386 }
|
rlm@1
|
1387 }
|
rlm@1
|
1388 }
|
rlm@1
|
1389 }
|
rlm@1
|
1390 }
|
rlm@1
|
1391
|
rlm@1
|
1392 if(RamWatchHWnd)
|
rlm@1
|
1393 {
|
rlm@1
|
1394 Update_RAM_Watch();
|
rlm@1
|
1395 }
|
rlm@1
|
1396 }
|
rlm@1
|
1397
|
rlm@1
|
1398 static int rs_lastPercent = -1;
|
rlm@1
|
1399 inline void UpdateRamSearchProgressBar(int percent)
|
rlm@1
|
1400 {
|
rlm@1
|
1401 if(rs_lastPercent != percent)
|
rlm@1
|
1402 {
|
rlm@1
|
1403 rs_lastPercent = percent;
|
rlm@1
|
1404 UpdateRamSearchTitleBar(percent);
|
rlm@1
|
1405 }
|
rlm@1
|
1406 }
|
rlm@1
|
1407
|
rlm@1
|
1408 static void SelectEditControl(int controlID)
|
rlm@1
|
1409 {
|
rlm@1
|
1410 HWND hEdit = GetDlgItem(RamSearchHWnd,controlID);
|
rlm@1
|
1411 SetFocus(hEdit);
|
rlm@1
|
1412 SendMessage(hEdit, EM_SETSEL, 0, -1);
|
rlm@1
|
1413 }
|
rlm@1
|
1414
|
rlm@1
|
1415 static BOOL SelectingByKeyboard()
|
rlm@1
|
1416 {
|
rlm@1
|
1417 int a = GetKeyState(VK_LEFT);
|
rlm@1
|
1418 int b = GetKeyState(VK_RIGHT);
|
rlm@1
|
1419 int c = GetKeyState(VK_UP);
|
rlm@1
|
1420 int d = GetKeyState(VK_DOWN); // space and tab are intentionally omitted
|
rlm@1
|
1421 return (a | b | c | d) & 0x80;
|
rlm@1
|
1422 }
|
rlm@1
|
1423
|
rlm@1
|
1424
|
rlm@1
|
1425 LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
rlm@1
|
1426 {
|
rlm@1
|
1427 static int watchIndex=0;
|
rlm@1
|
1428
|
rlm@1
|
1429 switch(uMsg)
|
rlm@1
|
1430 {
|
rlm@1
|
1431 case WM_INITDIALOG: {
|
rlm@1
|
1432 RamSearchHWnd = hDlg;
|
rlm@1
|
1433
|
rlm@1
|
1434 SetWindowPos(hDlg, NULL, regQueryDwordValue("ramSearchX", 0), regQueryDwordValue("ramSearchY", 0), NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
|
rlm@1
|
1435 switch(rs_o)
|
rlm@1
|
1436 {
|
rlm@1
|
1437 case '<':
|
rlm@1
|
1438 SendDlgItemMessage(hDlg, IDC_LESSTHAN, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1439 break;
|
rlm@1
|
1440 case '>':
|
rlm@1
|
1441 SendDlgItemMessage(hDlg, IDC_MORETHAN, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1442 break;
|
rlm@1
|
1443 case 'l':
|
rlm@1
|
1444 SendDlgItemMessage(hDlg, IDC_NOMORETHAN, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1445 break;
|
rlm@1
|
1446 case 'm':
|
rlm@1
|
1447 SendDlgItemMessage(hDlg, IDC_NOLESSTHAN, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1448 break;
|
rlm@1
|
1449 case '=':
|
rlm@1
|
1450 SendDlgItemMessage(hDlg, IDC_EQUALTO, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1451 break;
|
rlm@1
|
1452 case '!':
|
rlm@1
|
1453 SendDlgItemMessage(hDlg, IDC_DIFFERENTFROM, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1454 break;
|
rlm@1
|
1455 case 'd':
|
rlm@1
|
1456 SendDlgItemMessage(hDlg, IDC_DIFFERENTBY, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1457 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),true);
|
rlm@1
|
1458 break;
|
rlm@1
|
1459 case '%':
|
rlm@1
|
1460 SendDlgItemMessage(hDlg, IDC_MODULO, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1461 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),true);
|
rlm@1
|
1462 break;
|
rlm@1
|
1463 }
|
rlm@1
|
1464 switch (rs_c)
|
rlm@1
|
1465 {
|
rlm@1
|
1466 case 'r':
|
rlm@1
|
1467 SendDlgItemMessage(hDlg, IDC_PREVIOUSVALUE, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1468 break;
|
rlm@1
|
1469 case 's':
|
rlm@1
|
1470 SendDlgItemMessage(hDlg, IDC_SPECIFICVALUE, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1471 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),true);
|
rlm@1
|
1472 break;
|
rlm@1
|
1473 case 'a':
|
rlm@1
|
1474 SendDlgItemMessage(hDlg, IDC_SPECIFICADDRESS, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1475 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),true);
|
rlm@1
|
1476 break;
|
rlm@1
|
1477 case 'n':
|
rlm@1
|
1478 SendDlgItemMessage(hDlg, IDC_NUMBEROFCHANGES, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1479 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),true);
|
rlm@1
|
1480 break;
|
rlm@1
|
1481 }
|
rlm@1
|
1482 switch (rs_t)
|
rlm@1
|
1483 {
|
rlm@1
|
1484 case 's':
|
rlm@1
|
1485 SendDlgItemMessage(hDlg, IDC_SIGNED, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1486 break;
|
rlm@1
|
1487 case 'u':
|
rlm@1
|
1488 SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1489 break;
|
rlm@1
|
1490 case 'h':
|
rlm@1
|
1491 SendDlgItemMessage(hDlg, IDC_HEX, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1492 break;
|
rlm@1
|
1493 }
|
rlm@1
|
1494 switch (rs_type_size)
|
rlm@1
|
1495 {
|
rlm@1
|
1496 case 'b':
|
rlm@1
|
1497 SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1498 break;
|
rlm@1
|
1499 case 'w':
|
rlm@1
|
1500 SendDlgItemMessage(hDlg, IDC_2_BYTES, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1501 break;
|
rlm@1
|
1502 case 'd':
|
rlm@1
|
1503 SendDlgItemMessage(hDlg, IDC_4_BYTES, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1504 break;
|
rlm@1
|
1505 }
|
rlm@1
|
1506
|
rlm@1
|
1507 s_prevValuesNeedUpdate = true;
|
rlm@1
|
1508
|
rlm@1
|
1509 SendDlgItemMessage(hDlg,IDC_C_AUTOSEARCH,BM_SETCHECK,AutoSearch?BST_CHECKED:BST_UNCHECKED,0);
|
rlm@1
|
1510 //const char* names[5] = {"Address","Value","Previous","Changes","Notes"};
|
rlm@1
|
1511 //int widths[5] = {62,64,64,55,55};
|
rlm@1
|
1512 const char* names[] = {"Address","Value","Previous","Changes"};
|
rlm@1
|
1513 int widths[4] = {68,76,76,68};
|
rlm@1
|
1514 if (!ResultCount)
|
rlm@1
|
1515 reset_address_info();
|
rlm@1
|
1516 else
|
rlm@1
|
1517 {
|
rlm@1
|
1518 signal_new_frame();
|
rlm@1
|
1519 CompactAddrs();
|
rlm@1
|
1520 }
|
rlm@1
|
1521 void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths);
|
rlm@1
|
1522 init_list_box(GetDlgItem(hDlg,IDC_RAMLIST),names,4,widths);
|
rlm@1
|
1523 //ListView_SetItemCount(GetDlgItem(hDlg,IDC_RAMLIST),ResultCount);
|
rlm@1
|
1524 if (!noMisalign) SendDlgItemMessage(hDlg, IDC_MISALIGN, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1525 //if (littleEndian) SendDlgItemMessage(hDlg, IDC_ENDIAN, BM_SETCHECK, BST_CHECKED, 0);
|
rlm@1
|
1526 last_rs_possible = -1;
|
rlm@1
|
1527
|
rlm@1
|
1528 s_prevSelCount = -1;
|
rlm@1
|
1529 RefreshRamListSelectedCountControlStatus(hDlg);
|
rlm@1
|
1530
|
rlm@1
|
1531 // force misalign checkbox to refresh
|
rlm@1
|
1532 signal_new_size();
|
rlm@1
|
1533
|
rlm@1
|
1534 // force undo button to refresh
|
rlm@1
|
1535 int undoType = s_undoType;
|
rlm@1
|
1536 SetRamSearchUndoType(hDlg, -2);
|
rlm@1
|
1537 SetRamSearchUndoType(hDlg, undoType);
|
rlm@1
|
1538
|
rlm@1
|
1539 // force possibility count to refresh
|
rlm@1
|
1540 last_rs_possible--;
|
rlm@1
|
1541 UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size());
|
rlm@1
|
1542
|
rlm@1
|
1543 rs_val_valid = Set_RS_Val();
|
rlm@1
|
1544
|
rlm@1
|
1545 ListView_SetCallbackMask(GetDlgItem(hDlg,IDC_RAMLIST), LVIS_FOCUSED|LVIS_SELECTED);
|
rlm@1
|
1546
|
rlm@1
|
1547 return true;
|
rlm@1
|
1548 } break;
|
rlm@1
|
1549
|
rlm@1
|
1550 case WM_NOTIFY:
|
rlm@1
|
1551 {
|
rlm@1
|
1552 LPNMHDR lP = (LPNMHDR) lParam;
|
rlm@1
|
1553 switch (lP->code)
|
rlm@1
|
1554 {
|
rlm@1
|
1555 case LVN_ITEMCHANGED: // selection changed event
|
rlm@1
|
1556 {
|
rlm@1
|
1557 NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)lP;
|
rlm@1
|
1558 if(pNMListView->uNewState & LVIS_FOCUSED ||
|
rlm@1
|
1559 (pNMListView->uNewState ^ pNMListView->uOldState) & LVIS_SELECTED)
|
rlm@1
|
1560 {
|
rlm@1
|
1561 // disable buttons that we don't have the right number of selected items for
|
rlm@1
|
1562 RefreshRamListSelectedCountControlStatus(hDlg);
|
rlm@1
|
1563 }
|
rlm@1
|
1564 } break;
|
rlm@1
|
1565
|
rlm@1
|
1566 case LVN_GETDISPINFO:
|
rlm@1
|
1567 {
|
rlm@1
|
1568 LV_DISPINFO *Item = (LV_DISPINFO *)lParam;
|
rlm@1
|
1569 Item->item.mask = LVIF_TEXT;
|
rlm@1
|
1570 Item->item.state = 0;
|
rlm@1
|
1571 Item->item.iImage = 0;
|
rlm@1
|
1572 const unsigned int iNum = Item->item.iItem;
|
rlm@1
|
1573 static char num[11];
|
rlm@1
|
1574 switch (Item->item.iSubItem)
|
rlm@1
|
1575 {
|
rlm@1
|
1576 case 0:
|
rlm@1
|
1577 {
|
rlm@1
|
1578 int addr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum);
|
rlm@1
|
1579 sprintf(num,"%08X",addr);
|
rlm@1
|
1580 Item->item.pszText = num;
|
rlm@1
|
1581 } return true;
|
rlm@1
|
1582 case 1:
|
rlm@1
|
1583 {
|
rlm@1
|
1584 int i = CALL_WITH_T_SIZE_TYPES_1(GetCurValueFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum);
|
rlm@1
|
1585 const char* formatString = ((rs_t=='s') ? "%d" : (rs_t=='u') ? "%u" : (rs_type_size=='d' ? "%08X" : rs_type_size=='w' ? "%04X" : "%02X"));
|
rlm@1
|
1586 switch (rs_type_size)
|
rlm@1
|
1587 {
|
rlm@1
|
1588 case 'b':
|
rlm@1
|
1589 default: sprintf(num, formatString, rs_t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break;
|
rlm@1
|
1590 case 'w': sprintf(num, formatString, rs_t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break;
|
rlm@1
|
1591 case 'd': sprintf(num, formatString, rs_t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break;
|
rlm@1
|
1592 }
|
rlm@1
|
1593 Item->item.pszText = num;
|
rlm@1
|
1594 } return true;
|
rlm@1
|
1595 case 2:
|
rlm@1
|
1596 {
|
rlm@1
|
1597 int i = CALL_WITH_T_SIZE_TYPES_1(GetPrevValueFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum);
|
rlm@1
|
1598 const char* formatString = ((rs_t=='s') ? "%d" : (rs_t=='u') ? "%u" : (rs_type_size=='d' ? "%08X" : rs_type_size=='w' ? "%04X" : "%02X"));
|
rlm@1
|
1599 switch (rs_type_size)
|
rlm@1
|
1600 {
|
rlm@1
|
1601 case 'b':
|
rlm@1
|
1602 default: sprintf(num, formatString, rs_t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break;
|
rlm@1
|
1603 case 'w': sprintf(num, formatString, rs_t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break;
|
rlm@1
|
1604 case 'd': sprintf(num, formatString, rs_t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break;
|
rlm@1
|
1605 }
|
rlm@1
|
1606 Item->item.pszText = num;
|
rlm@1
|
1607 } return true;
|
rlm@1
|
1608 case 3:
|
rlm@1
|
1609 {
|
rlm@1
|
1610 int i = CALL_WITH_T_SIZE_TYPES_1(GetNumChangesFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum);
|
rlm@1
|
1611 sprintf(num,"%d",i);
|
rlm@1
|
1612
|
rlm@1
|
1613 Item->item.pszText = num;
|
rlm@1
|
1614 } return true;
|
rlm@1
|
1615 //case 4:
|
rlm@1
|
1616 // Item->item.pszText = rsaddrs[rsresults[iNum].Index].comment ? rsaddrs[rsresults[iNum].Index].comment : "";
|
rlm@1
|
1617 // return true;
|
rlm@1
|
1618 default:
|
rlm@1
|
1619 return false;
|
rlm@1
|
1620 }
|
rlm@1
|
1621 }
|
rlm@1
|
1622
|
rlm@1
|
1623 case NM_CUSTOMDRAW:
|
rlm@1
|
1624 {
|
rlm@1
|
1625 SetWindowLong(hDlg, DWL_MSGRESULT, CustomDraw(lParam));
|
rlm@1
|
1626 return TRUE;
|
rlm@1
|
1627 } break;
|
rlm@1
|
1628
|
rlm@1
|
1629 //case LVN_ODCACHEHINT: //Copied this bit from the MSDN virtual listbox code sample. Eventually it should probably do something.
|
rlm@1
|
1630 //{
|
rlm@1
|
1631 // LPNMLVCACHEHINT lpCacheHint = (LPNMLVCACHEHINT)lParam;
|
rlm@1
|
1632 // return 0;
|
rlm@1
|
1633 //}
|
rlm@1
|
1634 //case LVN_ODFINDITEM: //Copied this bit from the MSDN virtual listbox code sample. Eventually it should probably do something.
|
rlm@1
|
1635 //{
|
rlm@1
|
1636 // LPNMLVFINDITEM lpFindItem = (LPNMLVFINDITEM)lParam;
|
rlm@1
|
1637 // return 0;
|
rlm@1
|
1638 //}
|
rlm@1
|
1639 }
|
rlm@1
|
1640 } break;
|
rlm@1
|
1641
|
rlm@1
|
1642 case WM_COMMAND:
|
rlm@1
|
1643 {
|
rlm@1
|
1644 int rv = false;
|
rlm@1
|
1645 switch(LOWORD(wParam))
|
rlm@1
|
1646 {
|
rlm@1
|
1647 case IDC_SIGNED:
|
rlm@1
|
1648 rs_t='s';
|
rlm@1
|
1649 signal_new_size();
|
rlm@1
|
1650 {rv = true; break;}
|
rlm@1
|
1651 case IDC_UNSIGNED:
|
rlm@1
|
1652 rs_t='u';
|
rlm@1
|
1653 signal_new_size();
|
rlm@1
|
1654 {rv = true; break;}
|
rlm@1
|
1655 case IDC_HEX:
|
rlm@1
|
1656 rs_t='h';
|
rlm@1
|
1657 signal_new_size();
|
rlm@1
|
1658 {rv = true; break;}
|
rlm@1
|
1659 case IDC_1_BYTE:
|
rlm@1
|
1660 rs_type_size = 'b';
|
rlm@1
|
1661 signal_new_size();
|
rlm@1
|
1662 {rv = true; break;}
|
rlm@1
|
1663 case IDC_2_BYTES:
|
rlm@1
|
1664 rs_type_size = 'w';
|
rlm@1
|
1665 signal_new_size();
|
rlm@1
|
1666 {rv = true; break;}
|
rlm@1
|
1667 case IDC_4_BYTES:
|
rlm@1
|
1668 rs_type_size = 'd';
|
rlm@1
|
1669 signal_new_size();
|
rlm@1
|
1670 {rv = true; break;}
|
rlm@1
|
1671 case IDC_MISALIGN:
|
rlm@1
|
1672 noMisalign = !noMisalign;
|
rlm@1
|
1673 //CompactAddrs();
|
rlm@1
|
1674 signal_new_size();
|
rlm@1
|
1675 {rv = true; break;}
|
rlm@1
|
1676 // case IDC_ENDIAN:
|
rlm@1
|
1677 //// littleEndian = !littleEndian;
|
rlm@1
|
1678 //// signal_new_size();
|
rlm@1
|
1679 // {rv = true; break;}
|
rlm@1
|
1680 case IDC_LESSTHAN:
|
rlm@1
|
1681 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
|
rlm@1
|
1682 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
|
rlm@1
|
1683 rs_o = '<';
|
rlm@1
|
1684 {rv = true; break;}
|
rlm@1
|
1685 case IDC_MORETHAN:
|
rlm@1
|
1686 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
|
rlm@1
|
1687 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
|
rlm@1
|
1688 rs_o = '>';
|
rlm@1
|
1689 {rv = true; break;}
|
rlm@1
|
1690 case IDC_NOMORETHAN:
|
rlm@1
|
1691 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
|
rlm@1
|
1692 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
|
rlm@1
|
1693 rs_o = 'l';
|
rlm@1
|
1694 {rv = true; break;}
|
rlm@1
|
1695 case IDC_NOLESSTHAN:
|
rlm@1
|
1696 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
|
rlm@1
|
1697 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
|
rlm@1
|
1698 rs_o = 'm';
|
rlm@1
|
1699 {rv = true; break;}
|
rlm@1
|
1700 case IDC_EQUALTO:
|
rlm@1
|
1701 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
|
rlm@1
|
1702 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
|
rlm@1
|
1703 rs_o = '=';
|
rlm@1
|
1704 {rv = true; break;}
|
rlm@1
|
1705 case IDC_DIFFERENTFROM:
|
rlm@1
|
1706 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
|
rlm@1
|
1707 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
|
rlm@1
|
1708 rs_o = '!';
|
rlm@1
|
1709 {rv = true; break;}
|
rlm@1
|
1710 case IDC_DIFFERENTBY:
|
rlm@1
|
1711 {
|
rlm@1
|
1712 rs_o = 'd';
|
rlm@1
|
1713 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),true);
|
rlm@1
|
1714 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
|
rlm@1
|
1715 if(!SelectingByKeyboard())
|
rlm@1
|
1716 SelectEditControl(IDC_EDIT_DIFFBY);
|
rlm@1
|
1717 } {rv = true; break;}
|
rlm@1
|
1718 case IDC_MODULO:
|
rlm@1
|
1719 {
|
rlm@1
|
1720 rs_o = '%';
|
rlm@1
|
1721 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
|
rlm@1
|
1722 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),true);
|
rlm@1
|
1723 if(!SelectingByKeyboard())
|
rlm@1
|
1724 SelectEditControl(IDC_EDIT_MODBY);
|
rlm@1
|
1725 } {rv = true; break;}
|
rlm@1
|
1726 case IDC_PREVIOUSVALUE:
|
rlm@1
|
1727 rs_c='r';
|
rlm@1
|
1728 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false);
|
rlm@1
|
1729 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false);
|
rlm@1
|
1730 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false);
|
rlm@1
|
1731 {rv = true; break;}
|
rlm@1
|
1732 case IDC_SPECIFICVALUE:
|
rlm@1
|
1733 {
|
rlm@1
|
1734 rs_c = 's';
|
rlm@1
|
1735 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),true);
|
rlm@1
|
1736 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false);
|
rlm@1
|
1737 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false);
|
rlm@1
|
1738 if(!SelectingByKeyboard())
|
rlm@1
|
1739 SelectEditControl(IDC_EDIT_COMPAREVALUE);
|
rlm@1
|
1740 {rv = true; break;}
|
rlm@1
|
1741 }
|
rlm@1
|
1742 case IDC_SPECIFICADDRESS:
|
rlm@1
|
1743 {
|
rlm@1
|
1744 rs_c = 'a';
|
rlm@1
|
1745 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),true);
|
rlm@1
|
1746 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false);
|
rlm@1
|
1747 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false);
|
rlm@1
|
1748 if(!SelectingByKeyboard())
|
rlm@1
|
1749 SelectEditControl(IDC_EDIT_COMPAREADDRESS);
|
rlm@1
|
1750 } {rv = true; break;}
|
rlm@1
|
1751 case IDC_NUMBEROFCHANGES:
|
rlm@1
|
1752 {
|
rlm@1
|
1753 rs_c = 'n';
|
rlm@1
|
1754 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),true);
|
rlm@1
|
1755 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false);
|
rlm@1
|
1756 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false);
|
rlm@1
|
1757 if(!SelectingByKeyboard())
|
rlm@1
|
1758 SelectEditControl(IDC_EDIT_COMPARECHANGES);
|
rlm@1
|
1759 } {rv = true; break;}
|
rlm@1
|
1760 case IDC_C_ADDCHEAT:
|
rlm@1
|
1761 {
|
rlm@1
|
1762 HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST);
|
rlm@1
|
1763 int watchItemIndex = ListView_GetNextItem(ramListControl, -1, LVNI_SELECTED);
|
rlm@1
|
1764 while (watchItemIndex >= 0)
|
rlm@1
|
1765 {
|
rlm@1
|
1766 unsigned long address = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchItemIndex);
|
rlm@1
|
1767
|
rlm@1
|
1768 int sizeType = -1;
|
rlm@1
|
1769 if(rs_type_size == 'b')
|
rlm@1
|
1770 sizeType = 0;
|
rlm@1
|
1771 else if(rs_type_size == 'w')
|
rlm@1
|
1772 sizeType = 1;
|
rlm@1
|
1773 else if(rs_type_size == 'd')
|
rlm@1
|
1774 sizeType = 2;
|
rlm@1
|
1775
|
rlm@1
|
1776 int numberType = -1;
|
rlm@1
|
1777 if(rs_t == 's')
|
rlm@1
|
1778 numberType = 0;
|
rlm@1
|
1779 else if(rs_t == 'u')
|
rlm@1
|
1780 numberType = 1;
|
rlm@1
|
1781 else if(rs_t == 'h')
|
rlm@1
|
1782 numberType = 2;
|
rlm@1
|
1783
|
rlm@1
|
1784 if(systemCartridgeType == 0)
|
rlm@1
|
1785 {
|
rlm@1
|
1786 AddCheat dlg (address/*, hDlg*/);
|
rlm@1
|
1787 if(sizeType != -1) dlg.sizeType = sizeType;
|
rlm@1
|
1788 if(numberType != -1) dlg.numberType = numberType;
|
rlm@1
|
1789 dlg.DoModal();
|
rlm@1
|
1790 }
|
rlm@1
|
1791 else
|
rlm@1
|
1792 {
|
rlm@1
|
1793 AddGBCheat dlg (address/*, hDlg*/);
|
rlm@1
|
1794 if(sizeType != -1) dlg.sizeType = sizeType;
|
rlm@1
|
1795 if(numberType != -1) dlg.numberType = numberType;
|
rlm@1
|
1796 dlg.DoModal();
|
rlm@1
|
1797 }
|
rlm@1
|
1798 watchItemIndex = ListView_GetNextItem(ramListControl, watchItemIndex, LVNI_SELECTED);
|
rlm@1
|
1799 }
|
rlm@1
|
1800 } {rv = true; break;}
|
rlm@1
|
1801 case IDC_C_RESET:
|
rlm@1
|
1802 {
|
rlm@1
|
1803 RamSearchSaveUndoStateIfNotTooBig(RamSearchHWnd);
|
rlm@1
|
1804 int prevNumItems = last_rs_possible;
|
rlm@1
|
1805
|
rlm@1
|
1806 soft_reset_address_info();
|
rlm@1
|
1807
|
rlm@1
|
1808 if(prevNumItems == last_rs_possible)
|
rlm@1
|
1809 SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo
|
rlm@1
|
1810
|
rlm@1
|
1811 ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all
|
rlm@1
|
1812 //ListView_SetItemCount(GetDlgItem(hDlg,IDC_RAMLIST),ResultCount);
|
rlm@1
|
1813 ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST), 0);
|
rlm@1
|
1814 RefreshRamListSelectedCountControlStatus(hDlg);
|
rlm@1
|
1815 {rv = true; break;}
|
rlm@1
|
1816 }
|
rlm@1
|
1817 case IDC_C_RESET_CHANGES:
|
rlm@1
|
1818 memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE)));
|
rlm@1
|
1819 ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1);
|
rlm@1
|
1820 //SetRamSearchUndoType(hDlg, 0);
|
rlm@1
|
1821 {rv = true; break;}
|
rlm@1
|
1822 case IDC_C_UNDO:
|
rlm@1
|
1823 if(s_undoType>0)
|
rlm@1
|
1824 {
|
rlm@1
|
1825 systemSoundClearBuffer();
|
rlm@1
|
1826 EnterCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
1827 if(s_activeMemoryRegions.size() < tooManyRegionsForUndo)
|
rlm@1
|
1828 {
|
rlm@1
|
1829 MemoryList tempMemoryList = s_activeMemoryRegions;
|
rlm@1
|
1830 s_activeMemoryRegions = s_activeMemoryRegionsBackup;
|
rlm@1
|
1831 s_activeMemoryRegionsBackup = tempMemoryList;
|
rlm@1
|
1832 LeaveCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
1833 SetRamSearchUndoType(hDlg, 3 - s_undoType);
|
rlm@1
|
1834 }
|
rlm@1
|
1835 else
|
rlm@1
|
1836 {
|
rlm@1
|
1837 s_activeMemoryRegions = s_activeMemoryRegionsBackup;
|
rlm@1
|
1838 LeaveCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
1839 SetRamSearchUndoType(hDlg, -1);
|
rlm@1
|
1840 }
|
rlm@1
|
1841 CompactAddrs();
|
rlm@1
|
1842 ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all
|
rlm@1
|
1843 ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST), 0);
|
rlm@1
|
1844 RefreshRamListSelectedCountControlStatus(hDlg);
|
rlm@1
|
1845 }
|
rlm@1
|
1846 {rv = true; break;}
|
rlm@1
|
1847 case IDC_C_AUTOSEARCH:
|
rlm@1
|
1848 AutoSearch = SendDlgItemMessage(hDlg, IDC_C_AUTOSEARCH, BM_GETCHECK, 0, 0) != 0;
|
rlm@1
|
1849 AutoSearchAutoRetry = false;
|
rlm@1
|
1850 if (!AutoSearch) {rv = true; break;}
|
rlm@1
|
1851 case IDC_C_SEARCH:
|
rlm@1
|
1852 {
|
rlm@1
|
1853 systemSoundClearBuffer();
|
rlm@1
|
1854
|
rlm@1
|
1855 if(!rs_val_valid && !(rs_val_valid = Set_RS_Val()))
|
rlm@1
|
1856 goto invalid_field;
|
rlm@1
|
1857
|
rlm@1
|
1858 if(ResultCount)
|
rlm@1
|
1859 {
|
rlm@1
|
1860 RamSearchSaveUndoStateIfNotTooBig(hDlg);
|
rlm@1
|
1861
|
rlm@1
|
1862 prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param);
|
rlm@1
|
1863
|
rlm@1
|
1864 RefreshRamListSelectedCountControlStatus(hDlg);
|
rlm@1
|
1865 }
|
rlm@1
|
1866
|
rlm@1
|
1867 if(!ResultCount)
|
rlm@1
|
1868 {
|
rlm@1
|
1869
|
rlm@1
|
1870 MessageBox(RamSearchHWnd,"Resetting search.","Out of results.",MB_OK|MB_ICONINFORMATION);
|
rlm@1
|
1871 soft_reset_address_info();
|
rlm@1
|
1872 }
|
rlm@1
|
1873
|
rlm@1
|
1874 {rv = true; break;}
|
rlm@1
|
1875
|
rlm@1
|
1876 invalid_field:
|
rlm@1
|
1877 MessageBox(RamSearchHWnd,"Invalid or out-of-bound entered value.","Error",MB_OK|MB_ICONSTOP);
|
rlm@1
|
1878 if(AutoSearch) // stop autosearch if it just started
|
rlm@1
|
1879 {
|
rlm@1
|
1880 SendDlgItemMessage(hDlg, IDC_C_AUTOSEARCH, BM_SETCHECK, BST_UNCHECKED, 0);
|
rlm@1
|
1881 SendMessage(hDlg, WM_COMMAND, IDC_C_AUTOSEARCH, 0);
|
rlm@1
|
1882 }
|
rlm@1
|
1883 {rv = true; break;}
|
rlm@1
|
1884 }
|
rlm@1
|
1885 case IDC_C_WATCH:
|
rlm@1
|
1886 {
|
rlm@1
|
1887 HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST);
|
rlm@1
|
1888 int selCount = ListView_GetSelectedCount(ramListControl);
|
rlm@1
|
1889
|
rlm@1
|
1890 bool inserted = false;
|
rlm@1
|
1891 int watchItemIndex = ListView_GetNextItem(ramListControl, -1, LVNI_SELECTED);
|
rlm@1
|
1892 while (watchItemIndex >= 0)
|
rlm@1
|
1893 {
|
rlm@1
|
1894 AddressWatcher tempWatch;
|
rlm@1
|
1895 tempWatch.Address = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchItemIndex);
|
rlm@1
|
1896 tempWatch.Size = rs_type_size;
|
rlm@1
|
1897 tempWatch.Type = rs_t;
|
rlm@1
|
1898 tempWatch.WrongEndian = 0; //Replace when I get little endian working
|
rlm@1
|
1899 tempWatch.comment = NULL;
|
rlm@1
|
1900
|
rlm@1
|
1901 if (selCount == 1)
|
rlm@1
|
1902 inserted |= InsertWatch(tempWatch, hDlg);
|
rlm@1
|
1903 else
|
rlm@1
|
1904 inserted |= InsertWatch(tempWatch, "");
|
rlm@1
|
1905
|
rlm@1
|
1906 watchItemIndex = ListView_GetNextItem(ramListControl, watchItemIndex, LVNI_SELECTED);
|
rlm@1
|
1907 }
|
rlm@1
|
1908 // bring up the ram watch window if it's not already showing so the user knows where the watch went
|
rlm@1
|
1909 if(inserted && !RamWatchHWnd)
|
rlm@1
|
1910 SendMessage(hWnd, WM_COMMAND, ID_RAM_WATCH, 0);
|
rlm@1
|
1911 SetForegroundWindow(RamSearchHWnd);
|
rlm@1
|
1912 {rv = true; break;}
|
rlm@1
|
1913 }
|
rlm@1
|
1914
|
rlm@1
|
1915 // eliminate all selected items
|
rlm@1
|
1916 case IDC_C_ELIMINATE:
|
rlm@1
|
1917 {
|
rlm@1
|
1918 RamSearchSaveUndoStateIfNotTooBig(hDlg);
|
rlm@1
|
1919
|
rlm@1
|
1920 HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST);
|
rlm@1
|
1921 int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2;
|
rlm@1
|
1922 int selCount = ListView_GetSelectedCount(ramListControl);
|
rlm@1
|
1923 int watchIndex = -1;
|
rlm@1
|
1924
|
rlm@1
|
1925 // time-saving trick #1:
|
rlm@1
|
1926 // condense the selected items into an array of address ranges
|
rlm@1
|
1927 std::vector<AddrRange> selHardwareAddrs;
|
rlm@1
|
1928 for(int i = 0, j = 1024; i < selCount; ++i, --j)
|
rlm@1
|
1929 {
|
rlm@1
|
1930 watchIndex = ListView_GetNextItem(ramListControl, watchIndex, LVNI_SELECTED);
|
rlm@1
|
1931 int addr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchIndex);
|
rlm@1
|
1932 if(!selHardwareAddrs.empty() && addr == selHardwareAddrs.back().End())
|
rlm@1
|
1933 selHardwareAddrs.back().size += size;
|
rlm@1
|
1934 else
|
rlm@1
|
1935 selHardwareAddrs.push_back(AddrRange(addr,size));
|
rlm@1
|
1936
|
rlm@1
|
1937 if(!j) UpdateRamSearchProgressBar(i * 50 / selCount), j = 1024;
|
rlm@1
|
1938 }
|
rlm@1
|
1939
|
rlm@1
|
1940 // now deactivate the ranges
|
rlm@1
|
1941
|
rlm@1
|
1942 // time-saving trick #2:
|
rlm@1
|
1943 // take advantage of the fact that the listbox items must be in the same order as the regions
|
rlm@1
|
1944 MemoryList::iterator iter = s_activeMemoryRegions.begin();
|
rlm@1
|
1945 int numHardwareAddrRanges = selHardwareAddrs.size();
|
rlm@1
|
1946 for(int i = 0, j = 16; i < numHardwareAddrRanges; ++i, --j)
|
rlm@1
|
1947 {
|
rlm@1
|
1948 int addr = selHardwareAddrs[i].addr;
|
rlm@1
|
1949 int size = selHardwareAddrs[i].size;
|
rlm@1
|
1950 bool affected = false;
|
rlm@1
|
1951 while(iter != s_activeMemoryRegions.end())
|
rlm@1
|
1952 {
|
rlm@1
|
1953 MemoryRegion& region = *iter;
|
rlm@1
|
1954 int affNow = DeactivateRegion(region, iter, addr, size);
|
rlm@1
|
1955 if(affNow)
|
rlm@1
|
1956 affected = true;
|
rlm@1
|
1957 else if(affected)
|
rlm@1
|
1958 break;
|
rlm@1
|
1959 if(affNow != 2)
|
rlm@1
|
1960 ++iter;
|
rlm@1
|
1961 }
|
rlm@1
|
1962
|
rlm@1
|
1963 if(!j) UpdateRamSearchProgressBar(50 + (i * 50 / selCount)), j = 16;
|
rlm@1
|
1964 }
|
rlm@1
|
1965 UpdateRamSearchTitleBar();
|
rlm@1
|
1966
|
rlm@1
|
1967 // careful -- if the above two time-saving tricks aren't working,
|
rlm@1
|
1968 // the runtime can absolutely explode (seconds -> hours) when there are lots of regions
|
rlm@1
|
1969
|
rlm@1
|
1970 ListView_SetItemState(ramListControl, -1, 0, LVIS_SELECTED); // deselect all
|
rlm@1
|
1971 signal_new_size();
|
rlm@1
|
1972 {rv = true; break;}
|
rlm@1
|
1973 }
|
rlm@1
|
1974 //case IDOK:
|
rlm@1
|
1975 case IDCANCEL:
|
rlm@1
|
1976 RamSearchHWnd = NULL;
|
rlm@1
|
1977 /* if (theApp.pauseDuringCheatSearch)
|
rlm@1
|
1978 EndDialog(hDlg, true); // this should never be called on a modeless dialog
|
rlm@1
|
1979 else
|
rlm@1
|
1980 */
|
rlm@1
|
1981 DestroyWindow(hDlg);
|
rlm@1
|
1982 {rv = true; break;}
|
rlm@1
|
1983 }
|
rlm@1
|
1984
|
rlm@1
|
1985 // check refresh for comparison preview color update
|
rlm@1
|
1986 // also, update rs_val if needed
|
rlm@1
|
1987 bool needRefresh = false;
|
rlm@1
|
1988 switch(LOWORD(wParam))
|
rlm@1
|
1989 {
|
rlm@1
|
1990 case IDC_LESSTHAN:
|
rlm@1
|
1991 case IDC_MORETHAN:
|
rlm@1
|
1992 case IDC_NOMORETHAN:
|
rlm@1
|
1993 case IDC_NOLESSTHAN:
|
rlm@1
|
1994 case IDC_EQUALTO:
|
rlm@1
|
1995 case IDC_DIFFERENTFROM:
|
rlm@1
|
1996 case IDC_DIFFERENTBY:
|
rlm@1
|
1997 case IDC_MODULO:
|
rlm@1
|
1998 case IDC_PREVIOUSVALUE:
|
rlm@1
|
1999 case IDC_SPECIFICVALUE:
|
rlm@1
|
2000 case IDC_SPECIFICADDRESS:
|
rlm@1
|
2001 case IDC_NUMBEROFCHANGES:
|
rlm@1
|
2002 case IDC_SIGNED:
|
rlm@1
|
2003 case IDC_UNSIGNED:
|
rlm@1
|
2004 case IDC_HEX:
|
rlm@1
|
2005 rs_val_valid = Set_RS_Val();
|
rlm@1
|
2006 needRefresh = true;
|
rlm@1
|
2007 break;
|
rlm@1
|
2008 case IDC_EDIT_COMPAREVALUE:
|
rlm@1
|
2009 case IDC_EDIT_COMPAREADDRESS:
|
rlm@1
|
2010 case IDC_EDIT_COMPARECHANGES:
|
rlm@1
|
2011 case IDC_EDIT_DIFFBY:
|
rlm@1
|
2012 case IDC_EDIT_MODBY:
|
rlm@1
|
2013 if(HIWORD(wParam) == EN_CHANGE)
|
rlm@1
|
2014 {
|
rlm@1
|
2015 rs_val_valid = Set_RS_Val();
|
rlm@1
|
2016 needRefresh = true;
|
rlm@1
|
2017 }
|
rlm@1
|
2018 break;
|
rlm@1
|
2019 }
|
rlm@1
|
2020 if(needRefresh)
|
rlm@1
|
2021 ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1);
|
rlm@1
|
2022
|
rlm@1
|
2023
|
rlm@1
|
2024 return rv;
|
rlm@1
|
2025 } break;
|
rlm@1
|
2026
|
rlm@1
|
2027 case WM_CLOSE:
|
rlm@1
|
2028 RECT r;
|
rlm@1
|
2029 GetWindowRect(hDlg, &r);
|
rlm@1
|
2030 regSetDwordValue("ramSearchX", r.left);
|
rlm@1
|
2031 regSetDwordValue("ramSearchY", r.top);
|
rlm@1
|
2032 SendMessage(RamSearchHWnd, WM_DESTROY, 0, 0);
|
rlm@1
|
2033 break;
|
rlm@1
|
2034 case WM_DESTROY:
|
rlm@1
|
2035 RamSearchHWnd = NULL;
|
rlm@1
|
2036 // theApp.modelessCheatDialogIsOpen = false;
|
rlm@1
|
2037 // return true;
|
rlm@1
|
2038 break;
|
rlm@1
|
2039 }
|
rlm@1
|
2040
|
rlm@1
|
2041 return false;
|
rlm@1
|
2042 }
|
rlm@1
|
2043
|
rlm@1
|
2044 void UpdateRamSearchTitleBar(int percent)
|
rlm@1
|
2045 {
|
rlm@1
|
2046 #define HEADER_STR " RAM Search - "
|
rlm@1
|
2047 #define PROGRESS_STR " %d%% ... "
|
rlm@1
|
2048 #define STATUS_STR "%d Possibilit%s (%d Region%s)"
|
rlm@1
|
2049
|
rlm@1
|
2050 int poss = last_rs_possible;
|
rlm@1
|
2051 int regions = last_rs_regions;
|
rlm@1
|
2052 if(poss <= 0)
|
rlm@1
|
2053 strcpy(Str_Tmp," RAM Search");
|
rlm@1
|
2054 else if(percent <= 0)
|
rlm@1
|
2055 sprintf(Str_Tmp, HEADER_STR STATUS_STR, poss, poss==1?"y":"ies", regions, regions==1?"":"s");
|
rlm@1
|
2056 else
|
rlm@1
|
2057 sprintf(Str_Tmp, PROGRESS_STR STATUS_STR, percent, poss, poss==1?"y":"ies", regions, regions==1?"":"s");
|
rlm@1
|
2058 SetWindowText(RamSearchHWnd, Str_Tmp);
|
rlm@1
|
2059 }
|
rlm@1
|
2060
|
rlm@1
|
2061 void UpdatePossibilities(int rs_possible, int regions)
|
rlm@1
|
2062 {
|
rlm@1
|
2063 if(rs_possible != last_rs_possible)
|
rlm@1
|
2064 {
|
rlm@1
|
2065 last_rs_possible = rs_possible;
|
rlm@1
|
2066 last_rs_regions = regions;
|
rlm@1
|
2067 UpdateRamSearchTitleBar();
|
rlm@1
|
2068 }
|
rlm@1
|
2069 }
|
rlm@1
|
2070
|
rlm@1
|
2071 void SetRamSearchUndoType(HWND hDlg, int type)
|
rlm@1
|
2072 {
|
rlm@1
|
2073 if(s_undoType != type)
|
rlm@1
|
2074 {
|
rlm@1
|
2075 if((s_undoType!=2 && s_undoType!=-1)!=(type!=2 && type!=-1))
|
rlm@1
|
2076 SendDlgItemMessage(hDlg,IDC_C_UNDO,WM_SETTEXT,0,(LPARAM)((type == 2 || type == -1) ? "Redo" : "Undo"));
|
rlm@1
|
2077 if((s_undoType>0)!=(type>0))
|
rlm@1
|
2078 EnableWindow(GetDlgItem(hDlg,IDC_C_UNDO),type>0);
|
rlm@1
|
2079 s_undoType = type;
|
rlm@1
|
2080 }
|
rlm@1
|
2081 }
|
rlm@1
|
2082
|
rlm@1
|
2083 void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg)
|
rlm@1
|
2084 {
|
rlm@1
|
2085 EnterCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
2086 if(s_activeMemoryRegions.size() < tooManyRegionsForUndo)
|
rlm@1
|
2087 {
|
rlm@1
|
2088 s_activeMemoryRegionsBackup = s_activeMemoryRegions;
|
rlm@1
|
2089 LeaveCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
2090 SetRamSearchUndoType(hDlg, 1);
|
rlm@1
|
2091 }
|
rlm@1
|
2092 else
|
rlm@1
|
2093 {
|
rlm@1
|
2094 LeaveCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
2095 SetRamSearchUndoType(hDlg, 0);
|
rlm@1
|
2096 }
|
rlm@1
|
2097 }
|
rlm@1
|
2098
|
rlm@1
|
2099 struct InitRamSearch
|
rlm@1
|
2100 {
|
rlm@1
|
2101 InitRamSearch()
|
rlm@1
|
2102 {
|
rlm@1
|
2103 InitializeCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
2104 }
|
rlm@1
|
2105 ~InitRamSearch()
|
rlm@1
|
2106 {
|
rlm@1
|
2107 DeleteCriticalSection(&s_activeMemoryRegionsCS);
|
rlm@1
|
2108 }
|
rlm@1
|
2109 } initRamSearch;
|
rlm@1
|
2110
|
rlm@1
|
2111
|
rlm@1
|
2112 void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths) //initializes the ram search and/or ram watch listbox
|
rlm@1
|
2113 {
|
rlm@1
|
2114 LVCOLUMN Col;
|
rlm@1
|
2115 Col.mask = LVCF_FMT | LVCF_ORDER | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
|
rlm@1
|
2116 Col.fmt = LVCFMT_CENTER;
|
rlm@1
|
2117 for (int i = 0; i < numColumns; i++)
|
rlm@1
|
2118 {
|
rlm@1
|
2119 Col.iOrder = i;
|
rlm@1
|
2120 Col.iSubItem = i;
|
rlm@1
|
2121 Col.pszText = (LPSTR)(Strs[i]);
|
rlm@1
|
2122 Col.cx = columnWidths[i];
|
rlm@1
|
2123 ListView_InsertColumn(Box,i,&Col);
|
rlm@1
|
2124 }
|
rlm@1
|
2125
|
rlm@1
|
2126 ListView_SetExtendedListViewStyle(Box, LVS_EX_FULLROWSELECT);
|
rlm@1
|
2127 }
|