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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
use crate::addressing_mode::*;
use crate::instruction::*;
pub use crate::{address, status, Address};
use crate::{opcode, UnknownOpcode};
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct Cpu {
pub pc: Address,
pub sp: u8,
pub acc: u8,
pub x: u8,
pub y: u8,
pub status: StatusRegister,
}
impl Cpu {
pub fn new() -> Self {
Self {
pc: 0,
sp: 0xff,
acc: 0,
x: 0,
y: 0,
status: StatusRegister::new(),
}
}
pub fn retrieve_nmi_return_address_during_nmi<MRO: MemoryReadOnly>(
&self,
memory: &MRO,
) -> Option<Address> {
if self.pc == memory.read_u16_le_read_only(crate::interrupt_vector::NMI_LO) {
let lo = memory.read_u8_stack_read_only(self.sp.wrapping_add(2));
let hi = memory.read_u8_stack_read_only(self.sp.wrapping_add(3));
Some(address::from_u8_lo_hi(lo, hi))
} else {
None
}
}
pub fn nmi<M: Memory>(&mut self, memory: &mut M) {
self.push_stack_u8(memory, address::hi(self.pc));
self.push_stack_u8(memory, address::lo(self.pc));
self.push_stack_u8(memory, self.status.masked_with_brk_and_expansion());
self.pc = memory.read_u16_le(crate::interrupt_vector::NMI_LO);
}
pub fn push_stack_u8<M: Memory>(&mut self, memory: &mut M, value: u8) {
memory.write_u8_stack(self.sp, value);
self.sp = self.sp.wrapping_sub(1);
}
pub fn pop_stack_u8<M: Memory>(&mut self, memory: &mut M) -> u8 {
self.sp = self.sp.wrapping_add(1);
memory.read_u8_stack(self.sp)
}
pub fn start<M: Memory>(&mut self, memory: &mut M) {
self.pc = memory.read_u16_le(crate::interrupt_vector::START_LO);
}
pub fn run_for_cycles<M: Memory>(
&mut self,
memory: &mut M,
num_cycles: usize,
) -> Result<usize, UnknownOpcode> {
let mut cycle_count = 0;
while cycle_count < num_cycles {
cycle_count += self.step(memory)? as usize;
}
Ok(cycle_count)
}
pub fn step<M: Memory>(&mut self, memory: &mut M) -> Result<u8, UnknownOpcode> {
let opcode = memory.read_u8(self.pc);
let cycles = match opcode {
opcode::adc::ABSOLUTE => adc::interpret(Absolute, self, memory),
opcode::adc::ABSOLUTE_X_INDEXED => adc::interpret(AbsoluteXIndexed, self, memory),
opcode::adc::ABSOLUTE_Y_INDEXED => adc::interpret(AbsoluteYIndexed, self, memory),
opcode::adc::IMMEDIATE => adc::interpret(Immediate, self, memory),
opcode::adc::INDIRECT_Y_INDEXED => adc::interpret(IndirectYIndexed, self, memory),
opcode::adc::X_INDEXED_INDIRECT => adc::interpret(XIndexedIndirect, self, memory),
opcode::adc::ZERO_PAGE => adc::interpret(ZeroPage, self, memory),
opcode::adc::ZERO_PAGE_X_INDEXED => adc::interpret(ZeroPageXIndexed, self, memory),
opcode::ahx::unofficial0::ABSOLUTE_Y_INDEXED => {
ahx::interpret(AbsoluteYIndexed, self, memory)
}
opcode::ahx::unofficial0::INDIRECT_Y_INDEXED => {
ahx::interpret(IndirectYIndexed, self, memory)
}
opcode::alr::unofficial0::IMMEDIATE => alr::interpret(self, memory),
opcode::arr::unofficial0::IMMEDIATE => arr::interpret(self, memory),
opcode::anc::unofficial0::IMMEDIATE => anc::interpret(self, memory),
opcode::anc::unofficial1::IMMEDIATE => anc::interpret(self, memory),
opcode::and::ABSOLUTE => and::interpret(Absolute, self, memory),
opcode::and::ABSOLUTE_X_INDEXED => and::interpret(AbsoluteXIndexed, self, memory),
opcode::and::ABSOLUTE_Y_INDEXED => and::interpret(AbsoluteYIndexed, self, memory),
opcode::and::IMMEDIATE => and::interpret(Immediate, self, memory),
opcode::and::INDIRECT_Y_INDEXED => and::interpret(IndirectYIndexed, self, memory),
opcode::and::X_INDEXED_INDIRECT => and::interpret(XIndexedIndirect, self, memory),
opcode::and::ZERO_PAGE => and::interpret(ZeroPage, self, memory),
opcode::and::ZERO_PAGE_X_INDEXED => and::interpret(ZeroPageXIndexed, self, memory),
opcode::asl::ABSOLUTE => asl::interpret(Absolute, self, memory),
opcode::asl::ABSOLUTE_X_INDEXED => asl::interpret(AbsoluteXIndexed, self, memory),
opcode::asl::ACCUMULATOR => asl::interpret_acc(self),
opcode::asl::ZERO_PAGE => asl::interpret(ZeroPage, self, memory),
opcode::asl::ZERO_PAGE_X_INDEXED => asl::interpret(ZeroPageXIndexed, self, memory),
opcode::axs::unofficial0::IMMEDIATE => axs::interpret(self, memory),
opcode::bcc::RELATIVE => bcc::interpret(self, memory),
opcode::bcs::RELATIVE => bcs::interpret(self, memory),
opcode::beq::RELATIVE => beq::interpret(self, memory),
opcode::bmi::RELATIVE => bmi::interpret(self, memory),
opcode::bne::RELATIVE => bne::interpret(self, memory),
opcode::bpl::RELATIVE => bpl::interpret(self, memory),
opcode::bvc::RELATIVE => bvc::interpret(self, memory),
opcode::bvs::RELATIVE => bvs::interpret(self, memory),
opcode::bit::ABSOLUTE => bit::interpret(Absolute, self, memory),
opcode::bit::ZERO_PAGE => bit::interpret(ZeroPage, self, memory),
opcode::brk::IMPLIED => brk::interpret(self, memory),
opcode::clc::IMPLIED => clc::interpret(self),
opcode::cld::IMPLIED => cld::interpret(self),
opcode::cli::IMPLIED => cli::interpret(self),
opcode::clv::IMPLIED => clv::interpret(self),
opcode::cmp::ABSOLUTE => cmp::interpret(Absolute, self, memory),
opcode::cmp::ABSOLUTE_X_INDEXED => cmp::interpret(AbsoluteXIndexed, self, memory),
opcode::cmp::ABSOLUTE_Y_INDEXED => cmp::interpret(AbsoluteYIndexed, self, memory),
opcode::cmp::IMMEDIATE => cmp::interpret(Immediate, self, memory),
opcode::cmp::INDIRECT_Y_INDEXED => cmp::interpret(IndirectYIndexed, self, memory),
opcode::cmp::X_INDEXED_INDIRECT => cmp::interpret(XIndexedIndirect, self, memory),
opcode::cmp::ZERO_PAGE => cmp::interpret(ZeroPage, self, memory),
opcode::cmp::ZERO_PAGE_X_INDEXED => cmp::interpret(ZeroPageXIndexed, self, memory),
opcode::cpx::ABSOLUTE => cpx::interpret(Absolute, self, memory),
opcode::cpx::IMMEDIATE => cpx::interpret(Immediate, self, memory),
opcode::cpx::ZERO_PAGE => cpx::interpret(ZeroPage, self, memory),
opcode::cpy::ABSOLUTE => cpy::interpret(Absolute, self, memory),
opcode::cpy::IMMEDIATE => cpy::interpret(Immediate, self, memory),
opcode::cpy::ZERO_PAGE => cpy::interpret(ZeroPage, self, memory),
opcode::dcp::unofficial0::X_INDEXED_INDIRECT => {
dcp::interpret(XIndexedIndirect, self, memory)
}
opcode::dcp::unofficial0::ZERO_PAGE => dcp::interpret(ZeroPage, self, memory),
opcode::dcp::unofficial0::ABSOLUTE => dcp::interpret(Absolute, self, memory),
opcode::dcp::unofficial0::INDIRECT_Y_INDEXED => {
dcp::interpret(IndirectYIndexed, self, memory)
}
opcode::dcp::unofficial0::ZERO_PAGE_X_INDEXED => {
dcp::interpret(ZeroPageXIndexed, self, memory)
}
opcode::dcp::unofficial0::ABSOLUTE_X_INDEXED => {
dcp::interpret(AbsoluteXIndexed, self, memory)
}
opcode::dcp::unofficial0::ABSOLUTE_Y_INDEXED => {
dcp::interpret(AbsoluteYIndexed, self, memory)
}
opcode::dec::ABSOLUTE => dec::interpret(Absolute, self, memory),
opcode::dec::ABSOLUTE_X_INDEXED => dec::interpret(AbsoluteXIndexed, self, memory),
opcode::dec::ZERO_PAGE => dec::interpret(ZeroPage, self, memory),
opcode::dec::ZERO_PAGE_X_INDEXED => dec::interpret(ZeroPageXIndexed, self, memory),
opcode::dex::IMPLIED => dex::interpret(self),
opcode::dey::IMPLIED => dey::interpret(self),
opcode::eor::ABSOLUTE => eor::interpret(Absolute, self, memory),
opcode::eor::ABSOLUTE_X_INDEXED => eor::interpret(AbsoluteXIndexed, self, memory),
opcode::eor::ABSOLUTE_Y_INDEXED => eor::interpret(AbsoluteYIndexed, self, memory),
opcode::eor::IMMEDIATE => eor::interpret(Immediate, self, memory),
opcode::eor::INDIRECT_Y_INDEXED => eor::interpret(IndirectYIndexed, self, memory),
opcode::eor::X_INDEXED_INDIRECT => eor::interpret(XIndexedIndirect, self, memory),
opcode::eor::ZERO_PAGE => eor::interpret(ZeroPage, self, memory),
opcode::eor::ZERO_PAGE_X_INDEXED => eor::interpret(ZeroPageXIndexed, self, memory),
opcode::ign::unofficial0::ABSOLUTE => ign::interpret(Absolute, self, memory),
opcode::ign::unofficial0::ABSOLUTE_X_INDEXED => {
ign::interpret(AbsoluteXIndexed, self, memory)
}
opcode::ign::unofficial0::ZERO_PAGE => ign::interpret(ZeroPage, self, memory),
opcode::ign::unofficial0::ZERO_PAGE_X_INDEXED => {
ign::interpret(ZeroPageXIndexed, self, memory)
}
opcode::ign::unofficial1::ABSOLUTE_X_INDEXED => {
ign::interpret(AbsoluteXIndexed, self, memory)
}
opcode::ign::unofficial1::ZERO_PAGE => ign::interpret(ZeroPage, self, memory),
opcode::ign::unofficial1::ZERO_PAGE_X_INDEXED => {
ign::interpret(ZeroPageXIndexed, self, memory)
}
opcode::ign::unofficial2::ABSOLUTE_X_INDEXED => {
ign::interpret(AbsoluteXIndexed, self, memory)
}
opcode::ign::unofficial2::ZERO_PAGE => ign::interpret(ZeroPage, self, memory),
opcode::ign::unofficial2::ZERO_PAGE_X_INDEXED => {
ign::interpret(ZeroPageXIndexed, self, memory)
}
opcode::ign::unofficial3::ABSOLUTE_X_INDEXED => {
ign::interpret(AbsoluteXIndexed, self, memory)
}
opcode::ign::unofficial3::ZERO_PAGE_X_INDEXED => {
ign::interpret(ZeroPageXIndexed, self, memory)
}
opcode::ign::unofficial4::ABSOLUTE_X_INDEXED => {
ign::interpret(AbsoluteXIndexed, self, memory)
}
opcode::ign::unofficial4::ZERO_PAGE_X_INDEXED => {
ign::interpret(ZeroPageXIndexed, self, memory)
}
opcode::ign::unofficial5::ABSOLUTE_X_INDEXED => {
ign::interpret(AbsoluteXIndexed, self, memory)
}
opcode::ign::unofficial5::ZERO_PAGE_X_INDEXED => {
ign::interpret(ZeroPageXIndexed, self, memory)
}
opcode::inc::ABSOLUTE => inc::interpret(Absolute, self, memory),
opcode::inc::ABSOLUTE_X_INDEXED => inc::interpret(AbsoluteXIndexed, self, memory),
opcode::inc::ZERO_PAGE => inc::interpret(ZeroPage, self, memory),
opcode::inc::ZERO_PAGE_X_INDEXED => inc::interpret(ZeroPageXIndexed, self, memory),
opcode::inx::IMPLIED => inx::interpret(self),
opcode::iny::IMPLIED => iny::interpret(self),
opcode::isc::unofficial0::X_INDEXED_INDIRECT => {
isc::interpret(XIndexedIndirect, self, memory)
}
opcode::isc::unofficial0::ZERO_PAGE => isc::interpret(ZeroPage, self, memory),
opcode::isc::unofficial0::ABSOLUTE => isc::interpret(Absolute, self, memory),
opcode::isc::unofficial0::INDIRECT_Y_INDEXED => {
isc::interpret(IndirectYIndexed, self, memory)
}
opcode::isc::unofficial0::ZERO_PAGE_X_INDEXED => {
isc::interpret(ZeroPageXIndexed, self, memory)
}
opcode::isc::unofficial0::ABSOLUTE_X_INDEXED => {
isc::interpret(AbsoluteXIndexed, self, memory)
}
opcode::isc::unofficial0::ABSOLUTE_Y_INDEXED => {
isc::interpret(AbsoluteYIndexed, self, memory)
}
opcode::jmp::ABSOLUTE => jmp::interpret(Absolute, self, memory),
opcode::jmp::INDIRECT => jmp::interpret(Indirect, self, memory),
opcode::jsr::ABSOLUTE => jsr::interpret(Absolute, self, memory),
opcode::lax::unofficial0::ABSOLUTE => lax::interpret(Absolute, self, memory),
opcode::lax::unofficial0::ABSOLUTE_Y_INDEXED => {
lax::interpret(AbsoluteYIndexed, self, memory)
}
opcode::lax::unofficial0::IMMEDIATE => lax::interpret(Immediate, self, memory),
opcode::lax::unofficial0::X_INDEXED_INDIRECT => {
lax::interpret(XIndexedIndirect, self, memory)
}
opcode::lax::unofficial0::INDIRECT_Y_INDEXED => {
lax::interpret(IndirectYIndexed, self, memory)
}
opcode::lax::unofficial0::ZERO_PAGE => lax::interpret(ZeroPage, self, memory),
opcode::lax::unofficial0::ZERO_PAGE_Y_INDEXED => {
lax::interpret(ZeroPageYIndexed, self, memory)
}
opcode::lda::ABSOLUTE => lda::interpret(Absolute, self, memory),
opcode::lda::ABSOLUTE_X_INDEXED => lda::interpret(AbsoluteXIndexed, self, memory),
opcode::lda::ABSOLUTE_Y_INDEXED => lda::interpret(AbsoluteYIndexed, self, memory),
opcode::lda::IMMEDIATE => lda::interpret(Immediate, self, memory),
opcode::lda::INDIRECT_Y_INDEXED => lda::interpret(IndirectYIndexed, self, memory),
opcode::lda::X_INDEXED_INDIRECT => lda::interpret(XIndexedIndirect, self, memory),
opcode::lda::ZERO_PAGE => lda::interpret(ZeroPage, self, memory),
opcode::lda::ZERO_PAGE_X_INDEXED => lda::interpret(ZeroPageXIndexed, self, memory),
opcode::ldx::ABSOLUTE => ldx::interpret(Absolute, self, memory),
opcode::ldx::ABSOLUTE_Y_INDEXED => ldx::interpret(AbsoluteYIndexed, self, memory),
opcode::ldx::IMMEDIATE => ldx::interpret(Immediate, self, memory),
opcode::ldx::ZERO_PAGE => ldx::interpret(ZeroPage, self, memory),
opcode::ldx::ZERO_PAGE_Y_INDEXED => ldx::interpret(ZeroPageYIndexed, self, memory),
opcode::ldy::ABSOLUTE => ldy::interpret(Absolute, self, memory),
opcode::ldy::ABSOLUTE_X_INDEXED => ldy::interpret(AbsoluteXIndexed, self, memory),
opcode::ldy::IMMEDIATE => ldy::interpret(Immediate, self, memory),
opcode::ldy::ZERO_PAGE => ldy::interpret(ZeroPage, self, memory),
opcode::ldy::ZERO_PAGE_X_INDEXED => ldy::interpret(ZeroPageXIndexed, self, memory),
opcode::lsr::ABSOLUTE => lsr::interpret(Absolute, self, memory),
opcode::lsr::ABSOLUTE_X_INDEXED => lsr::interpret(AbsoluteXIndexed, self, memory),
opcode::lsr::ACCUMULATOR => lsr::interpret_acc(self),
opcode::lsr::ZERO_PAGE => lsr::interpret(ZeroPage, self, memory),
opcode::lsr::ZERO_PAGE_X_INDEXED => lsr::interpret(ZeroPageXIndexed, self, memory),
opcode::nop::IMPLIED => nop::interpret(self),
opcode::nop::unofficial0::IMPLIED => nop::interpret(self),
opcode::nop::unofficial1::IMPLIED => nop::interpret(self),
opcode::nop::unofficial2::IMPLIED => nop::interpret(self),
opcode::nop::unofficial3::IMPLIED => nop::interpret(self),
opcode::nop::unofficial4::IMPLIED => nop::interpret(self),
opcode::nop::unofficial5::IMPLIED => nop::interpret(self),
opcode::ora::ABSOLUTE => ora::interpret(Absolute, self, memory),
opcode::ora::ABSOLUTE_X_INDEXED => ora::interpret(AbsoluteXIndexed, self, memory),
opcode::ora::ABSOLUTE_Y_INDEXED => ora::interpret(AbsoluteYIndexed, self, memory),
opcode::ora::IMMEDIATE => ora::interpret(Immediate, self, memory),
opcode::ora::INDIRECT_Y_INDEXED => ora::interpret(IndirectYIndexed, self, memory),
opcode::ora::X_INDEXED_INDIRECT => ora::interpret(XIndexedIndirect, self, memory),
opcode::ora::ZERO_PAGE => ora::interpret(ZeroPage, self, memory),
opcode::ora::ZERO_PAGE_X_INDEXED => ora::interpret(ZeroPageXIndexed, self, memory),
opcode::pha::IMPLIED => pha::interpret(self, memory),
opcode::php::IMPLIED => php::interpret(self, memory),
opcode::pla::IMPLIED => pla::interpret(self, memory),
opcode::plp::IMPLIED => plp::interpret(self, memory),
opcode::rla::unofficial0::X_INDEXED_INDIRECT => {
rla::interpret(XIndexedIndirect, self, memory)
}
opcode::rla::unofficial0::ZERO_PAGE => rla::interpret(ZeroPage, self, memory),
opcode::rla::unofficial0::ABSOLUTE => rla::interpret(Absolute, self, memory),
opcode::rla::unofficial0::INDIRECT_Y_INDEXED => {
rla::interpret(IndirectYIndexed, self, memory)
}
opcode::rla::unofficial0::ZERO_PAGE_X_INDEXED => {
rla::interpret(ZeroPageXIndexed, self, memory)
}
opcode::rla::unofficial0::ABSOLUTE_X_INDEXED => {
rla::interpret(AbsoluteXIndexed, self, memory)
}
opcode::rla::unofficial0::ABSOLUTE_Y_INDEXED => {
rla::interpret(AbsoluteYIndexed, self, memory)
}
opcode::rol::ABSOLUTE => rol::interpret(Absolute, self, memory),
opcode::rol::ABSOLUTE_X_INDEXED => rol::interpret(AbsoluteXIndexed, self, memory),
opcode::rol::ACCUMULATOR => rol::interpret_acc(self),
opcode::rol::ZERO_PAGE => rol::interpret(ZeroPage, self, memory),
opcode::rol::ZERO_PAGE_X_INDEXED => rol::interpret(ZeroPageXIndexed, self, memory),
opcode::ror::ABSOLUTE => ror::interpret(Absolute, self, memory),
opcode::ror::ABSOLUTE_X_INDEXED => ror::interpret(AbsoluteXIndexed, self, memory),
opcode::ror::ACCUMULATOR => ror::interpret_acc(self),
opcode::ror::ZERO_PAGE => ror::interpret(ZeroPage, self, memory),
opcode::ror::ZERO_PAGE_X_INDEXED => ror::interpret(ZeroPageXIndexed, self, memory),
opcode::rra::unofficial0::X_INDEXED_INDIRECT => {
rra::interpret(XIndexedIndirect, self, memory)
}
opcode::rra::unofficial0::ZERO_PAGE => rra::interpret(ZeroPage, self, memory),
opcode::rra::unofficial0::ABSOLUTE => rra::interpret(Absolute, self, memory),
opcode::rra::unofficial0::INDIRECT_Y_INDEXED => {
rra::interpret(IndirectYIndexed, self, memory)
}
opcode::rra::unofficial0::ZERO_PAGE_X_INDEXED => {
rra::interpret(ZeroPageXIndexed, self, memory)
}
opcode::rra::unofficial0::ABSOLUTE_X_INDEXED => {
rra::interpret(AbsoluteXIndexed, self, memory)
}
opcode::rra::unofficial0::ABSOLUTE_Y_INDEXED => {
rra::interpret(AbsoluteYIndexed, self, memory)
}
opcode::rti::IMPLIED => rti::interpret(self, memory),
opcode::rts::IMPLIED => rts::interpret(self, memory),
opcode::sax::unofficial0::X_INDEXED_INDIRECT => {
sax::interpret(XIndexedIndirect, self, memory)
}
opcode::sax::unofficial0::ZERO_PAGE => sax::interpret(ZeroPage, self, memory),
opcode::sax::unofficial0::ABSOLUTE => sax::interpret(Absolute, self, memory),
opcode::sax::unofficial0::ZERO_PAGE_Y_INDEXED => {
sax::interpret(ZeroPageYIndexed, self, memory)
}
opcode::sbc::ABSOLUTE => sbc::interpret(Absolute, self, memory),
opcode::sbc::ABSOLUTE_X_INDEXED => sbc::interpret(AbsoluteXIndexed, self, memory),
opcode::sbc::ABSOLUTE_Y_INDEXED => sbc::interpret(AbsoluteYIndexed, self, memory),
opcode::sbc::IMMEDIATE => sbc::interpret(Immediate, self, memory),
opcode::sbc::INDIRECT_Y_INDEXED => sbc::interpret(IndirectYIndexed, self, memory),
opcode::sbc::X_INDEXED_INDIRECT => sbc::interpret(XIndexedIndirect, self, memory),
opcode::sbc::ZERO_PAGE => sbc::interpret(ZeroPage, self, memory),
opcode::sbc::ZERO_PAGE_X_INDEXED => sbc::interpret(ZeroPageXIndexed, self, memory),
opcode::sbc::unofficial0::IMMEDIATE => sbc::interpret(Immediate, self, memory),
opcode::sec::IMPLIED => sec::interpret(self),
opcode::sed::IMPLIED => sed::interpret(self),
opcode::sei::IMPLIED => sei::interpret(self),
opcode::skb::unofficial0::IMMEDIATE => skb::interpret(self, memory),
opcode::skb::unofficial1::IMMEDIATE => skb::interpret(self, memory),
opcode::skb::unofficial2::IMMEDIATE => skb::interpret(self, memory),
opcode::skb::unofficial3::IMMEDIATE => skb::interpret(self, memory),
opcode::skb::unofficial4::IMMEDIATE => skb::interpret(self, memory),
opcode::slo::unofficial0::X_INDEXED_INDIRECT => {
slo::interpret(XIndexedIndirect, self, memory)
}
opcode::slo::unofficial0::ZERO_PAGE => slo::interpret(ZeroPage, self, memory),
opcode::slo::unofficial0::ABSOLUTE => slo::interpret(Absolute, self, memory),
opcode::slo::unofficial0::INDIRECT_Y_INDEXED => {
slo::interpret(IndirectYIndexed, self, memory)
}
opcode::slo::unofficial0::ZERO_PAGE_X_INDEXED => {
slo::interpret(ZeroPageXIndexed, self, memory)
}
opcode::slo::unofficial0::ABSOLUTE_X_INDEXED => {
slo::interpret(AbsoluteXIndexed, self, memory)
}
opcode::slo::unofficial0::ABSOLUTE_Y_INDEXED => {
slo::interpret(AbsoluteYIndexed, self, memory)
}
opcode::sre::unofficial0::X_INDEXED_INDIRECT => {
sre::interpret(XIndexedIndirect, self, memory)
}
opcode::sre::unofficial0::ZERO_PAGE => sre::interpret(ZeroPage, self, memory),
opcode::sre::unofficial0::ABSOLUTE => sre::interpret(Absolute, self, memory),
opcode::sre::unofficial0::INDIRECT_Y_INDEXED => {
sre::interpret(IndirectYIndexed, self, memory)
}
opcode::sre::unofficial0::ZERO_PAGE_X_INDEXED => {
sre::interpret(ZeroPageXIndexed, self, memory)
}
opcode::sre::unofficial0::ABSOLUTE_X_INDEXED => {
sre::interpret(AbsoluteXIndexed, self, memory)
}
opcode::sre::unofficial0::ABSOLUTE_Y_INDEXED => {
sre::interpret(AbsoluteYIndexed, self, memory)
}
opcode::sta::ABSOLUTE => sta::interpret(Absolute, self, memory),
opcode::sta::ABSOLUTE_X_INDEXED => sta::interpret(AbsoluteXIndexed, self, memory),
opcode::sta::ABSOLUTE_Y_INDEXED => sta::interpret(AbsoluteYIndexed, self, memory),
opcode::sta::INDIRECT_Y_INDEXED => sta::interpret(IndirectYIndexed, self, memory),
opcode::sta::X_INDEXED_INDIRECT => sta::interpret(XIndexedIndirect, self, memory),
opcode::sta::ZERO_PAGE => sta::interpret(ZeroPage, self, memory),
opcode::sta::ZERO_PAGE_X_INDEXED => sta::interpret(ZeroPageXIndexed, self, memory),
opcode::stx::ABSOLUTE => stx::interpret(Absolute, self, memory),
opcode::stx::ZERO_PAGE => stx::interpret(ZeroPage, self, memory),
opcode::stx::ZERO_PAGE_Y_INDEXED => stx::interpret(ZeroPageYIndexed, self, memory),
opcode::sty::ABSOLUTE => sty::interpret(Absolute, self, memory),
opcode::sty::ZERO_PAGE => sty::interpret(ZeroPage, self, memory),
opcode::sty::ZERO_PAGE_X_INDEXED => sty::interpret(ZeroPageXIndexed, self, memory),
opcode::sxa::unofficial0::ABSOLUTE_Y_INDEXED => sxa::interpret(self, memory),
opcode::sya::unofficial0::ABSOLUTE_X_INDEXED => sya::interpret(self, memory),
opcode::tax::IMPLIED => tax::interpret(self),
opcode::tay::IMPLIED => tay::interpret(self),
opcode::tsx::IMPLIED => tsx::interpret(self),
opcode::txa::IMPLIED => txa::interpret(self),
opcode::txs::IMPLIED => txs::interpret(self),
opcode::tya::IMPLIED => tya::interpret(self),
_ => return Err(UnknownOpcode(opcode)),
};
Ok(cycles)
}
}
const STACK_ADDRESS_HI: u8 = 0x01;
pub trait Memory {
fn read_u8(&mut self, address: Address) -> u8;
fn read_u16_le(&mut self, address: Address) -> u16 {
let lo = self.read_u8(address);
let hi = self.read_u8(address.wrapping_add(1));
((hi as u16) << 8) | lo as u16
}
fn read_u8_zero_page(&mut self, address: u8) -> u8 {
self.read_u8(address as Address)
}
fn read_u16_le_zero_page(&mut self, address: u8) -> u16 {
let lo = self.read_u8_zero_page(address);
let hi = self.read_u8_zero_page(address.wrapping_add(1));
((hi as u16) << 8) | lo as u16
}
fn read_u8_stack(&mut self, stack_pointer: u8) -> u8 {
self.read_u8(address::from_u8_lo_hi(stack_pointer, STACK_ADDRESS_HI))
}
fn write_u8(&mut self, address: Address, data: u8);
fn write_u8_zero_page(&mut self, address: u8, data: u8) {
self.write_u8(address as Address, data);
}
fn write_u8_stack(&mut self, stack_pointer: u8, data: u8) {
self.write_u8(
address::from_u8_lo_hi(stack_pointer, STACK_ADDRESS_HI),
data,
);
}
}
pub trait MemoryReadOnly {
fn read_u8_read_only(&self, address: Address) -> u8;
fn read_u16_le_read_only(&self, address: Address) -> u16 {
let lo = self.read_u8_read_only(address);
let hi = self.read_u8_read_only(address + 1);
((hi as u16) << 8) | lo as u16
}
fn read_u8_stack_read_only(&self, stack_pointer: u8) -> u8 {
self.read_u8_read_only(address::from_u8_lo_hi(stack_pointer, STACK_ADDRESS_HI))
}
}
pub use status::Register as StatusRegister;