1 #if (defined(DUMMYCPU) && !defined(__DUMMYCPU__H)) || (!defined(DUMMYCPU) && !defined(__CPU__H)) 2 #ifdef DUMMYCPU 3 #define __DUMMYCPU__H 4 #else 5 #define __CPU__H 6 #endif 7 8 #include "stdafx.h" 9 #include "Snapshotable.h" 10 #include "Types.h" 11 12 enum class NesModel; 13 class Console; 14 class MemoryManager; 15 class DummyCpu; 16 17 class CPU : public Snapshotable 18 { 19 #ifndef DUMMYCPU 20 friend DummyCpu; 21 #endif 22 23 public: 24 static constexpr uint16_t NMIVector = 0xFFFA; 25 static constexpr uint16_t ResetVector = 0xFFFC; 26 static constexpr uint16_t IRQVector = 0xFFFE; 27 static constexpr uint32_t ClockRateNtsc = 1789773; 28 static constexpr uint32_t ClockRatePal = 1662607; 29 static constexpr uint32_t ClockRateDendy = 1773448; 30 31 private: 32 typedef void(CPU::*Func)(); 33 34 uint64_t _cycleCount; 35 uint16_t _operand; 36 37 Func _opTable[256]; 38 AddrMode _addrMode[256]; 39 AddrMode _instAddrMode; 40 41 uint16_t _spriteDmaCounter; 42 bool _spriteDmaTransfer; 43 44 int8_t _dmcCounter; 45 bool _dmcDmaRunning; 46 bool _cpuWrite = false; 47 uint16_t _writeAddr = 0; 48 49 uint8_t _irqMask; 50 51 State _state; 52 shared_ptr<Console> _console; 53 MemoryManager* _memoryManager; 54 55 bool _prevRunIrq = false; 56 bool _runIrq = false; 57 58 bool _warnOnCrash = true; 59 60 #ifdef DUMMYCPU 61 uint32_t _writeCounter = 0; 62 uint16_t _writeAddresses[10]; 63 uint8_t _writeValue[10]; 64 bool _isDummyWrite[10]; 65 66 uint32_t _readCounter = 0; 67 uint16_t _readAddresses[10]; 68 uint8_t _readValue[10]; 69 bool _isDummyRead[10]; 70 #endif 71 72 void IncCycleCount(); 73 uint16_t FetchOperand(); 74 void IRQ(); 75 GetOPCode()76 uint8_t GetOPCode() 77 { 78 uint8_t opCode = MemoryRead(_state.PC, MemoryOperationType::ExecOpCode); 79 _state.PC++; 80 return opCode; 81 } 82 DummyRead()83 void DummyRead() 84 { 85 MemoryRead(_state.PC, MemoryOperationType::DummyRead); 86 } 87 ReadByte()88 uint8_t ReadByte() 89 { 90 uint8_t value = MemoryRead(_state.PC, MemoryOperationType::ExecOperand); 91 _state.PC++; 92 return value; 93 } 94 ReadWord()95 uint16_t ReadWord() 96 { 97 uint16_t value = MemoryReadWord(_state.PC, MemoryOperationType::ExecOperand); 98 _state.PC += 2; 99 return value; 100 } 101 ClearFlags(uint8_t flags)102 void ClearFlags(uint8_t flags) 103 { 104 _state.PS &= ~flags; 105 } 106 SetFlags(uint8_t flags)107 void SetFlags(uint8_t flags) 108 { 109 _state.PS |= flags; 110 } 111 CheckFlag(uint8_t flag)112 bool CheckFlag(uint8_t flag) 113 { 114 return (_state.PS & flag) == flag; 115 } 116 SetZeroNegativeFlags(uint8_t value)117 void SetZeroNegativeFlags(uint8_t value) 118 { 119 if(value == 0) { 120 SetFlags(PSFlags::Zero); 121 } else if(value & 0x80) { 122 SetFlags(PSFlags::Negative); 123 } 124 } 125 CheckPageCrossed(uint16_t valA,int8_t valB)126 bool CheckPageCrossed(uint16_t valA, int8_t valB) 127 { 128 return ((valA + valB) & 0xFF00) != (valA & 0xFF00); 129 } 130 CheckPageCrossed(uint16_t valA,uint8_t valB)131 bool CheckPageCrossed(uint16_t valA, uint8_t valB) 132 { 133 return ((valA + valB) & 0xFF00) != (valA & 0xFF00); 134 } 135 136 void MemoryWrite(uint16_t addr, uint8_t value, MemoryOperationType operationType = MemoryOperationType::Write); 137 uint8_t MemoryRead(uint16_t addr, MemoryOperationType operationType = MemoryOperationType::Read); 138 139 uint16_t MemoryReadWord(uint16_t addr, MemoryOperationType operationType = MemoryOperationType::Read) { 140 uint8_t lo = MemoryRead(addr, operationType); 141 uint8_t hi = MemoryRead(addr + 1, operationType); 142 return lo | hi << 8; 143 } 144 SetRegister(uint8_t & reg,uint8_t value)145 void SetRegister(uint8_t ®, uint8_t value) { 146 ClearFlags(PSFlags::Zero | PSFlags::Negative); 147 SetZeroNegativeFlags(value); 148 reg = value; 149 } 150 Push(uint8_t value)151 void Push(uint8_t value) { 152 MemoryWrite(SP() + 0x100, value); 153 SetSP(SP() - 1); 154 } 155 Push(uint16_t value)156 void Push(uint16_t value) { 157 Push((uint8_t)(value >> 8)); 158 Push((uint8_t)value); 159 } 160 Pop()161 uint8_t Pop() { 162 SetSP(SP() + 1); 163 return MemoryRead(0x100 + SP()); 164 } 165 PopWord()166 uint16_t PopWord() { 167 uint8_t lo = Pop(); 168 uint8_t hi = Pop(); 169 170 return lo | hi << 8; 171 } 172 A()173 uint8_t A() { return _state.A; } SetA(uint8_t value)174 void SetA(uint8_t value) { SetRegister(_state.A, value); } X()175 uint8_t X() { return _state.X; } SetX(uint8_t value)176 void SetX(uint8_t value) { SetRegister(_state.X, value); } Y()177 uint8_t Y() { return _state.Y; } SetY(uint8_t value)178 void SetY(uint8_t value) { SetRegister(_state.Y, value); } SP()179 uint8_t SP() { return _state.SP; } SetSP(uint8_t value)180 void SetSP(uint8_t value) { _state.SP = value; } PS()181 uint8_t PS() { return _state.PS; } SetPS(uint8_t value)182 void SetPS(uint8_t value) { _state.PS = value & 0xCF; } PC()183 uint16_t PC() { return _state.PC; } SetPC(uint16_t value)184 void SetPC(uint16_t value) { _state.PC = value; } 185 GetOperand()186 uint16_t GetOperand() 187 { 188 return _operand; 189 } 190 GetOperandValue()191 uint8_t GetOperandValue() 192 { 193 if(_instAddrMode >= AddrMode::Zero) { 194 return MemoryRead(GetOperand()); 195 } else { 196 return (uint8_t)GetOperand(); 197 } 198 } 199 GetIndAddr()200 uint16_t GetIndAddr() { return ReadWord(); } GetImmediate()201 uint8_t GetImmediate() { return ReadByte(); } GetZeroAddr()202 uint8_t GetZeroAddr() { return ReadByte(); } GetZeroXAddr()203 uint8_t GetZeroXAddr() { 204 uint8_t value = ReadByte(); 205 MemoryRead(value, MemoryOperationType::DummyRead); //Dummy read 206 return value + X(); 207 } GetZeroYAddr()208 uint8_t GetZeroYAddr() { 209 uint8_t value = ReadByte(); 210 MemoryRead(value, MemoryOperationType::DummyRead); //Dummy read 211 return value + Y(); 212 } GetAbsAddr()213 uint16_t GetAbsAddr() { return ReadWord(); } 214 215 uint16_t GetAbsXAddr(bool dummyRead = true) { 216 uint16_t baseAddr = ReadWord(); 217 bool pageCrossed = CheckPageCrossed(baseAddr, X()); 218 219 if(pageCrossed || dummyRead) { 220 //Dummy read done by the processor (only when page is crossed for READ instructions) 221 MemoryRead(baseAddr + X() - (pageCrossed ? 0x100 : 0), MemoryOperationType::DummyRead); 222 } 223 return baseAddr + X(); 224 } 225 226 uint16_t GetAbsYAddr(bool dummyRead = true) { 227 uint16_t baseAddr = ReadWord(); 228 bool pageCrossed = CheckPageCrossed(baseAddr, Y()); 229 230 if(pageCrossed || dummyRead) { 231 //Dummy read done by the processor (only when page is crossed for READ instructions) 232 MemoryRead(baseAddr + Y() - (pageCrossed ? 0x100 : 0), MemoryOperationType::DummyRead); 233 } 234 235 return baseAddr + Y(); 236 } 237 GetInd()238 uint16_t GetInd() { 239 uint16_t addr = GetOperand(); 240 if((addr & 0xFF) == 0xFF) { 241 auto lo = MemoryRead(addr); 242 auto hi = MemoryRead(addr - 0xFF); 243 return (lo | hi << 8); 244 } else { 245 return MemoryReadWord(addr); 246 } 247 } 248 GetIndXAddr()249 uint16_t GetIndXAddr() { 250 uint8_t zero = ReadByte(); 251 252 //Dummy read 253 MemoryRead(zero, MemoryOperationType::DummyRead); 254 255 zero += X(); 256 257 uint16_t addr; 258 if(zero == 0xFF) { 259 addr = MemoryRead(0xFF) | MemoryRead(0x00) << 8; 260 } else { 261 addr = MemoryReadWord(zero); 262 } 263 return addr; 264 } 265 266 uint16_t GetIndYAddr(bool dummyRead = true) { 267 uint8_t zero = ReadByte(); 268 269 uint16_t addr; 270 if(zero == 0xFF) { 271 addr = MemoryRead(0xFF) | MemoryRead(0x00) << 8; 272 } else { 273 addr = MemoryReadWord(zero); 274 } 275 276 bool pageCrossed = CheckPageCrossed(addr, Y()); 277 if(pageCrossed || dummyRead) { 278 //Dummy read done by the processor (only when page is crossed for READ instructions) 279 MemoryRead(addr + Y() - (pageCrossed ? 0x100 : 0), MemoryOperationType::DummyRead); 280 } 281 return addr + Y(); 282 } 283 AND()284 void AND() { SetA(A() & GetOperandValue()); } EOR()285 void EOR() { SetA(A() ^ GetOperandValue()); } ORA()286 void ORA() { SetA(A() | GetOperandValue()); } 287 ADD(uint8_t value)288 void ADD(uint8_t value) 289 { 290 uint16_t result = (uint16_t)A() + (uint16_t)value + (CheckFlag(PSFlags::Carry) ? PSFlags::Carry : 0x00); 291 292 ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Overflow | PSFlags::Zero); 293 SetZeroNegativeFlags((uint8_t)result); 294 if(~(A() ^ value) & (A() ^ result) & 0x80) { 295 SetFlags(PSFlags::Overflow); 296 } 297 if(result > 0xFF) { 298 SetFlags(PSFlags::Carry); 299 } 300 SetA((uint8_t)result); 301 } 302 ADC()303 void ADC() { ADD(GetOperandValue()); } SBC()304 void SBC() { ADD(GetOperandValue() ^ 0xFF); } 305 CMP(uint8_t reg,uint8_t value)306 void CMP(uint8_t reg, uint8_t value) 307 { 308 ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Zero); 309 310 auto result = reg - value; 311 312 if(reg >= value) { 313 SetFlags(PSFlags::Carry); 314 } 315 if(reg == value) { 316 SetFlags(PSFlags::Zero); 317 } 318 if((result & 0x80) == 0x80) { 319 SetFlags(PSFlags::Negative); 320 } 321 } 322 CPA()323 void CPA() { CMP(A(), GetOperandValue()); } CPX()324 void CPX() { CMP(X(), GetOperandValue()); } CPY()325 void CPY() { CMP(Y(), GetOperandValue()); } 326 INC()327 void INC() 328 { 329 uint16_t addr = GetOperand(); 330 ClearFlags(PSFlags::Negative | PSFlags::Zero); 331 uint8_t value = MemoryRead(addr); 332 333 MemoryWrite(addr, value, MemoryOperationType::DummyWrite); //Dummy write 334 335 value++; 336 SetZeroNegativeFlags(value); 337 MemoryWrite(addr, value); 338 } 339 DEC()340 void DEC() 341 { 342 uint16_t addr = GetOperand(); 343 ClearFlags(PSFlags::Negative | PSFlags::Zero); 344 uint8_t value = MemoryRead(addr); 345 MemoryWrite(addr, value, MemoryOperationType::DummyWrite); //Dummy write 346 347 value--; 348 SetZeroNegativeFlags(value); 349 MemoryWrite(addr, value); 350 } 351 ASL(uint8_t value)352 uint8_t ASL(uint8_t value) 353 { 354 ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Zero); 355 if(value & 0x80) { 356 SetFlags(PSFlags::Carry); 357 } 358 359 uint8_t result = value << 1; 360 SetZeroNegativeFlags(result); 361 return result; 362 } 363 LSR(uint8_t value)364 uint8_t LSR(uint8_t value) { 365 ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Zero); 366 if(value & 0x01) { 367 SetFlags(PSFlags::Carry); 368 } 369 370 uint8_t result = value >> 1; 371 SetZeroNegativeFlags(result); 372 return result; 373 } 374 ROL(uint8_t value)375 uint8_t ROL(uint8_t value) { 376 bool carryFlag = CheckFlag(PSFlags::Carry); 377 ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Zero); 378 379 if(value & 0x80) { 380 SetFlags(PSFlags::Carry); 381 } 382 383 uint8_t result = (value << 1 | (carryFlag ? 0x01 : 0x00)); 384 SetZeroNegativeFlags(result); 385 return result; 386 } 387 ROR(uint8_t value)388 uint8_t ROR(uint8_t value) { 389 bool carryFlag = CheckFlag(PSFlags::Carry); 390 ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Zero); 391 if(value & 0x01) { 392 SetFlags(PSFlags::Carry); 393 } 394 395 uint8_t result = (value >> 1 | (carryFlag ? 0x80 : 0x00)); 396 SetZeroNegativeFlags(result); 397 return result; 398 } 399 ASLAddr()400 void ASLAddr() { 401 uint16_t addr = GetOperand(); 402 uint8_t value = MemoryRead(addr); 403 MemoryWrite(addr, value, MemoryOperationType::DummyWrite); //Dummy write 404 MemoryWrite(addr, ASL(value)); 405 } 406 LSRAddr()407 void LSRAddr() { 408 uint16_t addr = GetOperand(); 409 uint8_t value = MemoryRead(addr); 410 MemoryWrite(addr, value, MemoryOperationType::DummyWrite); //Dummy write 411 MemoryWrite(addr, LSR(value)); 412 } 413 ROLAddr()414 void ROLAddr() { 415 uint16_t addr = GetOperand(); 416 uint8_t value = MemoryRead(addr); 417 MemoryWrite(addr, value, MemoryOperationType::DummyWrite); //Dummy write 418 MemoryWrite(addr, ROL(value)); 419 } 420 RORAddr()421 void RORAddr() { 422 uint16_t addr = GetOperand(); 423 uint8_t value = MemoryRead(addr); 424 MemoryWrite(addr, value, MemoryOperationType::DummyWrite); //Dummy write 425 MemoryWrite(addr, ROR(value)); 426 } 427 JMP(uint16_t addr)428 void JMP(uint16_t addr) { 429 SetPC(addr); 430 } 431 BranchRelative(bool branch)432 void BranchRelative(bool branch) { 433 int8_t offset = (int8_t)GetOperand(); 434 if(branch) { 435 //"a taken non-page-crossing branch ignores IRQ/NMI during its last clock, so that next instruction executes before the IRQ" 436 //Fixes "branch_delays_irq" test 437 if(_runIrq && !_prevRunIrq) { 438 _runIrq = false; 439 } 440 DummyRead(); 441 442 if(CheckPageCrossed(PC(), offset)) { 443 DummyRead(); 444 } 445 446 SetPC(PC() + offset); 447 } 448 } 449 BIT()450 void BIT() { 451 uint8_t value = GetOperandValue(); 452 ClearFlags(PSFlags::Zero | PSFlags::Overflow | PSFlags::Negative); 453 if((A() & value) == 0) { 454 SetFlags(PSFlags::Zero); 455 } 456 if(value & 0x40) { 457 SetFlags(PSFlags::Overflow); 458 } 459 if(value & 0x80) { 460 SetFlags(PSFlags::Negative); 461 } 462 } 463 464 //OP Codes LDA()465 void LDA() { SetA(GetOperandValue()); } LDX()466 void LDX() { SetX(GetOperandValue()); } LDY()467 void LDY() { SetY(GetOperandValue()); } 468 STA()469 void STA() { MemoryWrite(GetOperand(), A()); } STX()470 void STX() { MemoryWrite(GetOperand(), X()); } STY()471 void STY() { MemoryWrite(GetOperand(), Y()); } 472 TAX()473 void TAX() { SetX(A()); } TAY()474 void TAY() { SetY(A()); } TSX()475 void TSX() { SetX(SP()); } TXA()476 void TXA() { SetA(X()); } TXS()477 void TXS() { SetSP(X()); } TYA()478 void TYA() { SetA(Y()); } 479 PHA()480 void PHA() { Push(A()); } PHP()481 void PHP() { 482 uint8_t flags = PS() | PSFlags::Break | PSFlags::Reserved; 483 Push((uint8_t)flags); 484 } PLA()485 void PLA() { 486 DummyRead(); 487 SetA(Pop()); 488 } PLP()489 void PLP() { 490 DummyRead(); 491 SetPS(Pop()); 492 } 493 INX()494 void INX() { SetX(X() + 1); } INY()495 void INY() { SetY(Y() + 1); } 496 DEX()497 void DEX() { SetX(X() - 1); } DEY()498 void DEY() { SetY(Y() - 1); } 499 ASL_Acc()500 void ASL_Acc() { SetA(ASL(A())); } ASL_Memory()501 void ASL_Memory() { ASLAddr(); } 502 LSR_Acc()503 void LSR_Acc() { SetA(LSR(A())); } LSR_Memory()504 void LSR_Memory() { LSRAddr(); } 505 ROL_Acc()506 void ROL_Acc() { SetA(ROL(A())); } ROL_Memory()507 void ROL_Memory() { ROLAddr(); } 508 ROR_Acc()509 void ROR_Acc() { SetA(ROR(A())); } ROR_Memory()510 void ROR_Memory() { RORAddr(); } 511 JMP_Abs()512 void JMP_Abs() { 513 JMP(GetOperand()); 514 } JMP_Ind()515 void JMP_Ind() { JMP(GetInd()); } JSR()516 void JSR() { 517 uint16_t addr = GetOperand(); 518 DummyRead(); 519 Push((uint16_t)(PC() - 1)); 520 JMP(addr); 521 } RTS()522 void RTS() { 523 uint16_t addr = PopWord(); 524 DummyRead(); 525 DummyRead(); 526 SetPC(addr + 1); 527 } 528 BCC()529 void BCC() { 530 BranchRelative(!CheckFlag(PSFlags::Carry)); 531 } 532 BCS()533 void BCS() { 534 BranchRelative(CheckFlag(PSFlags::Carry)); 535 } 536 BEQ()537 void BEQ() { 538 BranchRelative(CheckFlag(PSFlags::Zero)); 539 } 540 BMI()541 void BMI() { 542 BranchRelative(CheckFlag(PSFlags::Negative)); 543 } 544 BNE()545 void BNE() { 546 BranchRelative(!CheckFlag(PSFlags::Zero)); 547 } 548 BPL()549 void BPL() { 550 BranchRelative(!CheckFlag(PSFlags::Negative)); 551 } 552 BVC()553 void BVC() { 554 BranchRelative(!CheckFlag(PSFlags::Overflow)); 555 } 556 BVS()557 void BVS() { 558 BranchRelative(CheckFlag(PSFlags::Overflow)); 559 } 560 CLC()561 void CLC() { ClearFlags(PSFlags::Carry); } CLD()562 void CLD() { ClearFlags(PSFlags::Decimal); } CLI()563 void CLI() { ClearFlags(PSFlags::Interrupt); } CLV()564 void CLV() { ClearFlags(PSFlags::Overflow); } SEC()565 void SEC() { SetFlags(PSFlags::Carry); } SED()566 void SED() { SetFlags(PSFlags::Decimal); } SEI()567 void SEI() { SetFlags(PSFlags::Interrupt); } 568 569 void BRK(); 570 RTI()571 void RTI() { 572 DummyRead(); 573 SetPS(Pop()); 574 SetPC(PopWord()); 575 } 576 NOP()577 void NOP() { 578 //Make sure the nop operation takes as many cycles as meant to 579 GetOperandValue(); 580 } 581 582 583 //Unofficial OpCodes SLO()584 void SLO() 585 { 586 //ASL & ORA 587 uint8_t value = GetOperandValue(); 588 MemoryWrite(GetOperand(), value, MemoryOperationType::DummyWrite); //Dummy write 589 uint8_t shiftedValue = ASL(value); 590 SetA(A() | shiftedValue); 591 MemoryWrite(GetOperand(), shiftedValue); 592 } 593 SRE()594 void SRE() 595 { 596 //ROL & AND 597 uint8_t value = GetOperandValue(); 598 MemoryWrite(GetOperand(), value, MemoryOperationType::DummyWrite); //Dummy write 599 uint8_t shiftedValue = LSR(value); 600 SetA(A() ^ shiftedValue); 601 MemoryWrite(GetOperand(), shiftedValue); 602 } 603 RLA()604 void RLA() 605 { 606 //LSR & EOR 607 uint8_t value = GetOperandValue(); 608 MemoryWrite(GetOperand(), value, MemoryOperationType::DummyWrite); //Dummy write 609 uint8_t shiftedValue = ROL(value); 610 SetA(A() & shiftedValue); 611 MemoryWrite(GetOperand(), shiftedValue); 612 } 613 RRA()614 void RRA() 615 { 616 //ROR & ADC 617 uint8_t value = GetOperandValue(); 618 MemoryWrite(GetOperand(), value, MemoryOperationType::DummyWrite); //Dummy write 619 uint8_t shiftedValue = ROR(value); 620 ADD(shiftedValue); 621 MemoryWrite(GetOperand(), shiftedValue); 622 } 623 SAX()624 void SAX() 625 { 626 //STA & STX 627 MemoryWrite(GetOperand(), A() & X()); 628 } 629 LAX()630 void LAX() 631 { 632 //LDA & LDX 633 uint8_t value = GetOperandValue(); 634 SetX(value); 635 SetA(value); 636 } 637 DCP()638 void DCP() 639 { 640 //DEC & CMP 641 uint8_t value = GetOperandValue(); 642 MemoryWrite(GetOperand(), value, MemoryOperationType::DummyWrite); //Dummy write 643 value--; 644 CMP(A(), value); 645 MemoryWrite(GetOperand(), value); 646 } 647 ISB()648 void ISB() 649 { 650 //INC & SBC 651 uint8_t value = GetOperandValue(); 652 MemoryWrite(GetOperand(), value, MemoryOperationType::DummyWrite); //Dummy write 653 value++; 654 ADD(value ^ 0xFF); 655 MemoryWrite(GetOperand(), value); 656 } 657 AAC()658 void AAC() 659 { 660 SetA(A() & GetOperandValue()); 661 662 ClearFlags(PSFlags::Carry); 663 if(CheckFlag(PSFlags::Negative)) { 664 SetFlags(PSFlags::Carry); 665 } 666 } 667 ASR()668 void ASR() 669 { 670 ClearFlags(PSFlags::Carry); 671 SetA(A() & GetOperandValue()); 672 if(A() & 0x01) { 673 SetFlags(PSFlags::Carry); 674 } 675 SetA(A() >> 1); 676 } 677 ARR()678 void ARR() 679 { 680 SetA(((A() & GetOperandValue()) >> 1) | (CheckFlag(PSFlags::Carry) ? 0x80 : 0x00)); 681 ClearFlags(PSFlags::Carry | PSFlags::Overflow); 682 if(A() & 0x40) { 683 SetFlags(PSFlags::Carry); 684 } 685 if((CheckFlag(PSFlags::Carry) ? 0x01 : 0x00) ^ ((A() >> 5) & 0x01)) { 686 SetFlags(PSFlags::Overflow); 687 } 688 } 689 ATX()690 void ATX() 691 { 692 //LDA & TAX 693 uint8_t value = GetOperandValue(); 694 SetA(value); //LDA 695 SetX(A()); //TAX 696 SetA(A()); //Update flags based on A 697 } 698 AXS()699 void AXS() 700 { 701 //CMP & DEX 702 uint8_t opValue = GetOperandValue(); 703 uint8_t value = (A() & X()) - opValue; 704 705 ClearFlags(PSFlags::Carry); 706 if((A() & X()) >= opValue) { 707 SetFlags(PSFlags::Carry); 708 } 709 710 SetX(value); 711 } 712 SYA()713 void SYA() 714 { 715 uint8_t addrHigh = GetOperand() >> 8; 716 uint8_t addrLow = GetOperand() & 0xFF; 717 uint8_t value = Y() & (addrHigh + 1); 718 719 //From here: http://forums.nesdev.com/viewtopic.php?f=3&t=3831&start=30 720 //Unsure if this is accurate or not 721 //"the target address for e.g. SYA becomes ((y & (addr_high + 1)) << 8) | addr_low instead of the normal ((addr_high + 1) << 8) | addr_low" 722 MemoryWrite(((Y() & (addrHigh + 1)) << 8) | addrLow, value); 723 } 724 SXA()725 void SXA() 726 { 727 uint8_t addrHigh = GetOperand() >> 8; 728 uint8_t addrLow = GetOperand() & 0xFF; 729 uint8_t value = X() & (addrHigh + 1); 730 MemoryWrite(((X() & (addrHigh + 1)) << 8) | addrLow, value); 731 } 732 733 //Unimplemented/Incorrect Unofficial OP codes HLT()734 void HLT() 735 { 736 //normally freezes the cpu, we can probably assume nothing will ever call this 737 GetOperandValue(); 738 } 739 UNK()740 void UNK() 741 { 742 //Make sure we take the right amount of cycles (not reliable for operations that write to memory, etc.) 743 GetOperandValue(); 744 } 745 AXA()746 void AXA() 747 { 748 uint16_t addr = GetOperand(); 749 750 //"This opcode stores the result of A AND X AND the high byte of the target address of the operand +1 in memory." 751 //This may not be the actual behavior, but the read/write operations are needed for proper cycle counting 752 MemoryWrite(GetOperand(), ((addr >> 8) + 1) & A() & X()); 753 } 754 TAS()755 void TAS() 756 { 757 //"AND X register with accumulator and store result in stack 758 //pointer, then AND stack pointer with the high byte of the 759 //target address of the argument + 1. Store result in memory." 760 uint16_t addr = GetOperand(); 761 SetSP(X() & A()); 762 MemoryWrite(addr, SP() & ((addr >> 8) + 1)); 763 } 764 LAS()765 void LAS() 766 { 767 //"AND memory with stack pointer, transfer result to accumulator, X register and stack pointer." 768 uint8_t value = GetOperandValue(); 769 SetA(value & SP()); 770 SetX(A()); 771 SetSP(A()); 772 } 773 774 protected: 775 void StreamState(bool saving) override; 776 777 public: 778 CPU(shared_ptr<Console> console); 779 GetCycleCount()780 uint64_t GetCycleCount() { return _cycleCount; } SetNmiFlag()781 void SetNmiFlag() { _state.NMIFlag = true; } ClearNmiFlag()782 void ClearNmiFlag() { _state.NMIFlag = false; } SetIrqMask(uint8_t mask)783 void SetIrqMask(uint8_t mask) { _irqMask = mask; } SetIrqSource(IRQSource source)784 void SetIrqSource(IRQSource source) { _state.IRQFlag |= (int)source; } HasIrqSource(IRQSource source)785 bool HasIrqSource(IRQSource source) { return (_state.IRQFlag & (int)source) != 0; } ClearIrqSource(IRQSource source)786 void ClearIrqSource(IRQSource source) { _state.IRQFlag &= ~(int)source; } 787 788 void RunDMATransfer(uint8_t offsetValue); 789 void StartDmcTransfer(); 790 791 uint32_t GetClockRate(NesModel model); IsCpuWrite()792 bool IsCpuWrite() { return _cpuWrite; } 793 794 //Used by debugger for "Set Next Statement" SetDebugPC(uint16_t value)795 void SetDebugPC(uint16_t value) { 796 SetPC(value); 797 _state.PreviousDebugPC = _state.DebugPC; 798 _state.DebugPC = value; 799 } 800 801 void Reset(bool softReset, NesModel model); 802 void Exec(); 803 GetState(State & state)804 void GetState(State &state) 805 { 806 state = _state; 807 state.CycleCount = _cycleCount; 808 } 809 GetDebugPC()810 uint16_t GetDebugPC() { return _state.DebugPC; } GetPC()811 uint16_t GetPC() { return _state.PC; } 812 SetState(State state)813 void SetState(State state) 814 { 815 uint16_t originalPc = state.PC; 816 uint16_t originalDebugPc = state.DebugPC; 817 _state = state; 818 _cycleCount = state.CycleCount; 819 state.PC = originalPc; 820 state.DebugPC = originalDebugPc; 821 } 822 823 #ifdef DUMMYCPU 824 #undef CPU SetDummyState(CPU * c)825 void SetDummyState(CPU *c) 826 { 827 #define CPU DummyCpu 828 _writeCounter = 0; 829 _readCounter = 0; 830 831 _state = c->_state; 832 833 _cycleCount = c->_cycleCount; 834 _operand = c->_operand; 835 _spriteDmaCounter = c->_spriteDmaCounter; 836 _spriteDmaTransfer = c->_spriteDmaTransfer; 837 _dmcCounter = c->_dmcCounter; 838 _dmcDmaRunning = c->_dmcDmaRunning; 839 _cpuWrite = c->_cpuWrite; 840 _irqMask = c->_irqMask; 841 _prevRunIrq = c->_prevRunIrq; 842 _runIrq = c->_runIrq; 843 _cycleCount = c->_cycleCount; 844 } 845 GetWriteCount()846 uint32_t GetWriteCount() 847 { 848 return _writeCounter; 849 } 850 GetReadCount()851 uint32_t GetReadCount() 852 { 853 return _readCounter; 854 } 855 GetWriteAddrValue(uint32_t index,uint16_t & addr,uint8_t & value,bool & isDummyWrite)856 void GetWriteAddrValue(uint32_t index, uint16_t &addr, uint8_t &value, bool &isDummyWrite) 857 { 858 addr = _writeAddresses[index]; 859 value = _writeValue[index]; 860 isDummyWrite = _isDummyWrite[index]; 861 } 862 GetReadAddr(uint32_t index,uint16_t & addr,uint8_t & value,bool & isDummyRead)863 void GetReadAddr(uint32_t index, uint16_t &addr, uint8_t &value, bool &isDummyRead) 864 { 865 addr = _readAddresses[index]; 866 value = _readValue[index]; 867 isDummyRead = _isDummyRead[index]; 868 } 869 #endif 870 }; 871 872 #endif