view src/win32/ram_search.cpp @ 1:f9f4f1b99eed

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