1
1
#ifndef _NES_CPU_HPP_
2
2
#define _NES_CPU_HPP_
3
3
4
- #include " types.hpp"
4
+ #include " common/BitField.hpp"
5
+ #include " common/types.hpp"
5
6
6
7
#include < array>
7
8
#include < string>
@@ -11,87 +12,63 @@ namespace nes {
11
12
class Bus ;
12
13
13
14
class CPU {
14
- public:
15
- CPU ();
16
- CPU (const CPU&) = delete ;
17
- CPU& operator =(const CPU&) = delete ;
18
-
19
- enum Flags : u8 {
20
- C = (1 << 0 ), // Carry bit.
21
- Z = (1 << 1 ), // Zero
22
- I = (1 << 2 ), // Disable Interrupts
23
- D = (1 << 3 ), // Decimal Mode
24
- B = (1 << 4 ), // Break
25
- U = (1 << 5 ), // Unused
26
- V = (1 << 6 ), // Overflow
27
- N = (1 << 7 ), // Negative
28
- };
29
-
30
- void connectBus (Bus *bus);
31
-
32
- void clock ();
33
- void step ();
34
- void reset ();
35
-
36
- void irq ();
37
- void nmi ();
38
-
39
- inline void setPC (u16 pc) { m_pc = pc; }
40
-
41
- [[nodiscard]] inline u16 getPC () const { return m_pc; }
42
-
43
- inline void setFlag (Flags flag, bool active) {
44
- if (active) {
45
- m_status |= flag;
46
- } else {
47
- m_status &= (~flag);
48
- }
49
- }
50
-
51
- [[nodiscard]] inline u8 getFlag (Flags flag) const { return m_status & flag; }
52
-
53
- [[nodiscard]] inline u8 getCycles () const { return m_cycles; }
54
-
55
- [[nodiscard]] std::string getDebugString () const ;
56
-
57
- private:
58
- enum AddressingMode {
59
- IMP, // Implied : No operand
60
- ACC, // Accumulator : No operand
61
- IMM, // Immediate : #VALUE
62
- REL, // Relative : $ADDR8 used with Branch Instructions
63
- ZP0, // ZeroPage : $ADDR8
64
- ZPX, // ZeroPage, X : $ADDR8 + X
65
- ZPY, // ZeroPage, Y : $ADDR8 + Y
66
- ABS, // Absolute : $ADDR16
67
- ABX, // Absolute, X : $ADDR16 + X
68
- ABY, // Absolute, Y : $ADDR16 + Y
69
- IND, // Indirect : ($ADDR16) used only with JMP
70
- IZX, // (Indirect, X) : ($ADDR16 + X)
71
- IZY, // (Indirect), Y : ($ADDR16) + Y
72
- };
73
-
74
- struct Opcode {
75
- public:
76
- std::string name;
77
- AddressingMode addressing;
78
- void (CPU::*operation)(u16) = nullptr ;
79
- u8 cycles { 0 };
80
- u8 page_cycles { 0 };
81
- };
82
-
83
- [[nodiscard]] u8 memRead (u16 addr, bool ro = false ) const ;
84
- [[nodiscard]] u16 memRead16 (u16 addr, bool ro = false ) const ;
85
- void memWrite (u16 addr, u8 data);
86
-
87
- void stackPush (u8 data);
88
- void stackPush16 (u16 data);
89
- [[nodiscard]] u8 stackPop ();
90
- [[nodiscard]] u16 stackPop16 ();
91
-
92
- [[nodiscard]] std::tuple<u16, bool > getOperandAddress (AddressingMode mode);
93
-
94
- // clang-format off
15
+ public:
16
+ CPU ();
17
+ CPU (const CPU&) = delete ;
18
+ CPU& operator =(const CPU&) = delete ;
19
+
20
+ void connectBus (Bus *bus);
21
+
22
+ void clock ();
23
+ void step ();
24
+ void reset ();
25
+
26
+ void irq ();
27
+ void nmi ();
28
+
29
+ inline void setPC (u16 pc) { m_reg.pc = pc; }
30
+
31
+ [[nodiscard]] inline u8 getCycles () const { return m_cycles; }
32
+
33
+ [[nodiscard]] std::string getDebugString () const ;
34
+
35
+ private:
36
+ enum AddressingMode {
37
+ IMP, // Implied : No operand
38
+ ACC, // Accumulator : No operand
39
+ IMM, // Immediate : #VALUE
40
+ REL, // Relative : $ADDR8 used with Branch Instructions
41
+ ZP0, // ZeroPage : $ADDR8
42
+ ZPX, // ZeroPage, X : $ADDR8 + X
43
+ ZPY, // ZeroPage, Y : $ADDR8 + Y
44
+ ABS, // Absolute : $ADDR16
45
+ ABX, // Absolute, X : $ADDR16 + X
46
+ ABY, // Absolute, Y : $ADDR16 + Y
47
+ IND, // Indirect : ($ADDR16) used only with JMP
48
+ IZX, // (Indirect, X) : ($ADDR16 + X)
49
+ IZY, // (Indirect), Y : ($ADDR16) + Y
50
+ };
51
+
52
+ struct Opcode {
53
+ std::string name;
54
+ AddressingMode addressing;
55
+ void (CPU::*operation)(u16) = nullptr ;
56
+ u8 cycles { 0 };
57
+ u8 page_cycles { 0 };
58
+ };
59
+
60
+ [[nodiscard]] u8 memRead (u16 addr, bool ro = false ) const ;
61
+ [[nodiscard]] u16 memRead16 (u16 addr, bool ro = false ) const ;
62
+ void memWrite (u16 addr, u8 data);
63
+
64
+ void stackPush (u8 data);
65
+ void stackPush16 (u16 data);
66
+ [[nodiscard]] u8 stackPop ();
67
+ [[nodiscard]] u16 stackPop16 ();
68
+
69
+ [[nodiscard]] std::tuple<u16, bool > getOperandAddress (AddressingMode mode);
70
+
71
+ // clang-format off
95
72
void ADC (u16 addr); void AND (u16 addr); void ASL (u16 addr); void BCC (u16 addr);
96
73
void BCS (u16 addr); void BEQ (u16 addr); void BIT (u16 addr); void BMI (u16 addr);
97
74
void BNE (u16 addr); void BPL (u16 addr); void BRK (u16 addr); void BVC (u16 addr);
@@ -108,26 +85,41 @@ namespace nes {
108
85
void TSX (u16 addr); void TXA (u16 addr); void TXS (u16 addr); void TYA (u16 addr);
109
86
110
87
void NIL (u16 addr); // Catch all "illegal" opcodes
111
- // clang-format on
112
88
113
- // Registers
114
- u16 m_pc { 0x0000 }; // Program Counter
115
- u8 m_sp { 0xfd }; // Stack Pointer
116
- u8 m_status { 0x24 }; // Status Register
117
- u8 m_reg_a { 0x00 }; // Accumulator Register
118
- u8 m_reg_x { 0x00 }; // X Register
119
- u8 m_reg_y { 0x00 }; // Y Register
89
+ // clang-format on
120
90
121
- u8 m_cycles { 8 };
91
+ // Registers
92
+ struct {
93
+ u16 pc { 0x0000 }; // Program Counter
94
+ u8 sp { 0xfd }; // Stack Pointer
122
95
123
- Bus *m_bus { nullptr };
96
+ u8 a { 0x00 }; // Accumulator Register
97
+ u8 x { 0x00 }; // X Register
98
+ u8 y { 0x00 }; // Y Register
124
99
125
- // NOTE: Convenience variables.
126
- u8 m_opcode {};
127
- Opcode m_instruction {};
100
+ union { // CPU status
101
+ u8 raw;
102
+ BitField<7 > n; // Negative
103
+ BitField<6 > v; // Overflow
104
+ BitField<5 > u; // Unused
105
+ BitField<4 > b; // Break
106
+ BitField<3 > d; // Decimal Mode
107
+ BitField<2 > i; // Disable Interrupts
108
+ BitField<1 > z; // Zero
109
+ BitField<0 > c; // Carry bit.
110
+ } p;
111
+ } m_reg;
128
112
129
- // Lookup table with all opcodes.
130
- std::array<Opcode, 256 > m_optable;
113
+ u8 m_cycles { 8 };
114
+
115
+ Bus *m_bus { nullptr };
116
+
117
+ // Convenience variables.
118
+ u8 m_opcode {};
119
+ Opcode m_instruction {};
120
+
121
+ // Lookup table with all opcodes.
122
+ std::array<Opcode, 256 > m_optable;
131
123
};
132
124
} // namespace nes
133
125
0 commit comments