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 &reg, 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