@tmustier/pi-nes 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/AGENTS.md +89 -1
  2. package/README.md +78 -49
  3. package/extensions/nes/config.ts +1 -18
  4. package/extensions/nes/index.ts +1 -21
  5. package/extensions/nes/native/nes-core/Cargo.lock +0 -2
  6. package/extensions/nes/native/nes-core/Cargo.toml +1 -1
  7. package/extensions/nes/native/nes-core/index.d.ts +5 -0
  8. package/extensions/nes/native/nes-core/index.node +0 -0
  9. package/extensions/nes/native/nes-core/native.d.ts +5 -0
  10. package/extensions/nes/native/nes-core/src/lib.rs +25 -0
  11. package/extensions/nes/native/nes-core/vendor/nes_rust/.cargo-ok +1 -0
  12. package/extensions/nes/native/nes-core/vendor/nes_rust/.cargo_vcs_info.json +5 -0
  13. package/extensions/nes/native/nes-core/vendor/nes_rust/.travis.yml +3 -0
  14. package/extensions/nes/native/nes-core/vendor/nes_rust/Cargo.toml +23 -0
  15. package/extensions/nes/native/nes-core/vendor/nes_rust/LICENSE +21 -0
  16. package/extensions/nes/native/nes-core/vendor/nes_rust/README.md +59 -0
  17. package/extensions/nes/native/nes-core/vendor/nes_rust/src/apu.rs +1114 -0
  18. package/extensions/nes/native/nes-core/vendor/nes_rust/src/audio.rs +6 -0
  19. package/extensions/nes/native/nes-core/vendor/nes_rust/src/button.rs +23 -0
  20. package/extensions/nes/native/nes-core/vendor/nes_rust/src/cpu.rs +2364 -0
  21. package/extensions/nes/native/nes-core/vendor/nes_rust/src/default_audio.rs +49 -0
  22. package/extensions/nes/native/nes-core/vendor/nes_rust/src/default_display.rs +47 -0
  23. package/extensions/nes/native/nes-core/vendor/nes_rust/src/default_input.rs +33 -0
  24. package/extensions/nes/native/nes-core/vendor/nes_rust/src/display.rs +10 -0
  25. package/extensions/nes/native/nes-core/vendor/nes_rust/src/input.rs +7 -0
  26. package/extensions/nes/native/nes-core/vendor/nes_rust/src/joypad.rs +86 -0
  27. package/extensions/nes/native/nes-core/vendor/nes_rust/src/lib.rs +168 -0
  28. package/extensions/nes/native/nes-core/vendor/nes_rust/src/mapper.rs +502 -0
  29. package/extensions/nes/native/nes-core/vendor/nes_rust/src/memory.rs +73 -0
  30. package/extensions/nes/native/nes-core/vendor/nes_rust/src/ppu.rs +1378 -0
  31. package/extensions/nes/native/nes-core/vendor/nes_rust/src/register.rs +560 -0
  32. package/extensions/nes/native/nes-core/vendor/nes_rust/src/rom.rs +231 -0
  33. package/extensions/nes/nes-component.ts +3 -8
  34. package/extensions/nes/nes-core.ts +29 -9
  35. package/extensions/nes/paths.ts +40 -0
  36. package/extensions/nes/renderer.ts +53 -88
  37. package/package.json +1 -1
@@ -0,0 +1,2364 @@
1
+ use register::Register;
2
+ use memory::Memory;
3
+ use rom::{HEADER_SIZE, Rom};
4
+ use ppu::Ppu;
5
+ use apu::Apu;
6
+ use button;
7
+ use joypad;
8
+ use joypad::Joypad;
9
+ use input::Input;
10
+ use display::Display;
11
+ use audio::Audio;
12
+
13
+ const SRAM_START: usize = 0x6000;
14
+ const SRAM_END: usize = 0x8000;
15
+ const SRAM_SIZE: usize = SRAM_END - SRAM_START;
16
+
17
+ fn to_joypad_button(button: button::Button) -> joypad::Button {
18
+ match button {
19
+ button::Button::Joypad1A |
20
+ button::Button::Joypad2A => joypad::Button::A,
21
+ button::Button::Joypad1B |
22
+ button::Button::Joypad2B => joypad::Button::B,
23
+ button::Button::Joypad1Up |
24
+ button::Button::Joypad2Up => joypad::Button::Up,
25
+ button::Button::Joypad1Down |
26
+ button::Button::Joypad2Down => joypad::Button::Down,
27
+ button::Button::Joypad1Left |
28
+ button::Button::Joypad2Left => joypad::Button::Left,
29
+ button::Button::Joypad1Right |
30
+ button::Button::Joypad2Right => joypad::Button::Right,
31
+ button::Button::Start => joypad::Button::Start,
32
+ button::Button::Select => joypad::Button::Select,
33
+ _ => joypad::Button::A // dummy @TODO: Throw an error?
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Ricoh 6502
39
+ * Refer to https://wiki.nesdev.com/w/index.php/CPU
40
+ */
41
+ pub struct Cpu {
42
+ // registers
43
+ pc: Register<u16>,
44
+ sp: Register<u8>,
45
+ a: Register<u8>,
46
+ x: Register<u8>,
47
+ y: Register<u8>,
48
+ p: CpuStatusRegister,
49
+
50
+ // CPU inside RAM
51
+ ram: Memory,
52
+ sram_dirty: bool,
53
+
54
+ // manage additional stall cycles eg. DMA or branch success
55
+ stall_cycles: u16,
56
+
57
+ input: Box<dyn Input>,
58
+
59
+ // other devices
60
+ ppu: Ppu,
61
+ apu: Apu,
62
+ joypad1: Joypad,
63
+ joypad2: Joypad,
64
+ rom: Rom
65
+ }
66
+
67
+ // interrupts
68
+
69
+ pub enum Interrupts {
70
+ NMI,
71
+ RESET,
72
+ IRQ,
73
+ BRK // not interrupt but instruction
74
+ }
75
+
76
+ fn interrupt_handler_address(interrupt_type: Interrupts) -> u16 {
77
+ match interrupt_type {
78
+ Interrupts::NMI => 0xFFFA,
79
+ Interrupts::RESET => 0xFFFC,
80
+ Interrupts::IRQ => 0xFFFE,
81
+ Interrupts::BRK => 0xFFFE
82
+ }
83
+ }
84
+
85
+ enum InstructionTypes {
86
+ INV,
87
+ ADC,
88
+ AND,
89
+ ASL,
90
+ BCC,
91
+ BCS,
92
+ BEQ,
93
+ BIT,
94
+ BMI,
95
+ BNE,
96
+ BPL,
97
+ BRK,
98
+ BVC,
99
+ BVS,
100
+ CLC,
101
+ CLD,
102
+ CLI,
103
+ CLV,
104
+ CMP,
105
+ CPX,
106
+ CPY,
107
+ DEC,
108
+ DEX,
109
+ DEY,
110
+ EOR,
111
+ INC,
112
+ INX,
113
+ INY,
114
+ JMP,
115
+ JSR,
116
+ LDA,
117
+ LDX,
118
+ LDY,
119
+ LSR,
120
+ NOP,
121
+ ORA,
122
+ PHA,
123
+ PHP,
124
+ PLA,
125
+ PLP,
126
+ ROL,
127
+ ROR,
128
+ RTI,
129
+ RTS,
130
+ SBC,
131
+ SEC,
132
+ SED,
133
+ SEI,
134
+ STA,
135
+ STX,
136
+ STY,
137
+ TAX,
138
+ TAY,
139
+ TSX,
140
+ TXA,
141
+ TXS,
142
+ TYA
143
+ }
144
+
145
+ fn instruction_name(instruction_type: InstructionTypes) -> &'static str {
146
+ match instruction_type {
147
+ InstructionTypes::INV => "inv",
148
+ InstructionTypes::ADC => "adc",
149
+ InstructionTypes::AND => "and",
150
+ InstructionTypes::ASL => "asl",
151
+ InstructionTypes::BCC => "bcc",
152
+ InstructionTypes::BCS => "bcs",
153
+ InstructionTypes::BEQ => "beq",
154
+ InstructionTypes::BIT => "bit",
155
+ InstructionTypes::BMI => "bmi",
156
+ InstructionTypes::BNE => "bne",
157
+ InstructionTypes::BPL => "bpl",
158
+ InstructionTypes::BRK => "brk",
159
+ InstructionTypes::BVC => "bvc",
160
+ InstructionTypes::BVS => "bvs",
161
+ InstructionTypes::CLC => "clc",
162
+ InstructionTypes::CLD => "cld",
163
+ InstructionTypes::CLI => "cli",
164
+ InstructionTypes::CLV => "clv",
165
+ InstructionTypes::CMP => "cmp",
166
+ InstructionTypes::CPX => "cpx",
167
+ InstructionTypes::CPY => "cpy",
168
+ InstructionTypes::DEC => "dec",
169
+ InstructionTypes::DEX => "dex",
170
+ InstructionTypes::DEY => "dey",
171
+ InstructionTypes::EOR => "eor",
172
+ InstructionTypes::INC => "inc",
173
+ InstructionTypes::INX => "inx",
174
+ InstructionTypes::INY => "iny",
175
+ InstructionTypes::JMP => "jmp",
176
+ InstructionTypes::JSR => "jsr",
177
+ InstructionTypes::LDA => "lda",
178
+ InstructionTypes::LDX => "ldx",
179
+ InstructionTypes::LDY => "ldy",
180
+ InstructionTypes::LSR => "lsr",
181
+ InstructionTypes::NOP => "nop",
182
+ InstructionTypes::ORA => "qra",
183
+ InstructionTypes::PHA => "pha",
184
+ InstructionTypes::PHP => "php",
185
+ InstructionTypes::PLA => "pla",
186
+ InstructionTypes::PLP => "plp",
187
+ InstructionTypes::ROL => "rol",
188
+ InstructionTypes::ROR => "ror",
189
+ InstructionTypes::RTI => "rti",
190
+ InstructionTypes::RTS => "rts",
191
+ InstructionTypes::SBC => "sbc",
192
+ InstructionTypes::SEC => "sec",
193
+ InstructionTypes::SED => "sed",
194
+ InstructionTypes::SEI => "sei",
195
+ InstructionTypes::STA => "sta",
196
+ InstructionTypes::STX => "stx",
197
+ InstructionTypes::STY => "sty",
198
+ InstructionTypes::TAX => "tax",
199
+ InstructionTypes::TAY => "tay",
200
+ InstructionTypes::TSX => "tsx",
201
+ InstructionTypes::TXA => "txa",
202
+ InstructionTypes::TXS => "txs",
203
+ InstructionTypes::TYA => "tya"
204
+ }
205
+ }
206
+
207
+ enum AddressingModes {
208
+ Immediate,
209
+ Absolute,
210
+ IndexedAbsoluteX,
211
+ IndexedAbsoluteY,
212
+ ZeroPage,
213
+ IndexedZeroPageX,
214
+ IndexedZeroPageY,
215
+ Implied,
216
+ Accumulator,
217
+ Indirect,
218
+ IndexedIndirectX,
219
+ IndexedIndirectY,
220
+ Relative
221
+ }
222
+
223
+ struct Operation {
224
+ instruction_type: InstructionTypes,
225
+ cycle: u8,
226
+ addressing_mode: AddressingModes
227
+ }
228
+
229
+ // @TODO: Replace with static array?
230
+ fn operation(opc: u8) -> Operation {
231
+ match opc {
232
+ 0x00 => Operation {
233
+ instruction_type: InstructionTypes::BRK,
234
+ cycle: 7,
235
+ addressing_mode: AddressingModes::Implied
236
+ },
237
+ 0x01 => Operation {
238
+ instruction_type: InstructionTypes::ORA,
239
+ cycle: 6,
240
+ addressing_mode: AddressingModes::IndexedIndirectX
241
+ },
242
+ // 0x02 => invalid
243
+ // 0x03 => invalid
244
+ // 0x04 => invalid
245
+ 0x05 => Operation {
246
+ instruction_type: InstructionTypes::ORA,
247
+ cycle: 3,
248
+ addressing_mode: AddressingModes::ZeroPage
249
+ },
250
+ 0x06 => Operation {
251
+ instruction_type: InstructionTypes::ASL,
252
+ cycle: 5,
253
+ addressing_mode: AddressingModes::ZeroPage
254
+ },
255
+ // 0x07 => invalid
256
+ 0x08 => Operation {
257
+ instruction_type: InstructionTypes::PHP,
258
+ cycle: 3,
259
+ addressing_mode: AddressingModes::Implied
260
+ },
261
+ 0x09 => Operation {
262
+ instruction_type: InstructionTypes::ORA,
263
+ cycle: 2,
264
+ addressing_mode: AddressingModes::Immediate
265
+ },
266
+ 0x0A => Operation {
267
+ instruction_type: InstructionTypes::ASL,
268
+ cycle: 2,
269
+ addressing_mode: AddressingModes::Accumulator
270
+ },
271
+ // 0x0B => invalid
272
+ // 0x0C => invalid
273
+ 0x0D => Operation {
274
+ instruction_type: InstructionTypes::ORA,
275
+ cycle: 4,
276
+ addressing_mode: AddressingModes::Absolute
277
+ },
278
+ 0x0E => Operation {
279
+ instruction_type: InstructionTypes::ASL,
280
+ cycle: 6,
281
+ addressing_mode: AddressingModes::Absolute
282
+ },
283
+ // 0x0F => invalid
284
+ 0x10 => Operation {
285
+ instruction_type: InstructionTypes::BPL,
286
+ cycle: 2, // +1 if branch succeeds, +2 if to a new page
287
+ addressing_mode: AddressingModes::Relative
288
+ },
289
+ 0x11 => Operation {
290
+ instruction_type: InstructionTypes::ORA,
291
+ cycle: 5, // +1 if page crossed
292
+ addressing_mode: AddressingModes::IndexedIndirectY
293
+ },
294
+ // 0x12 => invalid
295
+ // 0x13 => invalid
296
+ // 0x14 => invalid
297
+ 0x15 => Operation {
298
+ instruction_type: InstructionTypes::ORA,
299
+ cycle: 4,
300
+ addressing_mode: AddressingModes::IndexedZeroPageX
301
+ },
302
+ 0x16 => Operation {
303
+ instruction_type: InstructionTypes::ASL,
304
+ cycle: 6,
305
+ addressing_mode: AddressingModes::IndexedZeroPageX
306
+ },
307
+ // 0x17 => invalid
308
+ 0x18 => Operation {
309
+ instruction_type: InstructionTypes::CLC,
310
+ cycle: 2,
311
+ addressing_mode: AddressingModes::Implied
312
+ },
313
+ 0x19 => Operation {
314
+ instruction_type: InstructionTypes::ORA,
315
+ cycle: 4, // +1 if page crossed
316
+ addressing_mode: AddressingModes::IndexedAbsoluteY
317
+ },
318
+ // 0x1A => invalid
319
+ // 0x1B => invalid
320
+ // 0x1C => invalid
321
+ 0x1D => Operation {
322
+ instruction_type: InstructionTypes::ORA,
323
+ cycle: 4, // +1 if page crossed
324
+ addressing_mode: AddressingModes::IndexedAbsoluteX
325
+ },
326
+ 0x1E => Operation {
327
+ instruction_type: InstructionTypes::ASL,
328
+ cycle: 7,
329
+ addressing_mode: AddressingModes::IndexedAbsoluteX
330
+ },
331
+ // 0x1F => invalid
332
+ 0x20 => Operation {
333
+ instruction_type: InstructionTypes::JSR,
334
+ cycle: 6,
335
+ addressing_mode: AddressingModes::Absolute
336
+ },
337
+ 0x21 => Operation {
338
+ instruction_type: InstructionTypes::AND,
339
+ cycle: 6,
340
+ addressing_mode: AddressingModes::IndexedIndirectX
341
+ },
342
+ // 0x22 => invalid
343
+ // 0x23 => invalid
344
+ 0x24 => Operation {
345
+ instruction_type: InstructionTypes::BIT,
346
+ cycle: 3,
347
+ addressing_mode: AddressingModes::ZeroPage
348
+ },
349
+ 0x25 => Operation {
350
+ instruction_type: InstructionTypes::AND,
351
+ cycle: 3,
352
+ addressing_mode: AddressingModes::ZeroPage
353
+ },
354
+ 0x26 => Operation {
355
+ instruction_type: InstructionTypes::ROL,
356
+ cycle: 5,
357
+ addressing_mode: AddressingModes::ZeroPage
358
+ },
359
+ // 0x27 => invalid
360
+ 0x28 => Operation {
361
+ instruction_type: InstructionTypes::PLP,
362
+ cycle: 4,
363
+ addressing_mode: AddressingModes::Implied
364
+ },
365
+ 0x29 => Operation {
366
+ instruction_type: InstructionTypes::AND,
367
+ cycle: 2,
368
+ addressing_mode: AddressingModes::Immediate
369
+ },
370
+ 0x2A => Operation {
371
+ instruction_type: InstructionTypes::ROL,
372
+ cycle: 2,
373
+ addressing_mode: AddressingModes::Accumulator
374
+ },
375
+ // 0x2B => invalid
376
+ 0x2C => Operation {
377
+ instruction_type: InstructionTypes::BIT,
378
+ cycle: 4,
379
+ addressing_mode: AddressingModes::Absolute
380
+ },
381
+ 0x2D => Operation {
382
+ instruction_type: InstructionTypes::AND,
383
+ cycle: 4,
384
+ addressing_mode: AddressingModes::Absolute
385
+ },
386
+ 0x2E => Operation {
387
+ instruction_type: InstructionTypes::ROL,
388
+ cycle: 6,
389
+ addressing_mode: AddressingModes::Absolute
390
+ },
391
+ // 0x2F => invalid
392
+ 0x30 => Operation {
393
+ instruction_type: InstructionTypes::BMI,
394
+ cycle: 2, // +1 if branch succeeds, +2 if to a new page
395
+ addressing_mode: AddressingModes::Relative
396
+ },
397
+ 0x31 => Operation {
398
+ instruction_type: InstructionTypes::AND,
399
+ cycle: 5, // +1 if page crossed
400
+ addressing_mode: AddressingModes::IndexedIndirectY
401
+ },
402
+ // 0x32 => invalid
403
+ // 0x33 => invalid
404
+ // 0x34 => invalid
405
+ 0x35 => Operation {
406
+ instruction_type: InstructionTypes::AND,
407
+ cycle: 4,
408
+ addressing_mode: AddressingModes::IndexedZeroPageX
409
+ },
410
+ 0x36 => Operation {
411
+ instruction_type: InstructionTypes::ROL,
412
+ cycle: 6,
413
+ addressing_mode: AddressingModes::IndexedZeroPageX
414
+ },
415
+ // 0x37 => invalid
416
+ 0x38 => Operation {
417
+ instruction_type: InstructionTypes::SEC,
418
+ cycle: 2,
419
+ addressing_mode: AddressingModes::Implied
420
+ },
421
+ 0x39 => Operation {
422
+ instruction_type: InstructionTypes::AND,
423
+ cycle: 4, // +1 if page crossed
424
+ addressing_mode: AddressingModes::IndexedAbsoluteY
425
+ },
426
+ // 0x3A => invalid
427
+ // 0x3B => invalid
428
+ // 0x3C => invalid
429
+ 0x3D => Operation {
430
+ instruction_type: InstructionTypes::AND,
431
+ cycle: 4, // +1 if page crossed
432
+ addressing_mode: AddressingModes::IndexedAbsoluteX
433
+ },
434
+ 0x3E => Operation {
435
+ instruction_type: InstructionTypes::ROL,
436
+ cycle: 7,
437
+ addressing_mode: AddressingModes::IndexedAbsoluteX
438
+ },
439
+ // 0x3F => invalid
440
+ 0x40 => Operation {
441
+ instruction_type: InstructionTypes::RTI,
442
+ cycle: 6,
443
+ addressing_mode: AddressingModes::Implied
444
+ },
445
+ 0x41 => Operation {
446
+ instruction_type: InstructionTypes::EOR,
447
+ cycle: 6,
448
+ addressing_mode: AddressingModes::IndexedIndirectX
449
+ },
450
+ // 0x42 => invalid
451
+ // 0x43 => invalid
452
+ // 0x44 => invalid
453
+ 0x45 => Operation {
454
+ instruction_type: InstructionTypes::EOR,
455
+ cycle: 3,
456
+ addressing_mode: AddressingModes::ZeroPage
457
+ },
458
+ 0x46 => Operation {
459
+ instruction_type: InstructionTypes::LSR,
460
+ cycle: 5,
461
+ addressing_mode: AddressingModes::ZeroPage
462
+ },
463
+ // 0x47 => invalid
464
+ 0x48 => Operation {
465
+ instruction_type: InstructionTypes::PHA,
466
+ cycle: 3,
467
+ addressing_mode: AddressingModes::Implied
468
+ },
469
+ 0x49 => Operation {
470
+ instruction_type: InstructionTypes::EOR,
471
+ cycle: 2,
472
+ addressing_mode: AddressingModes::Immediate
473
+ },
474
+ 0x4A => Operation {
475
+ instruction_type: InstructionTypes::LSR,
476
+ cycle: 2,
477
+ addressing_mode: AddressingModes::Accumulator
478
+ },
479
+ // 0x4B => invalid
480
+ 0x4C => Operation {
481
+ instruction_type: InstructionTypes::JMP,
482
+ cycle: 3,
483
+ addressing_mode: AddressingModes::Absolute
484
+ },
485
+ 0x4D => Operation {
486
+ instruction_type: InstructionTypes::EOR,
487
+ cycle: 4,
488
+ addressing_mode: AddressingModes::Absolute
489
+ },
490
+ 0x4E => Operation {
491
+ instruction_type: InstructionTypes::LSR,
492
+ cycle: 6,
493
+ addressing_mode: AddressingModes::Absolute
494
+ },
495
+ // 0x4F => invalid
496
+ 0x50 => Operation {
497
+ instruction_type: InstructionTypes::BVC,
498
+ cycle: 2, // +1 if branch succeeds, +2 if to a new page
499
+ addressing_mode: AddressingModes::Relative
500
+ },
501
+ 0x51 => Operation {
502
+ instruction_type: InstructionTypes::EOR,
503
+ cycle: 5, // +1 if page crossed
504
+ addressing_mode: AddressingModes::IndexedIndirectY
505
+ },
506
+ // 0x52 => invalid
507
+ // 0x53 => invalid
508
+ // 0x54 => invalid
509
+ 0x55 => Operation {
510
+ instruction_type: InstructionTypes::EOR,
511
+ cycle: 4,
512
+ addressing_mode: AddressingModes::IndexedZeroPageX
513
+ },
514
+ 0x56 => Operation {
515
+ instruction_type: InstructionTypes::LSR,
516
+ cycle: 6,
517
+ addressing_mode: AddressingModes::IndexedZeroPageX
518
+ },
519
+ // 0x57 => invalid
520
+ 0x58 => Operation {
521
+ instruction_type: InstructionTypes::CLI,
522
+ cycle: 2,
523
+ addressing_mode: AddressingModes::Implied
524
+ },
525
+ 0x59 => Operation {
526
+ instruction_type: InstructionTypes::EOR,
527
+ cycle: 4, // +1 if page crossed
528
+ addressing_mode: AddressingModes::IndexedAbsoluteY
529
+ },
530
+ // 0x5A => invalid
531
+ // 0x5B => invalid
532
+ // 0x5C => invalid
533
+ 0x5D => Operation {
534
+ instruction_type: InstructionTypes::EOR,
535
+ cycle: 4, // +1 if page crossed
536
+ addressing_mode: AddressingModes::IndexedAbsoluteX
537
+ },
538
+ 0x5E => Operation {
539
+ instruction_type: InstructionTypes::LSR,
540
+ cycle: 7,
541
+ addressing_mode: AddressingModes::IndexedAbsoluteX
542
+ },
543
+ // 0x5F => invalid
544
+ 0x60 => Operation {
545
+ instruction_type: InstructionTypes::RTS,
546
+ cycle: 6,
547
+ addressing_mode: AddressingModes::Implied
548
+ },
549
+ 0x61 => Operation {
550
+ instruction_type: InstructionTypes::ADC,
551
+ cycle: 6,
552
+ addressing_mode: AddressingModes::IndexedIndirectX
553
+ },
554
+ // 0x62 => invalid
555
+ // 0x63 => invalid
556
+ // 0x64 => invalid
557
+ 0x65 => Operation {
558
+ instruction_type: InstructionTypes::ADC,
559
+ cycle: 3,
560
+ addressing_mode: AddressingModes::ZeroPage
561
+ },
562
+ 0x66 => Operation {
563
+ instruction_type: InstructionTypes::ROR,
564
+ cycle: 5,
565
+ addressing_mode: AddressingModes::ZeroPage
566
+ },
567
+ // 0x67 => invalid
568
+ 0x68 => Operation {
569
+ instruction_type: InstructionTypes::PLA,
570
+ cycle: 4,
571
+ addressing_mode: AddressingModes::Implied
572
+ },
573
+ 0x69 => Operation {
574
+ instruction_type: InstructionTypes::ADC,
575
+ cycle: 2,
576
+ addressing_mode: AddressingModes::Immediate
577
+ },
578
+ 0x6A => Operation {
579
+ instruction_type: InstructionTypes::ROR,
580
+ cycle: 2,
581
+ addressing_mode: AddressingModes::Accumulator
582
+ },
583
+ // 0x6B => invalid
584
+ 0x6C => Operation {
585
+ instruction_type: InstructionTypes::JMP,
586
+ cycle: 5,
587
+ addressing_mode: AddressingModes::Indirect
588
+ },
589
+ 0x6D => Operation {
590
+ instruction_type: InstructionTypes::ADC,
591
+ cycle: 4,
592
+ addressing_mode: AddressingModes::Absolute
593
+ },
594
+ 0x6E => Operation {
595
+ instruction_type: InstructionTypes::ROR,
596
+ cycle: 6,
597
+ addressing_mode: AddressingModes::Absolute
598
+ },
599
+ // 0x6F => invalid
600
+ 0x70 => Operation {
601
+ instruction_type: InstructionTypes::BVS,
602
+ cycle: 2, // +1 if branch succeeds, +2 if to a new page
603
+ addressing_mode: AddressingModes::Relative
604
+ },
605
+ 0x71 => Operation {
606
+ instruction_type: InstructionTypes::ADC,
607
+ cycle: 5, // @TODO +1 if page crossed
608
+ addressing_mode: AddressingModes::IndexedIndirectY
609
+ },
610
+ // 0x72 => invalid
611
+ // 0x73 => invalid
612
+ // 0x74 => invalid
613
+ 0x75 => Operation {
614
+ instruction_type: InstructionTypes::ADC,
615
+ cycle: 4,
616
+ addressing_mode: AddressingModes::IndexedZeroPageX
617
+ },
618
+ 0x76 => Operation {
619
+ instruction_type: InstructionTypes::ROR,
620
+ cycle: 6,
621
+ addressing_mode: AddressingModes::IndexedZeroPageX
622
+ },
623
+ // 0x77 => invalid
624
+ 0x78 => Operation {
625
+ instruction_type: InstructionTypes::SEI,
626
+ cycle: 2,
627
+ addressing_mode: AddressingModes::Implied
628
+ },
629
+ 0x79 => Operation {
630
+ instruction_type: InstructionTypes::ADC,
631
+ cycle: 4, // +1 if page crossed
632
+ addressing_mode: AddressingModes::IndexedAbsoluteY
633
+ },
634
+ // 0x7A => invalid
635
+ // 0x7B => invalid
636
+ // 0x7C => invalid
637
+ 0x7D => Operation {
638
+ instruction_type: InstructionTypes::ADC,
639
+ cycle: 4, // +1 if page crossed
640
+ addressing_mode: AddressingModes::IndexedAbsoluteX
641
+ },
642
+ 0x7E => Operation {
643
+ instruction_type: InstructionTypes::ROR,
644
+ cycle: 7,
645
+ addressing_mode: AddressingModes::IndexedAbsoluteX
646
+ },
647
+ // 0x7F => invalid
648
+ // 0x80 => invalid
649
+ 0x81 => Operation {
650
+ instruction_type: InstructionTypes::STA,
651
+ cycle: 6,
652
+ addressing_mode: AddressingModes::IndexedIndirectX
653
+ },
654
+ // 0x82 => invalid
655
+ // 0x83 => invalid
656
+ 0x84 => Operation {
657
+ instruction_type: InstructionTypes::STY,
658
+ cycle: 3,
659
+ addressing_mode: AddressingModes::ZeroPage
660
+ },
661
+ 0x85 => Operation {
662
+ instruction_type: InstructionTypes::STA,
663
+ cycle: 3,
664
+ addressing_mode: AddressingModes::ZeroPage
665
+ },
666
+ 0x86 => Operation {
667
+ instruction_type: InstructionTypes::STX,
668
+ cycle: 3,
669
+ addressing_mode: AddressingModes::ZeroPage
670
+ },
671
+ // 0x87 => invalid
672
+ 0x88 => Operation {
673
+ instruction_type: InstructionTypes::DEY,
674
+ cycle: 2,
675
+ addressing_mode: AddressingModes::Implied
676
+ },
677
+ // 0x89 => invalid
678
+ 0x8A => Operation {
679
+ instruction_type: InstructionTypes::TXA,
680
+ cycle: 2,
681
+ addressing_mode: AddressingModes::Implied
682
+ },
683
+ // 0x8B => invalid
684
+ 0x8C => Operation {
685
+ instruction_type: InstructionTypes::STY,
686
+ cycle: 4,
687
+ addressing_mode: AddressingModes::Absolute
688
+ },
689
+ 0x8D => Operation {
690
+ instruction_type: InstructionTypes::STA,
691
+ cycle: 4,
692
+ addressing_mode: AddressingModes::Absolute
693
+ },
694
+ 0x8E => Operation {
695
+ instruction_type: InstructionTypes::STX,
696
+ cycle: 4,
697
+ addressing_mode: AddressingModes::Absolute
698
+ },
699
+ // 0x8F => invalid
700
+ 0x90 => Operation {
701
+ instruction_type: InstructionTypes::BCC,
702
+ cycle: 2, // +1 if branch suceeds, +2 if to a new page
703
+ addressing_mode: AddressingModes::Relative
704
+ },
705
+ 0x91 => Operation {
706
+ instruction_type: InstructionTypes::STA,
707
+ cycle: 6,
708
+ addressing_mode: AddressingModes::IndexedIndirectY
709
+ },
710
+ // 0x92 => invalid
711
+ // 0x93 => invalid
712
+ 0x94 => Operation {
713
+ instruction_type: InstructionTypes::STY,
714
+ cycle: 4,
715
+ addressing_mode: AddressingModes::IndexedZeroPageX
716
+ },
717
+ 0x95 => Operation {
718
+ instruction_type: InstructionTypes::STA,
719
+ cycle: 4,
720
+ addressing_mode: AddressingModes::IndexedZeroPageX
721
+ },
722
+ 0x96 => Operation {
723
+ instruction_type: InstructionTypes::STX,
724
+ cycle: 4,
725
+ addressing_mode: AddressingModes::IndexedZeroPageY
726
+ },
727
+ // 0x97 => invalid
728
+ 0x98 => Operation {
729
+ instruction_type: InstructionTypes::TYA,
730
+ cycle: 2,
731
+ addressing_mode: AddressingModes::Implied
732
+ },
733
+ 0x99 => Operation {
734
+ instruction_type: InstructionTypes::STA,
735
+ cycle: 5,
736
+ addressing_mode: AddressingModes::IndexedAbsoluteY
737
+ },
738
+ 0x9A => Operation {
739
+ instruction_type: InstructionTypes::TXS,
740
+ cycle: 2,
741
+ addressing_mode: AddressingModes::Implied
742
+ },
743
+ // 0x9B => invalid
744
+ // 0x9C => invalid
745
+ 0x9D => Operation {
746
+ instruction_type: InstructionTypes::STA,
747
+ cycle: 5,
748
+ addressing_mode: AddressingModes::IndexedAbsoluteX
749
+ },
750
+ // 0x9E => invalid
751
+ // 0x9F => invalid
752
+ 0xA0 => Operation {
753
+ instruction_type: InstructionTypes::LDY,
754
+ cycle: 2,
755
+ addressing_mode: AddressingModes::Immediate
756
+ },
757
+ 0xA1 => Operation {
758
+ instruction_type: InstructionTypes::LDA,
759
+ cycle: 6,
760
+ addressing_mode: AddressingModes::IndexedIndirectX
761
+ },
762
+ 0xA2 => Operation {
763
+ instruction_type: InstructionTypes::LDX,
764
+ cycle: 2,
765
+ addressing_mode: AddressingModes::Immediate
766
+ },
767
+ // 0xA3 => invalid
768
+ 0xA4 => Operation {
769
+ instruction_type: InstructionTypes::LDY,
770
+ cycle: 3,
771
+ addressing_mode: AddressingModes::ZeroPage
772
+ },
773
+ 0xA5 => Operation {
774
+ instruction_type: InstructionTypes::LDA,
775
+ cycle: 3,
776
+ addressing_mode: AddressingModes::ZeroPage
777
+ },
778
+ 0xA6 => Operation {
779
+ instruction_type: InstructionTypes::LDX,
780
+ cycle: 3,
781
+ addressing_mode: AddressingModes::ZeroPage
782
+ },
783
+ // 0xA7 => invalid
784
+ 0xA8 => Operation {
785
+ instruction_type: InstructionTypes::TAY,
786
+ cycle: 2,
787
+ addressing_mode: AddressingModes::Implied
788
+ },
789
+ 0xA9 => Operation {
790
+ instruction_type: InstructionTypes::LDA,
791
+ cycle: 2,
792
+ addressing_mode: AddressingModes::Immediate
793
+ },
794
+ 0xAA => Operation {
795
+ instruction_type: InstructionTypes::TAX,
796
+ cycle: 2,
797
+ addressing_mode: AddressingModes::Implied
798
+ },
799
+ // 0xAB => invalid
800
+ 0xAC => Operation {
801
+ instruction_type: InstructionTypes::LDY,
802
+ cycle: 4,
803
+ addressing_mode: AddressingModes::Absolute
804
+ },
805
+ 0xAD => Operation {
806
+ instruction_type: InstructionTypes::LDA,
807
+ cycle: 4,
808
+ addressing_mode: AddressingModes::Absolute
809
+ },
810
+ 0xAE => Operation {
811
+ instruction_type: InstructionTypes::LDX,
812
+ cycle: 4,
813
+ addressing_mode: AddressingModes::Absolute
814
+ },
815
+ // 0xAF => invalid
816
+ 0xB0 => Operation {
817
+ instruction_type: InstructionTypes::BCS,
818
+ cycle: 2, // +1 if branch succeeds, +2 if to a new page
819
+ addressing_mode: AddressingModes::Relative
820
+ },
821
+ 0xB1 => Operation {
822
+ instruction_type: InstructionTypes::LDA,
823
+ cycle: 5, // +1 if page crossed
824
+ addressing_mode: AddressingModes::IndexedIndirectY
825
+ },
826
+ // 0xB2 => invalid
827
+ // 0xB3 => invalid
828
+ 0xB4 => Operation {
829
+ instruction_type: InstructionTypes::LDY,
830
+ cycle: 4,
831
+ addressing_mode: AddressingModes::IndexedZeroPageX
832
+ },
833
+ 0xB5 => Operation {
834
+ instruction_type: InstructionTypes::LDA,
835
+ cycle: 4,
836
+ addressing_mode: AddressingModes::IndexedZeroPageX
837
+ },
838
+ 0xB6 => Operation {
839
+ instruction_type: InstructionTypes::LDX,
840
+ cycle: 4,
841
+ addressing_mode: AddressingModes::IndexedZeroPageY
842
+ },
843
+ // 0xB7 => invalid
844
+ 0xB8 => Operation {
845
+ instruction_type: InstructionTypes::CLV,
846
+ cycle: 2,
847
+ addressing_mode: AddressingModes::Implied
848
+ },
849
+ 0xB9 => Operation {
850
+ instruction_type: InstructionTypes::LDA,
851
+ cycle: 4, // +1 if page crossed
852
+ addressing_mode: AddressingModes::IndexedAbsoluteY
853
+ },
854
+ 0xBA => Operation {
855
+ instruction_type: InstructionTypes::TSX,
856
+ cycle: 2,
857
+ addressing_mode: AddressingModes::Implied
858
+ },
859
+ // 0xBB => invalid
860
+ 0xBC => Operation {
861
+ instruction_type: InstructionTypes::LDY,
862
+ cycle: 4, // +1 if page crossed
863
+ addressing_mode: AddressingModes::IndexedAbsoluteX
864
+ },
865
+ 0xBD => Operation {
866
+ instruction_type: InstructionTypes::LDA,
867
+ cycle: 4, // +1 if page crossed
868
+ addressing_mode: AddressingModes::IndexedAbsoluteX
869
+ },
870
+ 0xBE => Operation {
871
+ instruction_type: InstructionTypes::LDX,
872
+ cycle: 4, // +1 if page crossed
873
+ addressing_mode: AddressingModes::IndexedAbsoluteY
874
+ },
875
+ // 0xBF => invalid
876
+ 0xC0 => Operation {
877
+ instruction_type: InstructionTypes::CPY,
878
+ cycle: 2,
879
+ addressing_mode: AddressingModes::Immediate
880
+ },
881
+ 0xC1 => Operation {
882
+ instruction_type: InstructionTypes::CMP,
883
+ cycle: 6,
884
+ addressing_mode: AddressingModes::IndexedIndirectX
885
+ },
886
+ // 0xC2 => invalid
887
+ // 0xC3 => invalid
888
+ 0xC4 => Operation {
889
+ instruction_type: InstructionTypes::CPY,
890
+ cycle: 3,
891
+ addressing_mode: AddressingModes::ZeroPage
892
+ },
893
+ 0xC5 => Operation {
894
+ instruction_type: InstructionTypes::CMP,
895
+ cycle: 3,
896
+ addressing_mode: AddressingModes::ZeroPage
897
+ },
898
+ 0xC6 => Operation {
899
+ instruction_type: InstructionTypes::DEC,
900
+ cycle: 5,
901
+ addressing_mode: AddressingModes::ZeroPage
902
+ },
903
+ // 0xC7 => invalid
904
+ 0xC8 => Operation {
905
+ instruction_type: InstructionTypes::INY,
906
+ cycle: 2,
907
+ addressing_mode: AddressingModes::Implied
908
+ },
909
+ 0xC9 => Operation {
910
+ instruction_type: InstructionTypes::CMP,
911
+ cycle: 2,
912
+ addressing_mode: AddressingModes::Immediate
913
+ },
914
+ 0xCA => Operation {
915
+ instruction_type: InstructionTypes::DEX,
916
+ cycle: 2,
917
+ addressing_mode: AddressingModes::Implied
918
+ },
919
+ // 0xCB => invalid
920
+ 0xCC => Operation {
921
+ instruction_type: InstructionTypes::CPY,
922
+ cycle: 4,
923
+ addressing_mode: AddressingModes::Absolute
924
+ },
925
+ 0xCD => Operation {
926
+ instruction_type: InstructionTypes::CMP,
927
+ cycle: 4,
928
+ addressing_mode: AddressingModes::Absolute
929
+ },
930
+ 0xCE => Operation {
931
+ instruction_type: InstructionTypes::DEC,
932
+ cycle: 6,
933
+ addressing_mode: AddressingModes::Absolute
934
+ },
935
+ // 0xCF => invalid
936
+ 0xD0 => Operation {
937
+ instruction_type: InstructionTypes::BNE,
938
+ cycle: 2, // +1 if branch succeeds, +2 if to a new page
939
+ addressing_mode: AddressingModes::Relative
940
+ },
941
+ 0xD1 => Operation {
942
+ instruction_type: InstructionTypes::CMP,
943
+ cycle: 5, // +1 if page crossed
944
+ addressing_mode: AddressingModes::IndexedIndirectY
945
+ },
946
+ // 0xD2 => invalid
947
+ // 0xD3 => invalid
948
+ // 0xD4 => invalid
949
+ 0xD5 => Operation {
950
+ instruction_type: InstructionTypes::CMP,
951
+ cycle: 4,
952
+ addressing_mode: AddressingModes::IndexedZeroPageX
953
+ },
954
+ 0xD6 => Operation {
955
+ instruction_type: InstructionTypes::DEC,
956
+ cycle: 6,
957
+ addressing_mode: AddressingModes::IndexedZeroPageX
958
+ },
959
+ // 0xD7 => invalid
960
+ 0xD8 => Operation {
961
+ instruction_type: InstructionTypes::CLD,
962
+ cycle: 2,
963
+ addressing_mode: AddressingModes::Implied
964
+ },
965
+ 0xD9 => Operation {
966
+ instruction_type: InstructionTypes::CMP,
967
+ cycle: 4, // +1 if page crossed
968
+ addressing_mode: AddressingModes::IndexedAbsoluteY
969
+ },
970
+ // 0xDA => invalid
971
+ // 0xDB => invalid
972
+ // 0xDC => invalid
973
+ 0xDD => Operation {
974
+ instruction_type: InstructionTypes::CMP,
975
+ cycle: 4, // +1 if page crossed
976
+ addressing_mode: AddressingModes::IndexedAbsoluteX
977
+ },
978
+ 0xDE => Operation {
979
+ instruction_type: InstructionTypes::DEC,
980
+ cycle: 7,
981
+ addressing_mode: AddressingModes::IndexedAbsoluteX
982
+ },
983
+ // 0xDF => invalid
984
+ 0xE0 => Operation {
985
+ instruction_type: InstructionTypes::CPX,
986
+ cycle: 2,
987
+ addressing_mode: AddressingModes::Immediate
988
+ },
989
+ 0xE1 => Operation {
990
+ instruction_type: InstructionTypes::SBC,
991
+ cycle: 6,
992
+ addressing_mode: AddressingModes::IndexedIndirectX
993
+ },
994
+ // 0xE2 => invalid
995
+ // 0xE3 => invalid
996
+ 0xE4 => Operation {
997
+ instruction_type: InstructionTypes::CPX,
998
+ cycle: 3,
999
+ addressing_mode: AddressingModes::ZeroPage
1000
+ },
1001
+ 0xE5 => Operation {
1002
+ instruction_type: InstructionTypes::SBC,
1003
+ cycle: 3,
1004
+ addressing_mode: AddressingModes::ZeroPage
1005
+ },
1006
+ 0xE6 => Operation {
1007
+ instruction_type: InstructionTypes::INC,
1008
+ cycle: 5,
1009
+ addressing_mode: AddressingModes::ZeroPage
1010
+ },
1011
+ // 0xE7 => invalid
1012
+ 0xE8 => Operation {
1013
+ instruction_type: InstructionTypes::INX,
1014
+ cycle: 2,
1015
+ addressing_mode: AddressingModes::Implied
1016
+ },
1017
+ 0xE9 => Operation {
1018
+ instruction_type: InstructionTypes::SBC,
1019
+ cycle: 2,
1020
+ addressing_mode: AddressingModes::Immediate
1021
+ },
1022
+ 0xEA => Operation {
1023
+ instruction_type: InstructionTypes::NOP,
1024
+ cycle: 2,
1025
+ addressing_mode: AddressingModes::Implied
1026
+ },
1027
+ // 0xEB => invalid
1028
+ 0xEC => Operation {
1029
+ instruction_type: InstructionTypes::CPX,
1030
+ cycle: 4,
1031
+ addressing_mode: AddressingModes::Absolute
1032
+ },
1033
+ 0xED => Operation {
1034
+ instruction_type: InstructionTypes::SBC,
1035
+ cycle: 4,
1036
+ addressing_mode: AddressingModes::Absolute
1037
+ },
1038
+ 0xEE => Operation {
1039
+ instruction_type: InstructionTypes::INC,
1040
+ cycle: 6,
1041
+ addressing_mode: AddressingModes::Absolute
1042
+ },
1043
+ // 0xEF => invalid
1044
+ 0xF0 => Operation {
1045
+ instruction_type: InstructionTypes::BEQ,
1046
+ cycle: 2, // +1 if branch succeeds, +2 if to a new page
1047
+ addressing_mode: AddressingModes::Relative
1048
+ },
1049
+ 0xF1 => Operation {
1050
+ instruction_type: InstructionTypes::SBC,
1051
+ cycle: 5, // +1 if page crossed
1052
+ addressing_mode: AddressingModes::IndexedIndirectY
1053
+ },
1054
+ // 0xF2 => invalid
1055
+ // 0xF3 => invalid
1056
+ // 0xF4 => invalid
1057
+ 0xF5 => Operation {
1058
+ instruction_type: InstructionTypes::SBC,
1059
+ cycle: 4,
1060
+ addressing_mode: AddressingModes::IndexedZeroPageX
1061
+ },
1062
+ 0xF6 => Operation {
1063
+ instruction_type: InstructionTypes::INC,
1064
+ cycle: 6,
1065
+ addressing_mode: AddressingModes::IndexedZeroPageX
1066
+ },
1067
+ // 0xF7 => invalid
1068
+ 0xF8 => Operation {
1069
+ instruction_type: InstructionTypes::SED,
1070
+ cycle: 2,
1071
+ addressing_mode: AddressingModes::Implied
1072
+ },
1073
+ 0xF9 => Operation {
1074
+ instruction_type: InstructionTypes::SBC,
1075
+ cycle: 4, // +1 if page crossed
1076
+ addressing_mode: AddressingModes::IndexedAbsoluteY
1077
+ },
1078
+ // 0xFA => invalid
1079
+ // 0xFB => invalid
1080
+ // 0xFC => invalid
1081
+ 0xFD => Operation {
1082
+ instruction_type: InstructionTypes::SBC,
1083
+ cycle: 4, // +1 if page crossed
1084
+ addressing_mode: AddressingModes::IndexedAbsoluteX
1085
+ },
1086
+ 0xFE => Operation {
1087
+ instruction_type: InstructionTypes::INC,
1088
+ cycle: 7,
1089
+ addressing_mode: AddressingModes::IndexedAbsoluteX
1090
+ },
1091
+ // 0xFF => invalid
1092
+ _ => Operation {
1093
+ instruction_type: InstructionTypes::INV,
1094
+ cycle: 1,
1095
+ addressing_mode: AddressingModes::Immediate // dummy
1096
+ }
1097
+ }
1098
+ }
1099
+
1100
+ impl Cpu {
1101
+ pub fn new(input: Box<dyn Input>, display: Box<dyn Display>, audio: Box<dyn Audio>) -> Self {
1102
+ Cpu {
1103
+ pc: Register::<u16>::new(),
1104
+ sp: Register::<u8>::new(),
1105
+ a: Register::<u8>::new(),
1106
+ x: Register::<u8>::new(),
1107
+ y: Register::<u8>::new(),
1108
+ p: CpuStatusRegister::new(),
1109
+ ram: Memory::new(vec![0; 64 * 1024]), // 64KB
1110
+ sram_dirty: false,
1111
+ stall_cycles: 0,
1112
+ input: input,
1113
+ ppu: Ppu::new(display),
1114
+ apu: Apu::new(audio),
1115
+ joypad1: Joypad::new(),
1116
+ joypad2: Joypad::new(),
1117
+ rom: Rom::new(vec![0; HEADER_SIZE]) // dummy
1118
+ }
1119
+ }
1120
+
1121
+ pub fn set_rom(&mut self, rom: Rom) {
1122
+ self.rom = rom;
1123
+ self.sram_dirty = false;
1124
+ self.clear_sram();
1125
+ }
1126
+
1127
+ pub fn bootup(&mut self) {
1128
+ self.bootup_internal();
1129
+ self.ppu.bootup();
1130
+ self.apu.bootup();
1131
+ }
1132
+
1133
+ fn bootup_internal(&mut self) {
1134
+ self.p.store(0x34);
1135
+ self.a.clear();
1136
+ self.x.clear();
1137
+ self.y.clear();
1138
+ self.sp.store(0xFD);
1139
+
1140
+ for i in 0..0x10 {
1141
+ self.store(0x4000 + i, 0);
1142
+ }
1143
+
1144
+ self.store(0x4015, 0);
1145
+ self.store(0x4017, 0);
1146
+
1147
+ self.interrupt(Interrupts::RESET);
1148
+ }
1149
+
1150
+ pub fn reset(&mut self) {
1151
+ self.reset_internal();
1152
+ self.ppu.reset();
1153
+ self.apu.reset();
1154
+ self.interrupt(Interrupts::RESET);
1155
+ }
1156
+
1157
+ fn reset_internal(&mut self) {
1158
+ self.sp.sub(3);
1159
+ self.p.set_i();
1160
+ }
1161
+
1162
+ pub fn get_ppu(&self) -> &Ppu {
1163
+ &self.ppu
1164
+ }
1165
+
1166
+ pub fn get_mut_apu(&mut self) -> &mut Apu {
1167
+ &mut self.apu
1168
+ }
1169
+
1170
+ pub fn get_mut_input(&mut self) -> &mut Box<dyn Input> {
1171
+ &mut self.input
1172
+ }
1173
+
1174
+ pub fn has_battery_backed_ram(&self) -> bool {
1175
+ self.rom.has_battery_backed_ram()
1176
+ }
1177
+
1178
+ pub fn get_sram(&self) -> Vec<u8> {
1179
+ self.ram.as_slice()[SRAM_START..SRAM_END].to_vec()
1180
+ }
1181
+
1182
+ pub fn set_sram(&mut self, data: &[u8]) {
1183
+ if !self.has_battery_backed_ram() {
1184
+ return;
1185
+ }
1186
+ let slice = self.ram.as_mut_slice();
1187
+ let len = data.len().min(SRAM_SIZE);
1188
+ slice[SRAM_START..SRAM_START + len].copy_from_slice(&data[..len]);
1189
+ if len < SRAM_SIZE {
1190
+ for value in &mut slice[SRAM_START + len..SRAM_END] {
1191
+ *value = 0;
1192
+ }
1193
+ }
1194
+ self.sram_dirty = false;
1195
+ }
1196
+
1197
+ pub fn is_sram_dirty(&self) -> bool {
1198
+ self.sram_dirty
1199
+ }
1200
+
1201
+ pub fn mark_sram_saved(&mut self) {
1202
+ self.sram_dirty = false;
1203
+ }
1204
+
1205
+ fn clear_sram(&mut self) {
1206
+ let slice = self.ram.as_mut_slice();
1207
+ for value in &mut slice[SRAM_START..SRAM_END] {
1208
+ *value = 0;
1209
+ }
1210
+ }
1211
+
1212
+ //
1213
+
1214
+ pub fn step(&mut self) {
1215
+ let stall_cycles = self.step_internal();
1216
+ for _i in 0..stall_cycles * 3 {
1217
+ self.ppu.step(&mut self.rom);
1218
+ }
1219
+ for _i in 0..stall_cycles {
1220
+ // No reference to CPU from APU so detecting if APU DMC needs
1221
+ // CPU memory data, loading data, and sending to APU if needed
1222
+ // @TODO: Simplify
1223
+ let dmc_sample_data = match self.apu.dmc_needs_cpu_memory_data() {
1224
+ true => {
1225
+ // The CPU is stalled for up to 4 CPU cycles
1226
+ // @TODO: Fix me
1227
+ self.stall_cycles += 4;
1228
+ self.load(self.apu.dmc_sample_address())
1229
+ }
1230
+ false => 0
1231
+ };
1232
+ self.apu.step(dmc_sample_data);
1233
+ }
1234
+ }
1235
+
1236
+ pub fn step_frame(&mut self) {
1237
+ // Input handling should be here? Or under nes.rs?
1238
+ self.handle_inputs();
1239
+ // @TODO: More precise frame update detection?
1240
+ let ppu_frame = self.ppu.frame;
1241
+ loop {
1242
+ self.step();
1243
+ if ppu_frame != self.ppu.frame {
1244
+ break;
1245
+ }
1246
+ }
1247
+ }
1248
+
1249
+ fn handle_inputs(&mut self) {
1250
+ while let Some((button, event)) = self.input.get_input() {
1251
+ match button {
1252
+ button::Button::Poweroff => {
1253
+ // @TODO: Implement
1254
+ },
1255
+ button::Button::Reset => {
1256
+ self.reset();
1257
+ },
1258
+ button::Button::Select |
1259
+ button::Button::Start |
1260
+ button::Button::Joypad1A |
1261
+ button::Button::Joypad1B |
1262
+ button::Button::Joypad1Up |
1263
+ button::Button::Joypad1Down |
1264
+ button::Button::Joypad1Left |
1265
+ button::Button::Joypad1Right => {
1266
+ self.joypad1.handle_input(to_joypad_button(button), event);
1267
+ },
1268
+ button::Button::Joypad2A |
1269
+ button::Button::Joypad2B |
1270
+ button::Button::Joypad2Up |
1271
+ button::Button::Joypad2Down |
1272
+ button::Button::Joypad2Left |
1273
+ button::Button::Joypad2Right => {
1274
+ self.joypad2.handle_input(to_joypad_button(button), event);
1275
+ }
1276
+ }
1277
+ }
1278
+ }
1279
+
1280
+ fn step_internal(&mut self) -> u16 {
1281
+ // @TODO: What if both NMI and IRQ happen?
1282
+ if self.ppu.nmi_interrupted {
1283
+ self.ppu.nmi_interrupted = false;
1284
+ self.interrupt(Interrupts::NMI);
1285
+ }
1286
+ if self.ppu.irq_interrupted {
1287
+ self.ppu.irq_interrupted = false;
1288
+ self.interrupt(Interrupts::IRQ);
1289
+ }
1290
+ if self.apu.irq_interrupted {
1291
+ self.apu.irq_interrupted = false;
1292
+ self.interrupt(Interrupts::IRQ);
1293
+ }
1294
+
1295
+ let opc = self.fetch();
1296
+ let op = self.decode(opc);
1297
+ self.operate(&op);
1298
+ let stall_cycles = self.stall_cycles;
1299
+ self.stall_cycles = 0;
1300
+ stall_cycles + op.cycle as u16
1301
+ }
1302
+
1303
+ fn fetch(&mut self) -> u8 {
1304
+ let opc = self.load(self.pc.load());
1305
+ self.pc.increment();
1306
+ opc
1307
+ }
1308
+
1309
+ fn decode(&self, opc: u8) -> Operation {
1310
+ operation(opc)
1311
+ }
1312
+
1313
+ fn jump_to_interrupt_handler(&mut self, interrupt_type: Interrupts) {
1314
+ let address = interrupt_handler_address(interrupt_type);
1315
+ let value = self.load_2bytes(address);
1316
+ self.pc.store(value);
1317
+ }
1318
+
1319
+ fn do_branch(&mut self, op: &Operation, flag: bool) {
1320
+ let result = self.load_with_addressing_mode(&op);
1321
+ if flag {
1322
+ // stall_cycle + 1 if branch succeeds
1323
+ self.stall_cycles += 1;
1324
+ let current_page = self.pc.load() & 0xff00;
1325
+ self.pc.add(result);
1326
+ if current_page != (self.pc.load() & 0xff00) {
1327
+ // stall_cycle + 1 if across page
1328
+ self.stall_cycles += 1;
1329
+ }
1330
+ }
1331
+ }
1332
+
1333
+ // @TODO: Clean up if needed
1334
+ fn operate(&mut self, op: &Operation) {
1335
+ match op.instruction_type {
1336
+ InstructionTypes::ADC => {
1337
+ let src1 = self.a.load();
1338
+ let src2 = self.load_with_addressing_mode(&op);
1339
+ let c = match self.p.is_c() {
1340
+ true => 1,
1341
+ false => 0
1342
+ } as u16;
1343
+ let result = (src1 as u16).wrapping_add(src2).wrapping_add(c);
1344
+ self.a.store(result as u8);
1345
+ self.update_n(result);
1346
+ self.update_z(result);
1347
+ self.update_c(result);
1348
+ if !(((src1 ^ src2 as u8) & 0x80) != 0) && ((src2 as u8 ^ result as u8) & 0x80) != 0 {
1349
+ self.p.set_v();
1350
+ } else {
1351
+ self.p.clear_v();
1352
+ }
1353
+ },
1354
+ InstructionTypes::AND => {
1355
+ let src1 = self.a.load();
1356
+ let src2 = self.load_with_addressing_mode(&op);
1357
+ let result = (src1 as u16) & src2;
1358
+ self.a.store(result as u8);
1359
+ self.update_n(result);
1360
+ self.update_z(result);
1361
+ },
1362
+ InstructionTypes::ASL => {
1363
+ let result = self.update_memory_with_addressing_mode(op, |src: u8| {
1364
+ (src as u16) << 1
1365
+ });
1366
+ self.update_n(result);
1367
+ self.update_z(result);
1368
+ self.update_c(result);
1369
+ },
1370
+ InstructionTypes::BCC => {
1371
+ let flag = !self.p.is_c();
1372
+ self.do_branch(&op, flag);
1373
+ },
1374
+ InstructionTypes::BCS => {
1375
+ let flag = self.p.is_c();
1376
+ self.do_branch(&op, flag);
1377
+ },
1378
+ InstructionTypes::BEQ => {
1379
+ let flag = self.p.is_z();
1380
+ self.do_branch(&op, flag);
1381
+ },
1382
+ // @TODO: check logic
1383
+ InstructionTypes::BIT => {
1384
+ let src1 = self.a.load();
1385
+ let src2 = self.load_with_addressing_mode(&op);
1386
+ let result = (src1 as u16) & src2;
1387
+ self.update_n(src2);
1388
+ self.update_z(result);
1389
+ if (src2 & 0x40) == 0 {
1390
+ self.p.clear_v();
1391
+ } else {
1392
+ self.p.set_v();
1393
+ }
1394
+ },
1395
+ InstructionTypes::BMI => {
1396
+ let flag = self.p.is_n();
1397
+ self.do_branch(&op, flag);
1398
+ },
1399
+ InstructionTypes::BNE => {
1400
+ let flag = !self.p.is_z();
1401
+ self.do_branch(&op, flag);
1402
+ },
1403
+ InstructionTypes::BPL => {
1404
+ let flag = !self.p.is_n();
1405
+ self.do_branch(&op, flag);
1406
+ },
1407
+ InstructionTypes::BRK => {
1408
+ self.pc.increment(); // seems like necessary
1409
+ self.p.set_a();
1410
+ self.p.set_b();
1411
+ self.interrupt(Interrupts::BRK);
1412
+ },
1413
+ InstructionTypes::BVC => {
1414
+ let flag = !self.p.is_v();
1415
+ self.do_branch(&op, flag);
1416
+ },
1417
+ InstructionTypes::BVS => {
1418
+ let flag = self.p.is_v();
1419
+ self.do_branch(&op, flag);
1420
+ },
1421
+ InstructionTypes::CLC => {
1422
+ self.p.clear_c();
1423
+ },
1424
+ InstructionTypes::CLD => {
1425
+ self.p.clear_d();
1426
+ },
1427
+ InstructionTypes::CLI => {
1428
+ self.p.clear_i();
1429
+ },
1430
+ InstructionTypes::CLV => {
1431
+ self.p.clear_v();
1432
+ },
1433
+ InstructionTypes::CMP | InstructionTypes::CPX | InstructionTypes::CPY => {
1434
+ let src1 = match op.instruction_type {
1435
+ InstructionTypes::CMP => {
1436
+ self.a.load()
1437
+ },
1438
+ InstructionTypes::CPX => {
1439
+ self.x.load()
1440
+ },
1441
+ _ => { //InstructionTypes::CPY
1442
+ self.y.load()
1443
+ }
1444
+ };
1445
+ let src2 = self.load_with_addressing_mode(&op);
1446
+ let result = (src1 as u16).wrapping_sub(src2);
1447
+ self.update_n(result);
1448
+ self.update_z(result);
1449
+ if src1 as u16 >= src2 {
1450
+ self.p.set_c();
1451
+ } else {
1452
+ self.p.clear_c();
1453
+ }
1454
+ },
1455
+ InstructionTypes::DEC => {
1456
+ let result = self.update_memory_with_addressing_mode(op, |src: u8| {
1457
+ (src as u16).wrapping_sub(1)
1458
+ });
1459
+ self.update_n(result);
1460
+ self.update_z(result);
1461
+ },
1462
+ InstructionTypes::DEX | InstructionTypes::DEY => {
1463
+ let result = match op.instruction_type {
1464
+ InstructionTypes::DEX => {
1465
+ let src = self.x.load();
1466
+ let result = (src as u16).wrapping_sub(1);
1467
+ self.x.store(result as u8);
1468
+ result
1469
+ },
1470
+ _ => { // InstructionTypes::DEY
1471
+ let src = self.y.load();
1472
+ let result = (src as u16).wrapping_sub(1);
1473
+ self.y.store(result as u8);
1474
+ result
1475
+ }
1476
+ };
1477
+ self.update_n(result);
1478
+ self.update_z(result);
1479
+ },
1480
+ InstructionTypes::EOR => {
1481
+ let src1 = self.a.load();
1482
+ let src2 = self.load_with_addressing_mode(&op);
1483
+ let result = (src1 as u16) ^ src2;
1484
+ self.a.store(result as u8);
1485
+ self.update_n(result);
1486
+ self.update_z(result);
1487
+ },
1488
+ InstructionTypes::INC => {
1489
+ let result = self.update_memory_with_addressing_mode(op, |src: u8| {
1490
+ (src as u16).wrapping_add(1)
1491
+ });
1492
+ self.update_n(result);
1493
+ self.update_z(result);
1494
+ },
1495
+ InstructionTypes::INV => {
1496
+ // @TODO: Throw?
1497
+ println!("INV operation");
1498
+ },
1499
+ InstructionTypes::INX | InstructionTypes::INY => {
1500
+ let result = match op.instruction_type {
1501
+ InstructionTypes::INX => {
1502
+ let src = self.x.load();
1503
+ let result = (src as u16).wrapping_add(1);
1504
+ self.x.store(result as u8);
1505
+ result
1506
+ },
1507
+ _ => { // InstructionTypes::INY
1508
+ let src = self.y.load();
1509
+ let result = (src as u16).wrapping_add(1);
1510
+ self.y.store(result as u8);
1511
+ result
1512
+ }
1513
+ };
1514
+ self.update_n(result);
1515
+ self.update_z(result);
1516
+ },
1517
+ // TODO: check the logic.
1518
+ InstructionTypes::JMP => {
1519
+ let address = self.get_address_with_addressing_mode(op);
1520
+ self.pc.store(address);
1521
+ },
1522
+ // TODO: check the logic.
1523
+ InstructionTypes::JSR => {
1524
+ let address = self.get_address_with_addressing_mode(op);
1525
+ self.pc.decrement();
1526
+ let value = self.pc.load();
1527
+ self.push_stack_2bytes(value);
1528
+ self.pc.store(address);
1529
+ },
1530
+ InstructionTypes::LDA | InstructionTypes::LDX | InstructionTypes::LDY => {
1531
+ let result = match op.instruction_type {
1532
+ InstructionTypes::LDA => {
1533
+ let result = self.load_with_addressing_mode(&op);
1534
+ self.a.store(result as u8);
1535
+ result
1536
+ },
1537
+ InstructionTypes::LDX => {
1538
+ let result = self.load_with_addressing_mode(&op);
1539
+ self.x.store(result as u8);
1540
+ result
1541
+ },
1542
+ _ /*InstructionTypes::LDY*/ => {
1543
+ let result = self.load_with_addressing_mode(&op);
1544
+ self.y.store(result as u8);
1545
+ result
1546
+ }
1547
+ };
1548
+ self.update_n(result);
1549
+ self.update_z(result);
1550
+ },
1551
+ InstructionTypes::LSR => {
1552
+ let result = match op.addressing_mode {
1553
+ AddressingModes::Accumulator => {
1554
+ let src = self.a.load();
1555
+ if (src & 1) == 0 {
1556
+ self.p.clear_c();
1557
+ } else {
1558
+ self.p.set_c();
1559
+ }
1560
+ let result = (src as u16) >> 1;
1561
+ self.a.store(result as u8);
1562
+ result
1563
+ },
1564
+ _ => {
1565
+ let address = self.get_address_with_addressing_mode(op);
1566
+ let src = self.load(address);
1567
+ if (src & 1) == 0 {
1568
+ self.p.clear_c();
1569
+ } else {
1570
+ self.p.set_c();
1571
+ }
1572
+ let result = (src as u16) >> 1;
1573
+ self.store(address, result as u8);
1574
+ result
1575
+ }
1576
+ };
1577
+ self.p.clear_n();
1578
+ self.update_z(result);
1579
+ },
1580
+ InstructionTypes::NOP => {},
1581
+ InstructionTypes::ORA => {
1582
+ let src1 = self.a.load();
1583
+ let src2 = self.load_with_addressing_mode(op);
1584
+ let result = (src1 as u16) | src2;
1585
+ self.a.store(result as u8);
1586
+ self.update_n(result);
1587
+ self.update_z(result);
1588
+ },
1589
+ InstructionTypes::PHA => {
1590
+ let value = self.a.load();
1591
+ self.push_stack(value);
1592
+ },
1593
+ InstructionTypes::PHP => {
1594
+ self.p.set_a();
1595
+ self.p.set_b();
1596
+ let value = self.p.load();
1597
+ self.push_stack(value);
1598
+ },
1599
+ InstructionTypes::PLA => {
1600
+ let result = self.pop_stack() as u16;
1601
+ self.a.store(result as u8);
1602
+ self.update_n(result);
1603
+ self.update_z(result);
1604
+ },
1605
+ InstructionTypes::PLP => {
1606
+ let value = self.pop_stack();
1607
+ self.p.store(value);
1608
+ },
1609
+ InstructionTypes::ROL => {
1610
+ let result = match op.addressing_mode {
1611
+ AddressingModes::Accumulator => {
1612
+ let src = self.a.load();
1613
+ let c = match self.p.is_c() {
1614
+ true => 1,
1615
+ false => 0
1616
+ } as u16;
1617
+ let result = ((src as u16) << 1) | c;
1618
+ self.a.store(result as u8);
1619
+ result
1620
+ },
1621
+ _ => {
1622
+ let address = self.get_address_with_addressing_mode(op);
1623
+ let src = self.load(address);
1624
+ let c = match self.p.is_c() {
1625
+ true => 1,
1626
+ false => 0
1627
+ } as u16;
1628
+ let result = ((src as u16) << 1) | c;
1629
+ self.store(address, result as u8);
1630
+ result
1631
+ }
1632
+ };
1633
+ self.update_n(result);
1634
+ self.update_z(result);
1635
+ self.update_c(result);
1636
+ },
1637
+ InstructionTypes::ROR => {
1638
+ let result = match op.addressing_mode {
1639
+ AddressingModes::Accumulator => {
1640
+ let src = self.a.load();
1641
+ let c = match self.p.is_c() {
1642
+ true => 0x80,
1643
+ false => 0
1644
+ } as u16;
1645
+ let result = ((src as u16) >> 1) | c;
1646
+ self.a.store(result as u8);
1647
+ if (src & 1) == 0 {
1648
+ self.p.clear_c();
1649
+ } else {
1650
+ self.p.set_c();
1651
+ }
1652
+ result
1653
+ },
1654
+ _ => {
1655
+ let address = self.get_address_with_addressing_mode(op);
1656
+ let src = self.load(address);
1657
+ let c = match self.p.is_c() {
1658
+ true => 0x80,
1659
+ false => 0
1660
+ } as u16;
1661
+ let result = ((src as u16) >> 1) | c;
1662
+ self.store(address, result as u8);
1663
+ if (src & 1) == 0 {
1664
+ self.p.clear_c();
1665
+ } else {
1666
+ self.p.set_c();
1667
+ }
1668
+ result
1669
+ }
1670
+ };
1671
+ self.update_n(result);
1672
+ self.update_z(result);
1673
+ },
1674
+ // TODO: check logic.
1675
+ InstructionTypes::RTI => {
1676
+ let value = self.pop_stack();
1677
+ self.p.store(value);
1678
+ let value2 = self.pop_stack_2bytes();
1679
+ self.pc.store(value2);
1680
+ },
1681
+ // TODO: check logic.
1682
+ InstructionTypes::RTS => {
1683
+ let value = self.pop_stack_2bytes().wrapping_add(1);
1684
+ self.pc.store(value);
1685
+ },
1686
+ InstructionTypes::SBC => {
1687
+ let src1 = self.a.load();
1688
+ let src2 = self.load_with_addressing_mode(&op);
1689
+ let c = match self.p.is_c() {
1690
+ true => 0,
1691
+ false => 1
1692
+ } as u16;
1693
+ let result = (src1 as u16).wrapping_sub(src2).wrapping_sub(c);
1694
+ self.a.store(result as u8);
1695
+ self.update_n(result);
1696
+ self.update_z(result);
1697
+ // TODO: check if this logic is right.
1698
+ if src1 as u16 >= src2.wrapping_add(c) {
1699
+ self.p.set_c();
1700
+ } else {
1701
+ self.p.clear_c();
1702
+ }
1703
+ // TODO: implement right overflow logic.
1704
+ // this is just a temporal logic.
1705
+ if ((src1 ^ result as u8) & 0x80) != 0 && ((src1 ^ src2 as u8) & 0x80) != 0 {
1706
+ self.p.set_v();
1707
+ } else {
1708
+ self.p.clear_v();
1709
+ }
1710
+ },
1711
+ InstructionTypes::SEC => {
1712
+ self.p.set_c();
1713
+ },
1714
+ InstructionTypes::SED => {
1715
+ self.p.set_d();
1716
+ },
1717
+ InstructionTypes::SEI => {
1718
+ self.p.set_i();
1719
+ },
1720
+ InstructionTypes::STA => {
1721
+ let value = self.a.load();
1722
+ self.store_with_addressing_mode(&op, value);
1723
+ },
1724
+ InstructionTypes::STX => {
1725
+ let value = self.x.load();
1726
+ self.store_with_addressing_mode(&op, value);
1727
+ },
1728
+ InstructionTypes::STY => {
1729
+ let value = self.y.load();
1730
+ self.store_with_addressing_mode(&op, value);
1731
+ },
1732
+ InstructionTypes::TAX => {
1733
+ let result = self.a.load() as u16;
1734
+ self.x.store(result as u8);
1735
+ self.update_n(result);
1736
+ self.update_z(result);
1737
+ },
1738
+ InstructionTypes::TAY => {
1739
+ let result = self.a.load() as u16;
1740
+ self.y.store(result as u8);
1741
+ self.update_n(result);
1742
+ self.update_z(result);
1743
+ },
1744
+ InstructionTypes::TSX => {
1745
+ let result = self.sp.load() as u16;
1746
+ self.x.store(result as u8);
1747
+ self.update_n(result);
1748
+ self.update_z(result);
1749
+ },
1750
+ InstructionTypes::TXA => {
1751
+ let result = self.x.load() as u16;
1752
+ self.a.store(result as u8);
1753
+ self.update_n(result);
1754
+ self.update_z(result);
1755
+ },
1756
+ InstructionTypes::TXS => {
1757
+ let result = self.x.load();
1758
+ self.sp.store(result);
1759
+ },
1760
+ InstructionTypes::TYA => {
1761
+ let result = self.y.load() as u16;
1762
+ self.a.store(result as u8);
1763
+ self.update_n(result);
1764
+ self.update_z(result);
1765
+ }
1766
+ }
1767
+ }
1768
+
1769
+ pub fn load(&mut self, address: u16) -> u8 {
1770
+ // 0x0000 - 0x07FF: 2KB internal RAM
1771
+ // 0x0800 - 0x1FFF: Mirrors of 0x0000 - 0x07FF (repeats every 0x800 bytes)
1772
+
1773
+ if address < 0x2000 {
1774
+ return self.ram.load((address & 0x07FF) as u32);
1775
+ }
1776
+
1777
+ // 0x2000 - 0x2007: PPU registers
1778
+ // 0x2008 - 0x3FFF: Mirrors of 0x2000 - 0x2007 (repeats every 8 bytes)
1779
+
1780
+ if address >= 0x2000 && address < 0x4000 {
1781
+ return self.ppu.load_register(address & 0x2007, &self.rom);
1782
+ }
1783
+
1784
+ if address >= 0x4000 && address < 0x4014 {
1785
+ return self.apu.load_register(address);
1786
+ }
1787
+
1788
+ if address == 0x4014 {
1789
+ return self.ppu.load_register(address, &self.rom);
1790
+ }
1791
+
1792
+ if address == 0x4015 {
1793
+ return self.apu.load_register(address);
1794
+ }
1795
+
1796
+ if address == 0x4016 {
1797
+ return self.joypad1.load_register();
1798
+ }
1799
+
1800
+ if address == 0x4017 {
1801
+ return self.joypad2.load_register();
1802
+ }
1803
+
1804
+ if address >= 0x4017 && address < 0x4020 {
1805
+ return self.apu.load_register(address);
1806
+ }
1807
+
1808
+ if address >= 0x4020 && address < 0x6000 {
1809
+ return self.ram.load(address as u32);
1810
+ }
1811
+
1812
+ if address >= 0x6000 && address < 0x8000 {
1813
+ return self.ram.load(address as u32);
1814
+ }
1815
+
1816
+ if address >= 0x8000 {
1817
+ return self.rom.load(address as u32);
1818
+ }
1819
+
1820
+ 0 // dummy
1821
+ }
1822
+
1823
+ fn load_2bytes(&mut self, address: u16) -> u16 {
1824
+ let byte_low = self.load(address) as u16;
1825
+ let byte_high = self.load(address.wrapping_add(1)) as u16;
1826
+ (byte_high << 8) | byte_low
1827
+ }
1828
+
1829
+ fn load_2bytes_from_zeropage(&mut self, address: u16) -> u16 {
1830
+ self.ram.load((address & 0xff) as u32) as u16 | ((self.ram.load((address.wrapping_add(1) & 0xff) as u32) as u16) << 8)
1831
+ }
1832
+
1833
+ fn load_2bytes_in_page(&mut self, address: u16) -> u16 {
1834
+ let addr1 = address;
1835
+ let addr2 = (address & 0xff00) | ((address.wrapping_add(1)) & 0xff);
1836
+ let byte_low = self.load(addr1) as u16;
1837
+ let byte_high = self.load(addr2) as u16;
1838
+ (byte_high << 8) | byte_low
1839
+ }
1840
+
1841
+ fn store(&mut self, address: u16, value: u8) {
1842
+ // 0x0000 - 0x07FF: 2KB internal RAM
1843
+ // 0x0800 - 0x1FFF: Mirrors of 0x0000 - 0x07FF (repeats every 0x800 bytes)
1844
+
1845
+ if address < 0x2000 {
1846
+ self.ram.store((address & 0x07FF) as u32, value);
1847
+ }
1848
+
1849
+ // 0x2000 - 0x2007: PPU registers
1850
+ // 0x2008 - 0x3FFF: Mirrors of 0x2000 - 0x2007 (repeats every 8 bytes)
1851
+
1852
+ if address >= 0x2000 && address < 0x4000 {
1853
+ self.ppu.store_register(address & 0x2007, value, &mut self.rom);
1854
+ }
1855
+
1856
+ if address >= 0x4000 && address < 0x4014 {
1857
+ self.apu.store_register(address, value);
1858
+ }
1859
+
1860
+ // @TODO: clean up
1861
+
1862
+ if address == 0x4014 {
1863
+ self.ppu.store_register(address, value, &mut self.rom);
1864
+
1865
+ // DMA.
1866
+ // Writing 0xXX will upload 256 bytes of data from CPU page
1867
+ // 0xXX00-0xXXFF to the internal PPU OAM.
1868
+ let offset = (value as u16) << 8;
1869
+ for i in 0..256 {
1870
+ let data = self.load(offset + i);
1871
+ self.ppu.store_register(0x2004, data, &mut self.rom);
1872
+ }
1873
+
1874
+ // @TODO
1875
+ self.stall_cycles += 514;
1876
+ }
1877
+
1878
+ if address == 0x4015 {
1879
+ self.apu.store_register(address, value);
1880
+ }
1881
+
1882
+ if address == 0x4016 {
1883
+ self.joypad1.store_register(value);
1884
+ self.joypad2.store_register(value); // to clear the joypad2 state
1885
+ }
1886
+
1887
+ if address >= 0x4017 && address < 0x4020 {
1888
+ self.apu.store_register(address, value);
1889
+ }
1890
+
1891
+ // cartridge space
1892
+
1893
+ if address >= 0x4020 && address < 0x6000 {
1894
+ self.ram.store(address as u32, value);
1895
+ }
1896
+
1897
+ // 0x6000 - 0x7FFF: Battery Backed Save or Work RAM
1898
+
1899
+ if address >= 0x6000 && address < 0x8000 {
1900
+ if self.rom.has_battery_backed_ram() {
1901
+ let current = self.ram.load(address as u32);
1902
+ if current != value {
1903
+ self.sram_dirty = true;
1904
+ }
1905
+ }
1906
+ self.ram.store(address as u32, value);
1907
+ }
1908
+
1909
+ // 0x8000 - 0xFFFF: ROM
1910
+
1911
+ if address >= 0x8000 {
1912
+ self.rom.store(address as u32, value);
1913
+ }
1914
+ }
1915
+
1916
+ pub fn interrupt(&mut self, interrupt_type: Interrupts) {
1917
+ // @TODO: Optimize
1918
+
1919
+ match interrupt_type {
1920
+ Interrupts::IRQ => {
1921
+ if self.p.is_i() {
1922
+ return;
1923
+ }
1924
+ },
1925
+ _ => {}
1926
+ }
1927
+
1928
+ match interrupt_type {
1929
+ Interrupts::RESET => {},
1930
+ _ => {
1931
+ match interrupt_type {
1932
+ Interrupts::BRK => {},
1933
+ _ => self.p.clear_b()
1934
+ };
1935
+ self.p.set_a();
1936
+
1937
+ let value = self.pc.load();
1938
+ self.push_stack_2bytes(value);
1939
+ let value2 = self.p.load();
1940
+ self.push_stack(value2);
1941
+ self.p.set_i();
1942
+ }
1943
+ };
1944
+
1945
+ self.jump_to_interrupt_handler(interrupt_type);
1946
+ }
1947
+
1948
+ fn load_with_addressing_mode(&mut self, op: &Operation) -> u16 {
1949
+ match op.addressing_mode {
1950
+ AddressingModes::Accumulator => {
1951
+ self.a.load() as u16
1952
+ },
1953
+ _ => {
1954
+ let address = self.get_address_with_addressing_mode(&op);
1955
+ let value = self.load(address) as u16;
1956
+ match op.addressing_mode {
1957
+ // expects that relative addressing mode is used only for load.
1958
+ AddressingModes::Relative => {
1959
+ // TODO: confirm if this logic is right.
1960
+ if (value & 0x80) != 0 {
1961
+ value | 0xff00
1962
+ } else {
1963
+ value
1964
+ }
1965
+ },
1966
+ _ => value
1967
+ }
1968
+ }
1969
+ }
1970
+ }
1971
+
1972
+ fn store_with_addressing_mode(&mut self, op: &Operation, value: u8) {
1973
+ match op.addressing_mode {
1974
+ AddressingModes::Accumulator => {
1975
+ self.a.store(value);
1976
+ },
1977
+ _ => {
1978
+ let address = self.get_address_with_addressing_mode(op);
1979
+ self.store(address, value);
1980
+ }
1981
+ };
1982
+ }
1983
+
1984
+ fn update_memory_with_addressing_mode<F>(&mut self, op: &Operation, func: F) -> u16 where F: Fn(u8) -> u16 {
1985
+ match op.addressing_mode {
1986
+ AddressingModes::Accumulator => {
1987
+ let src = self.a.load();
1988
+ let result = func(src);
1989
+ self.a.store(result as u8);
1990
+ result
1991
+ },
1992
+ _ => {
1993
+ let address = self.get_address_with_addressing_mode(op);
1994
+ let src = self.load(address);
1995
+ let result = func(src);
1996
+ self.store(address, result as u8);
1997
+ result
1998
+ }
1999
+ }
2000
+ }
2001
+
2002
+ fn get_address_with_addressing_mode(&mut self, op: &Operation) -> u16 {
2003
+ match op.addressing_mode {
2004
+ AddressingModes::Immediate | AddressingModes::Relative => {
2005
+ let address = self.pc.load();
2006
+ self.pc.increment();
2007
+ address
2008
+ },
2009
+ AddressingModes::Absolute | AddressingModes::IndexedAbsoluteX | AddressingModes::IndexedAbsoluteY => {
2010
+ let address = self.load_2bytes(self.pc.load());
2011
+ self.pc.increment_by_2();
2012
+ let effective_address = address.wrapping_add(match op.addressing_mode {
2013
+ AddressingModes::IndexedAbsoluteX => self.x.load(),
2014
+ AddressingModes::IndexedAbsoluteY => self.y.load(),
2015
+ _ => 0
2016
+ } as u16);
2017
+ match op.instruction_type {
2018
+ InstructionTypes::ADC |
2019
+ InstructionTypes::AND |
2020
+ InstructionTypes::CMP |
2021
+ InstructionTypes::EOR |
2022
+ InstructionTypes::LDA |
2023
+ InstructionTypes::LDY |
2024
+ InstructionTypes::LDX |
2025
+ InstructionTypes::ORA |
2026
+ InstructionTypes::SBC => {
2027
+ // stall_cycles + 1 if page is crossed
2028
+ if (address & 0xff00) != (effective_address & 0xff00) {
2029
+ self.stall_cycles += 1;
2030
+ }
2031
+ },
2032
+ _ => {}
2033
+ };
2034
+ effective_address
2035
+ },
2036
+ AddressingModes::ZeroPage | AddressingModes::IndexedZeroPageX | AddressingModes::IndexedZeroPageY => {
2037
+ let address = self.pc.load();
2038
+ let address2 = self.load(address) as u16;
2039
+ self.pc.increment();
2040
+ address2.wrapping_add(match op.addressing_mode {
2041
+ AddressingModes::IndexedZeroPageX => self.x.load(),
2042
+ AddressingModes::IndexedZeroPageY => self.y.load(),
2043
+ _ => 0
2044
+ } as u16) & 0xFF
2045
+ },
2046
+ AddressingModes::Indirect => {
2047
+ let address = self.pc.load();
2048
+ let tmp = self.load_2bytes(address);
2049
+ self.pc.increment_by_2();
2050
+ self.load_2bytes_in_page(tmp)
2051
+ },
2052
+ AddressingModes::IndexedIndirectX => {
2053
+ let address = self.pc.load();
2054
+ let tmp = self.load(address);
2055
+ self.pc.increment();
2056
+ self.load_2bytes_from_zeropage(((tmp.wrapping_add(self.x.load())) & 0xFF) as u16)
2057
+ },
2058
+ AddressingModes::IndexedIndirectY => {
2059
+ let address = self.pc.load();
2060
+ let tmp = self.load(address);
2061
+ self.pc.increment();
2062
+ let address2 = self.load_2bytes_from_zeropage(tmp as u16);
2063
+ let effective_address = address2.wrapping_add(self.y.load() as u16);
2064
+ match op.instruction_type {
2065
+ InstructionTypes::AND |
2066
+ InstructionTypes::CMP |
2067
+ InstructionTypes::EOR |
2068
+ InstructionTypes::LDA |
2069
+ InstructionTypes::ORA |
2070
+ InstructionTypes::SBC => {
2071
+ // stall_cycles + 1 if page is crossed
2072
+ if (address2 & 0xff00) != (effective_address & 0xff00) {
2073
+ self.stall_cycles += 1;
2074
+ }
2075
+ },
2076
+ _ => {}
2077
+ };
2078
+ effective_address
2079
+ },
2080
+ _ => {
2081
+ // @TODO: Throw?
2082
+ println!("Unknown addressing mode.");
2083
+ 0
2084
+ }
2085
+ }
2086
+ }
2087
+
2088
+ fn update_n(&mut self, value: u16) {
2089
+ if (value & 0x80) == 0 {
2090
+ self.p.clear_n();
2091
+ } else {
2092
+ self.p.set_n();
2093
+ }
2094
+ }
2095
+
2096
+ fn update_z(&mut self, value: u16) {
2097
+ if (value & 0xff) == 0 {
2098
+ self.p.set_z();
2099
+ } else {
2100
+ self.p.clear_z();
2101
+ }
2102
+ }
2103
+
2104
+ fn update_c(&mut self, value: u16) {
2105
+ if (value & 0x100) == 0 {
2106
+ self.p.clear_c();
2107
+ } else {
2108
+ self.p.set_c();
2109
+ }
2110
+ }
2111
+
2112
+ fn get_stack_address(&self) -> u16 {
2113
+ self.sp.load() as u16 + 0x100
2114
+ }
2115
+
2116
+ fn push_stack(&mut self, value: u8) {
2117
+ let address = self.get_stack_address();
2118
+ self.store(address, value);
2119
+ self.sp.decrement();
2120
+ }
2121
+
2122
+ fn push_stack_2bytes(&mut self, value: u16) {
2123
+ let address = self.get_stack_address();
2124
+ self.store(address, ((value >> 8) & 0xff) as u8);
2125
+ self.sp.decrement();
2126
+ let address2 = self.get_stack_address();
2127
+ self.store(address2, (value & 0xff) as u8);
2128
+ self.sp.decrement();
2129
+ }
2130
+
2131
+ fn pop_stack(&mut self) -> u8 {
2132
+ self.sp.increment();
2133
+ self.load(self.get_stack_address())
2134
+ }
2135
+
2136
+ fn pop_stack_2bytes(&mut self) -> u16 {
2137
+ self.sp.increment();
2138
+ let byte_low = self.load(self.get_stack_address()) as u16;
2139
+ self.sp.increment();
2140
+ let byte_high = self.load(self.get_stack_address()) as u16;
2141
+ (byte_high << 8) | byte_low
2142
+ }
2143
+
2144
+ pub fn dump(&mut self) -> String {
2145
+ let opc = self.load(self.pc.load());
2146
+ let op = self.decode(opc);
2147
+ "p:".to_owned() + &self.p.dump() + &" ".to_owned() +
2148
+ &"pc:".to_owned() + &self.pc.dump() + &format!("(0x{:02x})", opc) + &" ".to_owned() +
2149
+ &"sp:".to_owned() + &self.sp.dump() + &" ".to_owned() +
2150
+ &"a:".to_owned() + &self.a.dump() + &" ".to_owned() +
2151
+ &"x:".to_owned() + &self.x.dump() + &" ".to_owned() +
2152
+ &"y:".to_owned() + &self.y.dump() + &" ".to_owned() +
2153
+ instruction_name(op.instruction_type) + &" ".to_owned() +
2154
+ &self.dump_addressing_mode(op.addressing_mode, self.pc.load().wrapping_add(1))
2155
+ }
2156
+
2157
+ fn dump_addressing_mode(&mut self, mode: AddressingModes, pc: u16) -> String {
2158
+ match mode {
2159
+ AddressingModes::Immediate => {
2160
+ "#".to_owned() + &format!("0x{:02x} ", self.load(pc)) +
2161
+ &"immediate".to_owned()
2162
+ },
2163
+ AddressingModes::Relative => {
2164
+ format!("0x{:02x} ", self.load(pc) as i8) +
2165
+ &"relative".to_owned()
2166
+ },
2167
+ AddressingModes::Absolute => {
2168
+ let address = self.load_2bytes(pc);
2169
+ format!("0x{:04x} ", address) +
2170
+ &format!("(0x{:02x}) ", self.load(address) as i8) +
2171
+ &"absolute".to_owned()
2172
+ },
2173
+ AddressingModes::IndexedAbsoluteX => {
2174
+ let address = self.load_2bytes(pc);
2175
+ format!("0x{:04x},X ", address) +
2176
+ &format!("(0x{:02x}) ", self.load((self.x.load() as u16).wrapping_add(address)) as i8) +
2177
+ &"indexed_absolute_x".to_owned()
2178
+ },
2179
+ AddressingModes::IndexedAbsoluteY => {
2180
+ let address = self.load_2bytes(pc);
2181
+ format!("0x{:04x},Y ", address) +
2182
+ &format!("(0x{:02x}) ", self.load((self.y.load() as u16).wrapping_add(address)) as i8) +
2183
+ &"indexed_absolute_y".to_owned()
2184
+ },
2185
+ AddressingModes::ZeroPage => {
2186
+ let address = self.load(pc);
2187
+ format!("0x{:02x} ", address) +
2188
+ &format!("(0x{:02x}) ", self.load(address as u16) as i8) +
2189
+ &"zero_page".to_owned()
2190
+ },
2191
+ AddressingModes::IndexedZeroPageX => {
2192
+ let address = self.load(pc);
2193
+ format!("0x{:02x},X ", address) +
2194
+ &format!("(0x{:02x}) ", self.load(self.x.load().wrapping_add(address) as u16) as i8) +
2195
+ &"indexed_zero_page_x".to_owned()
2196
+ },
2197
+ AddressingModes::IndexedZeroPageY => {
2198
+ let address = self.load(pc);
2199
+ format!("0x{:02x},Y ", address) +
2200
+ &format!("(0x{:02x}) ", self.load(self.y.load().wrapping_add(address) as u16) as i8) +
2201
+ &"indexed_zero_page_y".to_owned()
2202
+ },
2203
+ AddressingModes::Indirect => {
2204
+ let address = self.load_2bytes(pc);
2205
+ let address2 = self.load_2bytes(address);
2206
+ format!("0x{:04x} ", address) +
2207
+ &format!("(0x{:04x}(0x{:02x})) ", address2, self.load(address2) as i8) +
2208
+ &"indirect".to_owned()
2209
+ },
2210
+ AddressingModes::IndexedIndirectX => {
2211
+ let address = self.load(pc) as u16;
2212
+ let address2 = (self.x.load() as u16).wrapping_add(address);
2213
+ format!("0x{:02x},X ", address) +
2214
+ &format!("(0x{:04x}(0x{:02x})) ", address2, self.load(address2) as i8) +
2215
+ &"indexed_indirect_x".to_owned()
2216
+ },
2217
+ AddressingModes::IndexedIndirectY => {
2218
+ let address = self.load(pc) as u16;
2219
+ let address2 = self.load_2bytes_from_zeropage(address).wrapping_add(self.x.load() as u16);
2220
+ format!("0x{:02x},Y ", address) +
2221
+ &format!("(0x{:04x}(0x{:02x})) ", address2, self.load(address2) as i8) +
2222
+ &"indexed_indirect_y".to_owned()
2223
+ },
2224
+ AddressingModes::Accumulator => {
2225
+ format!("A0x{:02x} ", self.a.load()) +
2226
+ &"accumulator".to_owned()
2227
+ },
2228
+ _ => { "".to_owned() }
2229
+ }
2230
+ }
2231
+ }
2232
+
2233
+ pub struct CpuStatusRegister {
2234
+ register: Register<u8>
2235
+ }
2236
+
2237
+ impl CpuStatusRegister {
2238
+ pub fn new() -> Self {
2239
+ CpuStatusRegister {
2240
+ register: Register::<u8>::new()
2241
+ }
2242
+ }
2243
+
2244
+ pub fn load(&self) -> u8 {
2245
+ self.register.load()
2246
+ }
2247
+
2248
+ pub fn store(&mut self, value: u8) {
2249
+ self.register.store(value);
2250
+ }
2251
+
2252
+ pub fn is_n(&self) -> bool {
2253
+ self.register.is_bit_set(7)
2254
+ }
2255
+
2256
+ pub fn set_n(&mut self) {
2257
+ self.register.set_bit(7);
2258
+ }
2259
+
2260
+ pub fn clear_n(&mut self) {
2261
+ self.register.clear_bit(7);
2262
+ }
2263
+
2264
+ pub fn is_v(&self) -> bool {
2265
+ self.register.is_bit_set(6)
2266
+ }
2267
+
2268
+ pub fn set_v(&mut self) {
2269
+ self.register.set_bit(6);
2270
+ }
2271
+
2272
+ pub fn clear_v(&mut self) {
2273
+ self.register.clear_bit(6);
2274
+ }
2275
+
2276
+ // 5-bit is unused bit (but somehow set from BRK) and no name.
2277
+ // I named random name "a".
2278
+
2279
+ pub fn is_a(&self) -> bool {
2280
+ self.register.is_bit_set(5)
2281
+ }
2282
+
2283
+ pub fn set_a(&mut self) {
2284
+ self.register.set_bit(5);
2285
+ }
2286
+
2287
+ pub fn clear_a(&mut self) {
2288
+ self.register.clear_bit(5);
2289
+ }
2290
+
2291
+ pub fn is_b(&self) -> bool {
2292
+ self.register.is_bit_set(4)
2293
+ }
2294
+
2295
+ pub fn set_b(&mut self) {
2296
+ self.register.set_bit(4);
2297
+ }
2298
+
2299
+ pub fn clear_b(&mut self) {
2300
+ self.register.clear_bit(4);
2301
+ }
2302
+
2303
+ pub fn is_d(&self) -> bool {
2304
+ self.register.is_bit_set(3)
2305
+ }
2306
+
2307
+ pub fn set_d(&mut self) {
2308
+ self.register.set_bit(3);
2309
+ }
2310
+
2311
+ pub fn clear_d(&mut self) {
2312
+ self.register.clear_bit(3);
2313
+ }
2314
+
2315
+ pub fn is_i(&self) -> bool {
2316
+ self.register.is_bit_set(2)
2317
+ }
2318
+
2319
+ pub fn set_i(&mut self) {
2320
+ self.register.set_bit(2);
2321
+ }
2322
+
2323
+ pub fn clear_i(&mut self) {
2324
+ self.register.clear_bit(2);
2325
+ }
2326
+
2327
+ pub fn is_z(&self) -> bool {
2328
+ self.register.is_bit_set(1)
2329
+ }
2330
+
2331
+ pub fn set_z(&mut self) {
2332
+ self.register.set_bit(1);
2333
+ }
2334
+
2335
+ pub fn clear_z(&mut self) {
2336
+ self.register.clear_bit(1);
2337
+ }
2338
+
2339
+ pub fn is_c(&self) -> bool {
2340
+ self.register.is_bit_set(0)
2341
+ }
2342
+
2343
+ pub fn set_c(&mut self) {
2344
+ self.register.set_bit(0);
2345
+ }
2346
+
2347
+ pub fn clear_c(&mut self) {
2348
+ self.register.clear_bit(0);
2349
+ }
2350
+
2351
+ fn dump(&self) -> String {
2352
+ self.register.dump() +
2353
+ &"(".to_owned() +
2354
+ match self.is_n() { true => &"N", false => &"-" }.to_owned() +
2355
+ match self.is_v() { true => &"V", false => &"-" }.to_owned() +
2356
+ match self.is_a() { true => &"A", false => &"-" }.to_owned() +
2357
+ match self.is_b() { true => &"B", false => &"-" }.to_owned() +
2358
+ match self.is_d() { true => &"D", false => &"-" }.to_owned() +
2359
+ match self.is_i() { true => &"I", false => &"-" }.to_owned() +
2360
+ match self.is_z() { true => &"Z", false => &"-" }.to_owned() +
2361
+ match self.is_c() { true => &"C", false => &"-" }.to_owned() +
2362
+ &")".to_owned()
2363
+ }
2364
+ }