-
Notifications
You must be signed in to change notification settings - Fork 0
/
cpu.hpp
219 lines (175 loc) · 6.12 KB
/
cpu.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#pragma once
#include <memory>
#include <cstdint>
#include "junknes.h"
#include "util.hpp"
class Cpu{
public:
// CPUから外部へアクセスするためのインターフェース
class Door{
public:
virtual ~Door();
virtual std::uint8_t read(std::uint16_t addr) = 0;
virtual void write(std::uint16_t addr, std::uint8_t value) = 0;
// 1命令ごとにAPUを処理する。FCEUXのパクリ
virtual void tickApu(int cycle /* CPU cycle */) = 0;
};
explicit Cpu(const std::shared_ptr<Door>& door);
void hardReset();
void softReset();
void triggerNmi();
void triggerIrq();
void oamDmaDelay();
void dmcDmaDelay(int cycle /* CPU cycle */);
void exec(int cycle /* PPU cycle */);
void beforeExec(JunknesCpuHook hook, void* userdata);
private:
void doNmi();
void doIrq();
void delay(int cycle /* CPU cycle */);
void fetchOp(std::uint8_t& opcode, std::uint16_t& operand);
JunknesCpuState state() const;
std::uint8_t read8(std::uint16_t addr);
std::uint16_t read16(std::uint16_t addr);
std::uint16_t read16_inpage(std::uint16_t addr);
void write8(std::uint16_t addr, std::uint8_t value);
void write16(std::uint16_t addr, std::uint16_t value);
void write16_inpage(std::uint16_t addr, std::uint16_t value);
std::uint8_t pop8();
std::uint16_t pop16();
void push8(std::uint8_t value);
void push16(std::uint16_t value);
std::uint16_t ADDR_ZPI(std::uint16_t arg, std::uint8_t idx);
std::uint16_t ADDR_ZPX(std::uint16_t arg);
std::uint16_t ADDR_ZPY(std::uint16_t arg);
std::uint16_t ADDR_ABI_READ(std::uint16_t arg, std::uint8_t idx);
std::uint16_t ADDR_ABX_READ(std::uint16_t arg);
std::uint16_t ADDR_ABY_READ(std::uint16_t arg);
std::uint16_t ADDR_ABI_WRITE(std::uint16_t arg, std::uint8_t idx);
std::uint16_t ADDR_ABX_WRITE(std::uint16_t arg);
std::uint16_t ADDR_ABY_WRITE(std::uint16_t arg);
std::uint16_t ADDR_IX(std::uint16_t arg);
std::uint16_t ADDR_IY_READ(std::uint16_t arg);
std::uint16_t ADDR_IY_WRITE(std::uint16_t arg);
std::uint8_t LD_ZP(std::uint16_t arg);
std::uint8_t LD_ZPX(std::uint16_t arg);
std::uint8_t LD_ZPY(std::uint16_t arg);
std::uint8_t LD_AB(std::uint16_t arg);
std::uint8_t LD_ABX(std::uint16_t arg);
std::uint8_t LD_ABY(std::uint16_t arg);
std::uint8_t LD_IX(std::uint16_t arg);
std::uint8_t LD_IY(std::uint16_t arg);
void ST_ZP(std::uint16_t arg, std::uint8_t value);
void ST_ZPX(std::uint16_t arg, std::uint8_t value);
void ST_ZPY(std::uint16_t arg, std::uint8_t value);
void ST_AB(std::uint16_t arg, std::uint8_t value);
void ST_ABX(std::uint16_t arg, std::uint8_t value);
void ST_ABY(std::uint16_t arg, std::uint8_t value);
void ST_IX(std::uint16_t arg, std::uint8_t value);
void ST_IY(std::uint16_t arg, std::uint8_t value);
struct AddrValue{
const std::uint16_t addr;
std::uint8_t value;
};
AddrValue AV_READ(std::uint16_t addr);
void AV_WRITE(AddrValue av);
AddrValue RMW_ZP(std::uint16_t arg);
AddrValue RMW_ZPX(std::uint16_t arg);
AddrValue RMW_AB(std::uint16_t arg);
AddrValue RMW_ABX(std::uint16_t arg);
AddrValue RMW_ABY(std::uint16_t arg);
AddrValue RMW_IX(std::uint16_t arg);
AddrValue RMW_IY(std::uint16_t arg);
void ZN_UPDATE(std::uint8_t value);
void LDA(std::uint8_t value);
void LDX(std::uint8_t value);
void LDY(std::uint8_t value);
void ADC(std::uint8_t value);
void SBC(std::uint8_t value);
void ORA(std::uint8_t value);
void AND(std::uint8_t value);
void EOR(std::uint8_t value);
void ASL_DO(std::uint8_t& value);
void ASL();
void ASL(AddrValue av);
void LSR_DO(std::uint8_t& value);
void LSR();
void LSR(AddrValue av);
void ROL_DO(std::uint8_t& value);
void ROL();
void ROL(AddrValue av);
void ROR_DO(std::uint8_t& value);
void ROR();
void ROR(AddrValue av);
void BIT(std::uint8_t value);
void INC_DO(std::uint8_t& value);
void INC(AddrValue av);
void DEC_DO(std::uint8_t& value);
void DEC(AddrValue av);
void CMP_DO(std::uint8_t lhs, std::uint8_t rhs);
void CMP(std::uint8_t value);
void CPX(std::uint8_t value);
void CPY(std::uint8_t value);
void BRANCH(std::uint16_t arg, bool cond);
void JMP_AB(std::uint16_t arg);
void JMP_IND(std::uint16_t arg);
void JSR(std::uint16_t arg);
void RTS();
void RTI();
void BRK();
void PUSH_P(bool b4);
void POP_P();
// unofficial
void KIL();
// http://wiki.nesdev.com/w/index.php/Programming_with_unofficial_opcodes
void ALR(std::uint8_t value);
void ANC(std::uint8_t value);
void ARR(std::uint8_t value);
void AXS(std::uint8_t value);
void LAX(std::uint8_t value);
void DCP(AddrValue av);
void ISC(AddrValue av);
void RLA(AddrValue av);
void RRA(AddrValue av);
void SLO(AddrValue av);
void SRE(AddrValue av);
// unofficial and unstable
// http://www.oxyron.de/html/opcodes02.html
// とりあえずFCEUXと同じ実装にしてある
void LAS(std::uint16_t arg); // stable?
uint8_t AHX_VALUE(std::uint16_t arg);
void AHX_ABY(std::uint16_t arg);
void AHX_IY(std::uint16_t arg);
void TAS(std::uint16_t arg);
void SHX(std::uint16_t arg);
void SHY(std::uint16_t arg);
void LAX_IM(std::uint16_t arg);
void XAA(std::uint16_t arg);
std::shared_ptr<Door> door_;
JunknesCpuHook beforeExecHook_;
void* beforeExecData_;
int restCycle_; // PPU cycle
bool nmi_;
bool irq_;
std::uint16_t PC_;
std::uint8_t A_;
std::uint8_t X_;
std::uint8_t Y_;
std::uint8_t S_;
union Status{
std::uint8_t raw;
explicit Status(std::uint8_t value=0) : raw(value) {};
Status& operator=(const Status& rhs) { raw = rhs.raw; return *this; }
BitField8<0> C;
BitField8<1> Z;
BitField8<2> I;
BitField8<3> D;
BitField8<4> b4;
BitField8<5> b5; // always 1
BitField8<6> V;
BitField8<7> N;
};
Status P_;
bool jammed_;
int apuRestCycle_; // CPU cycle
};