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