1//============================================================================
2//
3// MM MM 6666 555555 0000 2222
4// MMMM MMMM 66 66 55 00 00 22 22
5// MM MMM MM 66 55 00 00 22
6// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
7// MM MM 66 66 55 00 00 22
8// MM MM 66 66 55 55 00 00 22
9// MM MM 6666 5555 0000 222222
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#ifdef DEBUGGER_SUPPORT
19 #include "Debugger.hxx"
20 #include "Expression.hxx"
21 #include "CartDebug.hxx"
22 #include "Base.hxx"
23
24 // Flags for disassembly types
25 #define DISASM_CODE CartDebug::CODE
26// #define DISASM_GFX CartDebug::GFX
27// #define DISASM_PGFX CartDebug::PGFX
28 #define DISASM_DATA CartDebug::DATA
29// #define DISASM_ROW CartDebug::ROW
30 #define DISASM_WRITE CartDebug::WRITE
31 #define DISASM_NONE 0
32#else
33 // Flags for disassembly types
34 #define DISASM_CODE 0
35// #define DISASM_GFX 0
36// #define DISASM_PGFX 0
37 #define DISASM_DATA 0
38// #define DISASM_ROW 0
39 #define DISASM_NONE 0
40 #define DISASM_WRITE 0
41#endif
42#include "Settings.hxx"
43#include "Vec.hxx"
44
45#include "Cart.hxx"
46#include "TIA.hxx"
47#include "M6532.hxx"
48#include "System.hxx"
49#include "M6502.hxx"
50#include "DispatchResult.hxx"
51#include "exception/EmulationWarning.hxx"
52#include "exception/FatalEmulationError.hxx"
53
54// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
55M6502::M6502(const Settings& settings)
56 : myExecutionStatus(0),
57 mySystem(nullptr),
58 mySettings(settings),
59 A(0), X(0), Y(0), SP(0), IR(0), PC(0),
60 N(false), V(false), B(false), D(false), I(false), notZ(false), C(false),
61 icycles(0),
62 myNumberOfDistinctAccesses(0),
63 myLastAddress(0),
64 myLastBreakCycle(ULLONG_MAX),
65 myLastPeekAddress(0),
66 myLastPokeAddress(0),
67 myLastPeekBaseAddress(0),
68 myLastPokeBaseAddress(0),
69 myFlags(DISASM_NONE),
70 myLastSrcAddressS(-1),
71 myLastSrcAddressA(-1),
72 myLastSrcAddressX(-1),
73 myLastSrcAddressY(-1),
74 myDataAddressForPoke(0),
75 myOnHaltCallback(nullptr),
76 myHaltRequested(false),
77 myGhostReadsTrap(false),
78 myReadFromWritePortBreak(false),
79 myWriteToReadPortBreak(false),
80 myStepStateByInstruction(false)
81{
82#ifdef DEBUGGER_SUPPORT
83 myDebugger = nullptr;
84 myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
85#endif
86}
87
88// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
89void M6502::install(System& system)
90{
91 // Remember which system I'm installed in
92 mySystem = &system;
93}
94
95// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
96void M6502::reset()
97{
98 // Clear the execution status flags
99 myExecutionStatus = 0;
100
101 // Set registers to random or default values
102 bool devSettings = mySettings.getBool("dev.settings");
103 const string& cpurandom = mySettings.getString(devSettings ? "dev.cpurandom" : "plr.cpurandom");
104 SP = BSPF::containsIgnoreCase(cpurandom, "S") ?
105 mySystem->randGenerator().next() : 0xfd;
106 A = BSPF::containsIgnoreCase(cpurandom, "A") ?
107 mySystem->randGenerator().next() : 0x00;
108 X = BSPF::containsIgnoreCase(cpurandom, "X") ?
109 mySystem->randGenerator().next() : 0x00;
110 Y = BSPF::containsIgnoreCase(cpurandom, "Y") ?
111 mySystem->randGenerator().next() : 0x00;
112 PS(BSPF::containsIgnoreCase(cpurandom, "P") ?
113 mySystem->randGenerator().next() : 0x20);
114
115 icycles = 0;
116
117 // Load PC from the reset vector
118 PC = uInt16(mySystem->peek(0xfffc)) | (uInt16(mySystem->peek(0xfffd)) << 8);
119
120 myLastAddress = myLastPeekAddress = myLastPokeAddress = myLastPeekBaseAddress = myLastPokeBaseAddress;
121 myLastSrcAddressS = myLastSrcAddressA =
122 myLastSrcAddressX = myLastSrcAddressY = -1;
123 myDataAddressForPoke = 0;
124 myFlags = DISASM_NONE;
125
126 myHaltRequested = false;
127 myGhostReadsTrap = mySettings.getBool("dbg.ghostreadstrap");
128 myReadFromWritePortBreak = devSettings ? mySettings.getBool("dev.rwportbreak") : false;
129 myWriteToReadPortBreak = devSettings ? mySettings.getBool("dev.wrportbreak") : false;
130
131 myLastBreakCycle = ULLONG_MAX;
132}
133
134// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
135inline uInt8 M6502::peek(uInt16 address, uInt8 flags)
136{
137 handleHalt();
138
139 ////////////////////////////////////////////////
140 // TODO - move this logic directly into CartAR
141 if(address != myLastAddress)
142 {
143 ++myNumberOfDistinctAccesses;
144 myLastAddress = address;
145 }
146 ////////////////////////////////////////////////
147 mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
148 icycles += SYSTEM_CYCLES_PER_CPU;
149 myFlags = flags;
150 uInt8 result = mySystem->peek(address, flags);
151 myLastPeekAddress = address;
152
153#ifdef DEBUGGER_SUPPORT
154 if(myReadTraps.isInitialized() && myReadTraps.isSet(address)
155 && (myGhostReadsTrap || flags != DISASM_NONE))
156 {
157 myLastPeekBaseAddress = myDebugger->getBaseAddress(myLastPeekAddress, true); // mirror handling
158 int cond = evalCondTraps();
159 if(cond > -1)
160 {
161 myJustHitReadTrapFlag = true;
162 stringstream msg;
163 msg << "RTrap" << (flags == DISASM_NONE ? "G[" : "[") << Common::Base::HEX2 << cond << "]"
164 << (myTrapCondNames[cond].empty() ? ": " : "If: {" + myTrapCondNames[cond] + "} ");
165 myHitTrapInfo.message = msg.str();
166 myHitTrapInfo.address = address;
167 }
168 }
169#endif // DEBUGGER_SUPPORT
170
171 return result;
172}
173
174// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
175inline void M6502::poke(uInt16 address, uInt8 value, uInt8 flags)
176{
177 ////////////////////////////////////////////////
178 // TODO - move this logic directly into CartAR
179 if(address != myLastAddress)
180 {
181 ++myNumberOfDistinctAccesses;
182 myLastAddress = address;
183 }
184 ////////////////////////////////////////////////
185 mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
186 icycles += SYSTEM_CYCLES_PER_CPU;
187 mySystem->poke(address, value, flags);
188 myLastPokeAddress = address;
189
190#ifdef DEBUGGER_SUPPORT
191 if(myWriteTraps.isInitialized() && myWriteTraps.isSet(address))
192 {
193 myLastPokeBaseAddress = myDebugger->getBaseAddress(myLastPokeAddress, false); // mirror handling
194 int cond = evalCondTraps();
195 if(cond > -1)
196 {
197 myJustHitWriteTrapFlag = true;
198 stringstream msg;
199 msg << "WTrap[" << Common::Base::HEX2 << cond << "]" << (myTrapCondNames[cond].empty() ? ": " : "If: {" + myTrapCondNames[cond] + "} ");
200 myHitTrapInfo.message = msg.str();
201 myHitTrapInfo.address = address;
202 }
203 }
204#endif // DEBUGGER_SUPPORT
205}
206
207// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
208void M6502::requestHalt()
209{
210 if (!myOnHaltCallback) throw runtime_error("onHaltCallback not configured");
211 myHaltRequested = true;
212}
213
214// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
215inline void M6502::handleHalt()
216{
217 if (myHaltRequested) {
218 myOnHaltCallback();
219 myHaltRequested = false;
220 }
221}
222
223// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
224void M6502::execute(uInt64 number, DispatchResult& result)
225{
226 _execute(number, result);
227
228#ifdef DEBUGGER_SUPPORT
229 // Debugger hack: this ensures that stepping a "STA WSYNC" will actually end at the
230 // beginning of the next line (otherwise, the next instruction would be stepped in order for
231 // the halt to take effect). This is safe because as we know that the next cycle will be a read
232 // cycle anyway.
233 handleHalt();
234#endif
235
236 // Make sure that the hardware state matches the current system clock. This is necessary
237 // to maintain a consistent state for the debugger after stepping and to make sure
238 // that audio samples are generated for the whole timeslice.
239 mySystem->tia().updateEmulation();
240 mySystem->m6532().updateEmulation();
241}
242
243// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
244bool M6502::execute(uInt64 number)
245{
246 DispatchResult result;
247
248 execute(number, result);
249
250 return result.isSuccess();
251}
252
253// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
254inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
255{
256 myExecutionStatus = 0;
257
258#ifdef DEBUGGER_SUPPORT
259 TIA& tia = mySystem->tia();
260 M6532& riot = mySystem->m6532();
261#endif
262
263 uInt64 previousCycles = mySystem->cycles();
264 uInt64 currentCycles = 0;
265
266 // Loop until execution is stopped or a fatal error occurs
267 for(;;)
268 {
269 while (!myExecutionStatus && currentCycles < cycles * SYSTEM_CYCLES_PER_CPU)
270 {
271 #ifdef DEBUGGER_SUPPORT
272 // Don't break if we haven't actually executed anything yet
273 if (myLastBreakCycle != mySystem->cycles()) {
274 if(myJustHitReadTrapFlag || myJustHitWriteTrapFlag)
275 {
276 bool read = myJustHitReadTrapFlag;
277 myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
278
279 myLastBreakCycle = mySystem->cycles();
280 result.setDebugger(currentCycles, myHitTrapInfo.message, myHitTrapInfo.address, read);
281 return;
282 }
283
284 if(myBreakPoints.isInitialized())
285 {
286 uInt8 bank = mySystem->cart().getBank(PC);
287
288 if(myBreakPoints.check(PC, bank))
289 {
290 myLastBreakCycle = mySystem->cycles();
291 // disable a one-shot breakpoint
292 if(myBreakPoints.get(PC, bank) & BreakpointMap::ONE_SHOT)
293 {
294 myBreakPoints.erase(PC, bank);
295 }
296 else
297 {
298 ostringstream msg;
299
300 msg << "BP: $" << Common::Base::HEX4 << PC << ", bank #" << std::dec << int(bank);
301 result.setDebugger(currentCycles, msg.str());
302 }
303 return;
304 }
305 }
306
307 int cond = evalCondBreaks();
308 if(cond > -1)
309 {
310 ostringstream msg;
311
312 msg << "CBP[" << Common::Base::HEX2 << cond << "]: " << myCondBreakNames[cond];
313
314 myLastBreakCycle = mySystem->cycles();
315 result.setDebugger(currentCycles, msg.str());
316 return;
317 }
318 }
319
320 int cond = evalCondSaveStates();
321 if(cond > -1)
322 {
323 ostringstream msg;
324 msg << "conditional savestate [" << Common::Base::HEX2 << cond << "]";
325 myDebugger->addState(msg.str());
326 }
327
328 mySystem->cart().clearAllRAMAccesses();
329 #endif // DEBUGGER_SUPPORT
330
331 uInt16 operandAddress = 0, intermediateAddress = 0;
332 uInt8 operand = 0;
333
334 // Reset the peek/poke address pointers
335 myLastPeekAddress = myLastPokeAddress = myDataAddressForPoke = 0;
336
337 try {
338 icycles = 0;
339 #ifdef DEBUGGER_SUPPORT
340 uInt16 oldPC = PC;
341 #endif
342
343 // Fetch instruction at the program counter
344 IR = peek(PC++, DISASM_CODE); // This address represents a code section
345
346 // Call code to execute the instruction
347 switch(IR)
348 {
349 // 6502 instruction emulation is generated by an M4 macro file
350 #include "M6502.ins"
351
352 default:
353 FatalEmulationError::raise("invalid instruction");
354 }
355
356 #ifdef DEBUGGER_SUPPORT
357 if(myReadFromWritePortBreak)
358 {
359 uInt16 rwpAddr = mySystem->cart().getIllegalRAMReadAccess();
360 if(rwpAddr)
361 {
362 ostringstream msg;
363 msg << "RWP[@ $" << Common::Base::HEX4 << rwpAddr << "]: ";
364 result.setDebugger(currentCycles, msg.str(), oldPC);
365 return;
366 }
367 }
368
369 if (myWriteToReadPortBreak)
370 {
371 uInt16 wrpAddr = mySystem->cart().getIllegalRAMWriteAccess();
372 if (wrpAddr)
373 {
374 ostringstream msg;
375 msg << "WRP[@ $" << Common::Base::HEX4 << wrpAddr << "]: ";
376 result.setDebugger(currentCycles, msg.str(), oldPC);
377 return;
378 }
379 }
380 #endif // DEBUGGER_SUPPORT
381 } catch (const FatalEmulationError& e) {
382 myExecutionStatus |= FatalErrorBit;
383 result.setMessage(e.what());
384 } catch (const EmulationWarning& e) {
385 result.setDebugger(currentCycles, e.what(), PC);
386 return;
387 }
388
389 currentCycles = (mySystem->cycles() - previousCycles);
390
391 #ifdef DEBUGGER_SUPPORT
392 if(myStepStateByInstruction)
393 {
394 // Check out M6502::execute for an explanation.
395 handleHalt();
396
397 tia.updateEmulation();
398 riot.updateEmulation();
399 }
400 #endif
401 }
402
403 // See if we need to handle an interrupt
404 if((myExecutionStatus & MaskableInterruptBit) ||
405 (myExecutionStatus & NonmaskableInterruptBit))
406 {
407 // Yes, so handle the interrupt
408 interruptHandler();
409 }
410
411 // See if a fatal error has occurred
412 if(myExecutionStatus & FatalErrorBit)
413 {
414 // Yes, so answer that something when wrong. The message has already been set when
415 // the exception was handled.
416 result.setFatal(currentCycles);
417 return;
418 }
419
420 // See if execution has been stopped
421 if(myExecutionStatus & StopExecutionBit)
422 {
423 // Yes, so answer that everything finished fine
424 result.setOk(currentCycles);
425 return;
426 }
427
428 if (currentCycles >= cycles * SYSTEM_CYCLES_PER_CPU) {
429 result.setOk(currentCycles);
430 return;
431 }
432 }
433}
434
435// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
436void M6502::interruptHandler()
437{
438 // Handle the interrupt
439 if((myExecutionStatus & MaskableInterruptBit) && !I)
440 {
441 mySystem->incrementCycles(7 * SYSTEM_CYCLES_PER_CPU);
442 mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
443 mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
444 mySystem->poke(0x0100 + SP--, PS() & (~0x10));
445 D = false;
446 I = true;
447 PC = uInt16(mySystem->peek(0xFFFE)) | (uInt16(mySystem->peek(0xFFFF)) << 8);
448 }
449 else if(myExecutionStatus & NonmaskableInterruptBit)
450 {
451 mySystem->incrementCycles(7 * SYSTEM_CYCLES_PER_CPU);
452 mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
453 mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
454 mySystem->poke(0x0100 + SP--, PS() & (~0x10));
455 D = false;
456 PC = uInt16(mySystem->peek(0xFFFA)) | (uInt16(mySystem->peek(0xFFFB)) << 8);
457 }
458
459 // Clear the interrupt bits in myExecutionStatus
460 myExecutionStatus &= ~(MaskableInterruptBit | NonmaskableInterruptBit);
461}
462
463// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
464bool M6502::save(Serializer& out) const
465{
466 try
467 {
468 out.putByte(A); // Accumulator
469 out.putByte(X); // X index register
470 out.putByte(Y); // Y index register
471 out.putByte(SP); // Stack Pointer
472 out.putByte(IR); // Instruction register
473 out.putShort(PC); // Program Counter
474
475 out.putBool(N); // N flag for processor status register
476 out.putBool(V); // V flag for processor status register
477 out.putBool(B); // B flag for processor status register
478 out.putBool(D); // D flag for processor status register
479 out.putBool(I); // I flag for processor status register
480 out.putBool(notZ); // Z flag complement for processor status register
481 out.putBool(C); // C flag for processor status register
482
483 out.putByte(myExecutionStatus);
484
485 // Indicates the number of distinct memory accesses
486 out.putInt(myNumberOfDistinctAccesses);
487 // Indicates the last address(es) which was accessed
488 out.putShort(myLastAddress);
489 out.putShort(myLastPeekAddress);
490 out.putShort(myLastPokeAddress);
491 out.putShort(myDataAddressForPoke);
492 out.putInt(myLastSrcAddressS);
493 out.putInt(myLastSrcAddressA);
494 out.putInt(myLastSrcAddressX);
495 out.putInt(myLastSrcAddressY);
496 out.putByte(myFlags);
497
498 out.putBool(myHaltRequested);
499 out.putLong(myLastBreakCycle);
500 }
501 catch(...)
502 {
503 cerr << "ERROR: M6502::save" << endl;
504 return false;
505 }
506
507 return true;
508}
509
510// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
511bool M6502::load(Serializer& in)
512{
513 try
514 {
515 A = in.getByte(); // Accumulator
516 X = in.getByte(); // X index register
517 Y = in.getByte(); // Y index register
518 SP = in.getByte(); // Stack Pointer
519 IR = in.getByte(); // Instruction register
520 PC = in.getShort(); // Program Counter
521
522 N = in.getBool(); // N flag for processor status register
523 V = in.getBool(); // V flag for processor status register
524 B = in.getBool(); // B flag for processor status register
525 D = in.getBool(); // D flag for processor status register
526 I = in.getBool(); // I flag for processor status register
527 notZ = in.getBool(); // Z flag complement for processor status register
528 C = in.getBool(); // C flag for processor status register
529
530 myExecutionStatus = in.getByte();
531
532 // Indicates the number of distinct memory accesses
533 myNumberOfDistinctAccesses = in.getInt();
534 // Indicates the last address(es) which was accessed
535 myLastAddress = in.getShort();
536 myLastPeekAddress = in.getShort();
537 myLastPokeAddress = in.getShort();
538 myDataAddressForPoke = in.getShort();
539 myLastSrcAddressS = in.getInt();
540 myLastSrcAddressA = in.getInt();
541 myLastSrcAddressX = in.getInt();
542 myLastSrcAddressY = in.getInt();
543 myFlags = in.getByte();
544
545 myHaltRequested = in.getBool();
546 myLastBreakCycle = in.getLong();
547
548 #ifdef DEBUGGER_SUPPORT
549 updateStepStateByInstruction();
550 #endif
551 }
552 catch(...)
553 {
554 cerr << "ERROR: M6502::load" << endl;
555 return false;
556 }
557
558 return true;
559}
560
561#ifdef DEBUGGER_SUPPORT
562// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
563void M6502::attach(Debugger& debugger)
564{
565 // Remember the debugger for this microprocessor
566 myDebugger = &debugger;
567}
568
569// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
570uInt32 M6502::addCondBreak(Expression* e, const string& name, bool oneShot)
571{
572 myCondBreaks.emplace_back(e);
573 myCondBreakNames.push_back(name);
574
575 updateStepStateByInstruction();
576
577 return uInt32(myCondBreaks.size() - 1);
578}
579
580// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
581bool M6502::delCondBreak(uInt32 idx)
582{
583 if(idx < myCondBreaks.size())
584 {
585 Vec::removeAt(myCondBreaks, idx);
586 Vec::removeAt(myCondBreakNames, idx);
587
588 updateStepStateByInstruction();
589
590 return true;
591 }
592 return false;
593}
594
595// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
596void M6502::clearCondBreaks()
597{
598 myCondBreaks.clear();
599 myCondBreakNames.clear();
600
601 updateStepStateByInstruction();
602}
603
604// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
605const StringList& M6502::getCondBreakNames() const
606{
607 return myCondBreakNames;
608}
609
610// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
611uInt32 M6502::addCondSaveState(Expression* e, const string& name)
612{
613 myCondSaveStates.emplace_back(e);
614 myCondSaveStateNames.push_back(name);
615
616 updateStepStateByInstruction();
617
618 return uInt32(myCondSaveStates.size() - 1);
619}
620
621// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
622bool M6502::delCondSaveState(uInt32 idx)
623{
624 if(idx < myCondSaveStates.size())
625 {
626 Vec::removeAt(myCondSaveStates, idx);
627 Vec::removeAt(myCondSaveStateNames, idx);
628
629 updateStepStateByInstruction();
630
631 return true;
632 }
633 return false;
634}
635
636// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
637void M6502::clearCondSaveStates()
638{
639 myCondSaveStates.clear();
640 myCondSaveStateNames.clear();
641
642 updateStepStateByInstruction();
643}
644
645// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
646const StringList& M6502::getCondSaveStateNames() const
647{
648 return myCondSaveStateNames;
649}
650
651// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
652uInt32 M6502::addCondTrap(Expression* e, const string& name)
653{
654 myTrapConds.emplace_back(e);
655 myTrapCondNames.push_back(name);
656
657 updateStepStateByInstruction();
658
659 return uInt32(myTrapConds.size() - 1);
660}
661
662// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
663bool M6502::delCondTrap(uInt32 brk)
664{
665 if(brk < myTrapConds.size())
666 {
667 Vec::removeAt(myTrapConds, brk);
668 Vec::removeAt(myTrapCondNames, brk);
669
670 updateStepStateByInstruction();
671
672 return true;
673 }
674 return false;
675}
676
677// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
678void M6502::clearCondTraps()
679{
680 myTrapConds.clear();
681 myTrapCondNames.clear();
682
683 updateStepStateByInstruction();
684}
685
686// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
687const StringList& M6502::getCondTrapNames() const
688{
689 return myTrapCondNames;
690}
691
692// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
693void M6502::updateStepStateByInstruction()
694{
695 myStepStateByInstruction = myCondBreaks.size() || myCondSaveStates.size() ||
696 myTrapConds.size();
697}
698#endif // DEBUGGER_SUPPORT
699