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#ifndef M6502_HXX
19#define M6502_HXX
20
21#include <functional>
22
23class Settings;
24class System;
25class DispatchResult;
26
27#ifdef DEBUGGER_SUPPORT
28 class Debugger;
29 class CpuDebug;
30
31 #include "Expression.hxx"
32 #include "TrapArray.hxx"
33 #include "BreakpointMap.hxx"
34#endif
35
36#include "bspf.hxx"
37#include "Serializable.hxx"
38
39/**
40 The 6502 is an 8-bit microprocessor that has a 64K addressing space.
41 This class provides a high compatibility 6502 microprocessor emulator.
42
43 The memory accesses and cycle counts it generates are valid at the
44 sub-instruction level and "false" reads are generated (such as the ones
45 produced by the Indirect,X addressing when it crosses a page boundary).
46 This provides provides better compatibility for hardware that has side
47 effects and for games which are very time sensitive.
48
49 @author Bradford W. Mott
50*/
51class M6502 : public Serializable
52{
53 // The 6502 and Cart debugger classes are friends who need special access
54 friend class CartDebug;
55 friend class CpuDebug;
56
57 public:
58
59 using onHaltCallback = std::function<void()>;
60
61 public:
62 /**
63 Create a new 6502 microprocessor.
64 */
65 explicit M6502(const Settings& settings);
66 virtual ~M6502() = default;
67
68 public:
69 /**
70 Install the processor in the specified system. Invoked by the
71 system when the processor is attached to it.
72
73 @param system The system the processor should install itself in
74 */
75 void install(System& system);
76
77 /**
78 Reset the processor to its power-on state. This method should not
79 be invoked until the entire 6502 system is constructed and installed
80 since it involves reading the reset vector from memory.
81 */
82 void reset();
83
84 /**
85 Request a maskable interrupt
86 */
87 void irq() { myExecutionStatus |= MaskableInterruptBit; }
88
89 /**
90 Request a non-maskable interrupt
91 */
92 void nmi() { myExecutionStatus |= NonmaskableInterruptBit; }
93
94 /**
95 Set the callback for handling a halt condition
96 */
97 void setOnHaltCallback(onHaltCallback callback) { myOnHaltCallback = callback; }
98
99 /**
100 RDY pulled low --- halt on next read.
101 */
102 void requestHalt();
103
104 /**
105 Pull RDY high again before the callback was triggered.
106 */
107 void clearHaltRequest() { myHaltRequested = false; }
108
109 /**
110 Execute instructions until the specified number of instructions
111 is executed, someone stops execution, or an error occurs. Answers
112 true iff execution stops normally.
113
114 @param cycles Indicates the number of cycles to execute. Not that the actual
115 granularity of the CPU is instructions, so this is only accurate up to
116 a couple of cycles
117 @param result A DispatchResult object that will transport the result
118 */
119 void execute(uInt64 cycles, DispatchResult& result);
120
121 bool execute(uInt64 cycles);
122
123 /**
124 Tell the processor to stop executing instructions. Invoking this
125 method while the processor is executing instructions will stop
126 execution as soon as possible.
127 */
128 void stop() { myExecutionStatus |= StopExecutionBit; }
129
130 /**
131 Answer true iff a fatal error has occured from which the processor
132 cannot recover (i.e. illegal instruction, etc.)
133
134 @return true iff a fatal error has occured
135 */
136 bool fatalError() const { return myExecutionStatus & FatalErrorBit; }
137
138 /**
139 Get the 16-bit value of the Program Counter register.
140
141 @return The program counter register
142 */
143 // uInt16 getPC() const { return PC; }
144
145 /**
146 Check the type of the last peek().
147
148 @return true, if the last peek() was a ghost read.
149 */
150 bool lastWasGhostPeek() const { return myFlags == 0; } // DISASM_NONE
151
152 /**
153 Return the last address that was part of a read/peek.
154
155 @return The address of the last read
156 */
157 uInt16 lastReadBaseAddress() const { return myLastPeekBaseAddress; }
158
159 /**
160 Return the last address that was part of a write/poke.
161
162 @return The address of the last write
163 */
164 uInt16 lastWriteBaseAddress() const { return myLastPokeBaseAddress; }
165
166 /**
167 Return the source of the address that was used for a write/poke.
168 Note that this isn't the same as the address that is poked, but
169 is instead the address of the *data* that is poked (if any).
170
171 @return The address of the data used in the last poke, else 0
172 */
173 uInt16 lastDataAddressForPoke() const { return myDataAddressForPoke; }
174
175 /**
176 Return the last data address used as part of a peek operation for
177 the S/A/X/Y registers. Note that if an address wasn't used (as in
178 immediate mode), then the address is -1.
179
180 @return The address of the data used in the last peek, else -1
181 */
182 Int32 lastSrcAddressS() const { return myLastSrcAddressS; }
183 Int32 lastSrcAddressA() const { return myLastSrcAddressA; }
184 Int32 lastSrcAddressX() const { return myLastSrcAddressX; }
185 Int32 lastSrcAddressY() const { return myLastSrcAddressY; }
186
187 /**
188 Get the number of memory accesses to distinct memory locations
189
190 @return The number of memory accesses to distinct memory locations
191 */
192 uInt32 distinctAccesses() const { return myNumberOfDistinctAccesses; }
193
194 /**
195 Saves the current state of this device to the given Serializer.
196
197 @param out The serializer device to save to.
198 @return The result of the save. True on success, false on failure.
199 */
200 bool save(Serializer& out) const override;
201
202 /**
203 Loads the current state of this device from the given Serializer.
204
205 @param in The Serializer device to load from.
206 @return The result of the load. True on success, false on failure.
207 */
208 bool load(Serializer& in) override;
209
210#ifdef DEBUGGER_SUPPORT
211 public:
212 // Attach the specified debugger.
213 void attach(Debugger& debugger);
214
215 TrapArray& readTraps() { return myReadTraps; }
216 TrapArray& writeTraps() { return myWriteTraps; }
217
218 BreakpointMap& breakPoints() { return myBreakPoints; }
219
220 // methods for 'breakif' handling
221 uInt32 addCondBreak(Expression* e, const string& name, bool oneShot = false);
222 bool delCondBreak(uInt32 idx);
223 void clearCondBreaks();
224 const StringList& getCondBreakNames() const;
225
226 // methods for 'savestateif' handling
227 uInt32 addCondSaveState(Expression* e, const string& name);
228 bool delCondSaveState(uInt32 idx);
229 void clearCondSaveStates();
230 const StringList& getCondSaveStateNames() const;
231
232 // methods for 'trapif' handling
233 uInt32 addCondTrap(Expression* e, const string& name);
234 bool delCondTrap(uInt32 brk);
235 void clearCondTraps();
236 const StringList& getCondTrapNames() const;
237
238 void setGhostReadsTrap(bool enable) { myGhostReadsTrap = enable; }
239 void setReadFromWritePortBreak(bool enable) { myReadFromWritePortBreak = enable; }
240 void setWriteToReadPortBreak(bool enable) { myWriteToReadPortBreak = enable; }
241#endif // DEBUGGER_SUPPORT
242
243 private:
244 /**
245 Get the byte at the specified address and update the cycle count.
246 Addresses marked as code are hints to the debugger/disassembler to
247 conclusively determine code sections, even if the disassembler cannot
248 find them itself.
249
250 @param address The address from which the value should be loaded
251 @param flags Indicates that this address has the given flags
252 for type of access (CODE, DATA, GFX, etc)
253
254 @return The byte at the specified address
255 */
256 uInt8 peek(uInt16 address, uInt8 flags);
257
258 /**
259 Change the byte at the specified address to the given value and
260 update the cycle count.
261
262 @param address The address where the value should be stored
263 @param value The value to be stored at the address
264 */
265 void poke(uInt16 address, uInt8 value, uInt8 flags = 0);
266
267 /**
268 Get the 8-bit value of the Processor Status register.
269
270 @return The processor status register
271 */
272 uInt8 PS() const {
273 uInt8 ps = 0x20;
274
275 if(N) ps |= 0x80;
276 if(V) ps |= 0x40;
277 if(B) ps |= 0x10;
278 if(D) ps |= 0x08;
279 if(I) ps |= 0x04;
280 if(!notZ) ps |= 0x02;
281 if(C) ps |= 0x01;
282
283 return ps;
284 }
285
286 /**
287 Change the Processor Status register to correspond to the given value.
288
289 @param ps The value to set the processor status register to
290 */
291 void PS(uInt8 ps) {
292 N = ps & 0x80;
293 V = ps & 0x40;
294 B = true; // B = ps & 0x10; The 6507's B flag always true
295 D = ps & 0x08;
296 I = ps & 0x04;
297 notZ = !(ps & 0x02);
298 C = ps & 0x01;
299 }
300
301 /**
302 Called after an interrupt has be requested using irq() or nmi()
303 */
304 void interruptHandler();
305
306 /**
307 Check whether halt was requested (RDY low) and notify
308 */
309 void handleHalt();
310
311 /**
312 This is the actual dispatch function that does the grunt work. M6502::execute
313 wraps it and makes sure that any pending halt is processed before returning.
314 */
315 void _execute(uInt64 cycles, DispatchResult& result);
316
317#ifdef DEBUGGER_SUPPORT
318 /**
319 Check whether we are required to update hardware (TIA + RIOT) in lockstep
320 with the CPU and update the flag accordingly.
321 */
322 void updateStepStateByInstruction();
323#endif // DEBUGGER_SUPPORT
324
325 private:
326 /**
327 Bit fields used to indicate that certain conditions need to be
328 handled such as stopping execution, fatal errors, maskable interrupts
329 and non-maskable interrupts (in myExecutionStatus)
330 */
331 static constexpr uInt8
332 StopExecutionBit = 0x01,
333 FatalErrorBit = 0x02,
334 MaskableInterruptBit = 0x04,
335 NonmaskableInterruptBit = 0x08
336 ;
337 uInt8 myExecutionStatus;
338
339 /// Pointer to the system the processor is installed in or the null pointer
340 System* mySystem;
341
342 /// Reference to the settings
343 const Settings& mySettings;
344
345 uInt8 A; // Accumulator
346 uInt8 X; // X index register
347 uInt8 Y; // Y index register
348 uInt8 SP; // Stack Pointer
349 uInt8 IR; // Instruction register
350 uInt16 PC; // Program Counter
351
352 bool N; // N flag for processor status register
353 bool V; // V flag for processor status register
354 bool B; // B flag for processor status register
355 bool D; // D flag for processor status register
356 bool I; // I flag for processor status register
357 bool notZ; // Z flag complement for processor status register
358 bool C; // C flag for processor status register
359
360 uInt8 icycles; // cycles of last instruction
361
362 /// Indicates the numer of distinct memory accesses
363 uInt32 myNumberOfDistinctAccesses;
364
365 /// Indicates the last address which was accessed
366 uInt16 myLastAddress;
367
368 /// Last cycle that triggered a breakpoint
369 uInt64 myLastBreakCycle;
370
371 /// Indicates the last address which was accessed specifically
372 /// by a peek or poke command
373 uInt16 myLastPeekAddress, myLastPokeAddress;
374 /// Indicates the last base (= non-mirrored) address which was
375 /// accessed specifically by a peek or poke command
376 uInt16 myLastPeekBaseAddress, myLastPokeBaseAddress;
377 // Indicates the type of the last access
378 uInt8 myFlags;
379
380 /// Indicates the last address used to access data by a peek command
381 /// for the CPU registers (S/A/X/Y)
382 Int32 myLastSrcAddressS, myLastSrcAddressA,
383 myLastSrcAddressX, myLastSrcAddressY;
384
385 /// Indicates the data address used by the last command that performed
386 /// a poke (currently, the last address used by STx)
387 /// If an address wasn't used (ie, as in immediate mode), the address
388 /// is set to zero
389 uInt16 myDataAddressForPoke;
390
391 /// Indicates the number of system cycles per processor cycle
392 static constexpr uInt32 SYSTEM_CYCLES_PER_CPU = 1;
393
394 /// Called when the processor enters halt state
395 onHaltCallback myOnHaltCallback;
396
397 /// Indicates whether RDY was pulled low
398 bool myHaltRequested;
399
400#ifdef DEBUGGER_SUPPORT
401 Int32 evalCondBreaks() {
402 for(Int32 i = Int32(myCondBreaks.size()) - 1; i >= 0; --i)
403 if(myCondBreaks[i]->evaluate())
404 return i;
405
406 return -1; // no break hit
407 }
408
409 Int32 evalCondSaveStates()
410 {
411 for(Int32 i = Int32(myCondSaveStates.size()) - 1; i >= 0; --i)
412 if(myCondSaveStates[i]->evaluate())
413 return i;
414
415 return -1; // no save state point hit
416 }
417
418 Int32 evalCondTraps()
419 {
420 for(Int32 i = Int32(myTrapConds.size()) - 1; i >= 0; --i)
421 if(myTrapConds[i]->evaluate())
422 return i;
423
424 return -1; // no trapif hit
425 }
426
427 /// Pointer to the debugger for this processor or the null pointer
428 Debugger* myDebugger;
429
430 // Addresses for which the specified action should occur
431 TrapArray myReadTraps, myWriteTraps;
432
433 // Did we just now hit a trap?
434 bool myJustHitReadTrapFlag;
435 bool myJustHitWriteTrapFlag;
436 struct HitTrapInfo {
437 string message;
438 int address;
439 };
440 HitTrapInfo myHitTrapInfo;
441
442 BreakpointMap myBreakPoints;
443 vector<unique_ptr<Expression>> myCondBreaks;
444 StringList myCondBreakNames;
445 vector<unique_ptr<Expression>> myCondSaveStates;
446 StringList myCondSaveStateNames;
447 vector<unique_ptr<Expression>> myTrapConds;
448 StringList myTrapCondNames;
449#endif // DEBUGGER_SUPPORT
450
451 bool myGhostReadsTrap; // trap on ghost reads
452 bool myReadFromWritePortBreak; // trap on reads from write ports
453 bool myWriteToReadPortBreak; // trap on writes to read ports
454 bool myStepStateByInstruction;
455
456 private:
457 // Following constructors and assignment operators not supported
458 M6502() = delete;
459 M6502(const M6502&) = delete;
460 M6502(M6502&&) = delete;
461 M6502& operator=(const M6502&) = delete;
462 M6502& operator=(M6502&&) = delete;
463};
464
465#endif
466