summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--CMakeLists.txt4
-rw-r--r--lib/nes/sys/cpu.cc853
-rw-r--r--lib/nes/sys/cpu.hh185
4 files changed, 533 insertions, 511 deletions
diff --git a/.gitignore b/.gitignore
index 822dd55..a13f433 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
cmake-build-*/
+build/
+.vscode/
.idea/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 101c1bd..2b19668 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,13 +17,13 @@ target_compile_options(nes_options
INTERFACE
-Wall
-Wextra
+ -Wno-changes-meaning # fuck off, gcc
+ -Wno-unused-function # fr
-Wnon-virtual-dtor
-Wcast-align
-Wunused
-Woverloaded-virtual
-Wpedantic
- -Wconversion
- -Wsign-conversion
-Wdouble-promotion
-Wformat=2
-Wswitch-enum)
diff --git a/lib/nes/sys/cpu.cc b/lib/nes/sys/cpu.cc
index 55bbb21..b2f9a88 100644
--- a/lib/nes/sys/cpu.cc
+++ b/lib/nes/sys/cpu.cc
@@ -61,262 +61,262 @@ namespace nes::sys
auto const opcode = advance_pc8();
switch (opcode)
{
- case 0x00: return run_brk<addressing_mode::immediate>();
- case 0x01: return run_ora<addressing_mode::indexed_indirect>();
+ case 0x00: return run_brk<detail::addressing_mode::immediate>();
+ case 0x01: return run_ora<detail::addressing_mode::indexed_indirect>();
case 0x02: return run_stp();
- case 0x03: return run_slo<addressing_mode::indexed_indirect>();
- case 0x04: return run_nop<addressing_mode::zero_page>();
- case 0x05: return run_ora<addressing_mode::zero_page>();
- case 0x06: return run_asl<addressing_mode::zero_page>();
- case 0x07: return run_slo<addressing_mode::zero_page>();
+ case 0x03: return run_slo<detail::addressing_mode::indexed_indirect>();
+ case 0x04: return run_nop<detail::addressing_mode::zero_page>();
+ case 0x05: return run_ora<detail::addressing_mode::zero_page>();
+ case 0x06: return run_asl<detail::addressing_mode::zero_page>();
+ case 0x07: return run_slo<detail::addressing_mode::zero_page>();
case 0x08: return run_php();
- case 0x09: return run_ora<addressing_mode::immediate>();
- case 0x0A: return run_asl<addressing_mode::accumulator>();
- case 0x0B: return run_anc<addressing_mode::immediate>();
- case 0x0C: return run_nop<addressing_mode::absolute>();
- case 0x0D: return run_ora<addressing_mode::absolute>();
- case 0x0E: return run_asl<addressing_mode::absolute>();
- case 0x0F: return run_slo<addressing_mode::absolute>();
- case 0x10: return run_bpl<addressing_mode::relative>();
- case 0x11: return run_ora<addressing_mode::indirect_indexed>();
+ case 0x09: return run_ora<detail::addressing_mode::immediate>();
+ case 0x0A: return run_asl<detail::addressing_mode::accumulator>();
+ case 0x0B: return run_anc<detail::addressing_mode::immediate>();
+ case 0x0C: return run_nop<detail::addressing_mode::absolute>();
+ case 0x0D: return run_ora<detail::addressing_mode::absolute>();
+ case 0x0E: return run_asl<detail::addressing_mode::absolute>();
+ case 0x0F: return run_slo<detail::addressing_mode::absolute>();
+ case 0x10: return run_bpl<detail::addressing_mode::relative>();
+ case 0x11: return run_ora<detail::addressing_mode::indirect_indexed>();
case 0x12: return run_stp();
- case 0x13: return run_slo<addressing_mode::indirect_indexed>();
- case 0x14: return run_nop<addressing_mode::zero_page_indexed_x>();
- case 0x15: return run_ora<addressing_mode::zero_page_indexed_x>();
- case 0x16: return run_asl<addressing_mode::zero_page_indexed_x>();
- case 0x17: return run_slo<addressing_mode::zero_page_indexed_x>();
+ case 0x13: return run_slo<detail::addressing_mode::indirect_indexed>();
+ case 0x14: return run_nop<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x15: return run_ora<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x16: return run_asl<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x17: return run_slo<detail::addressing_mode::zero_page_indexed_x>();
case 0x18: return run_clc();
- case 0x19: return run_ora<addressing_mode::absolute_indexed_y>();
+ case 0x19: return run_ora<detail::addressing_mode::absolute_indexed_y>();
case 0x1A: return run_nop();
- case 0x1B: return run_slo<addressing_mode::absolute_indexed_y>();
- case 0x1C: return run_nop<addressing_mode::absolute_indexed_x>();
- case 0x1D: return run_ora<addressing_mode::absolute_indexed_x>();
- case 0x1E: return run_asl<addressing_mode::absolute_indexed_x>();
- case 0x1F: return run_slo<addressing_mode::absolute_indexed_x>();
- case 0x20: return run_jsr<addressing_mode::absolute>();
- case 0x21: return run_and<addressing_mode::indexed_indirect>();
+ case 0x1B: return run_slo<detail::addressing_mode::absolute_indexed_y>();
+ case 0x1C: return run_nop<detail::addressing_mode::absolute_indexed_x>();
+ case 0x1D: return run_ora<detail::addressing_mode::absolute_indexed_x>();
+ case 0x1E: return run_asl<detail::addressing_mode::absolute_indexed_x>();
+ case 0x1F: return run_slo<detail::addressing_mode::absolute_indexed_x>();
+ case 0x20: return run_jsr<detail::addressing_mode::absolute>();
+ case 0x21: return run_and<detail::addressing_mode::indexed_indirect>();
case 0x22: return run_stp();
- case 0x23: return run_rla<addressing_mode::indexed_indirect>();
- case 0x24: return run_bit<addressing_mode::zero_page>();
- case 0x25: return run_and<addressing_mode::zero_page>();
- case 0x26: return run_rol<addressing_mode::zero_page>();
- case 0x27: return run_rla<addressing_mode::zero_page>();
+ case 0x23: return run_rla<detail::addressing_mode::indexed_indirect>();
+ case 0x24: return run_bit<detail::addressing_mode::zero_page>();
+ case 0x25: return run_and<detail::addressing_mode::zero_page>();
+ case 0x26: return run_rol<detail::addressing_mode::zero_page>();
+ case 0x27: return run_rla<detail::addressing_mode::zero_page>();
case 0x28: return run_plp();
- case 0x29: return run_and<addressing_mode::immediate>();
- case 0x2A: return run_rol<addressing_mode::accumulator>();
- case 0x2B: return run_anc<addressing_mode::immediate>();
- case 0x2C: return run_bit<addressing_mode::absolute>();
- case 0x2D: return run_and<addressing_mode::absolute>();
- case 0x2E: return run_rol<addressing_mode::absolute>();
- case 0x2F: return run_rla<addressing_mode::absolute>();
- case 0x30: return run_bmi<addressing_mode::relative>();
- case 0x31: return run_and<addressing_mode::indirect_indexed>();
+ case 0x29: return run_and<detail::addressing_mode::immediate>();
+ case 0x2A: return run_rol<detail::addressing_mode::accumulator>();
+ case 0x2B: return run_anc<detail::addressing_mode::immediate>();
+ case 0x2C: return run_bit<detail::addressing_mode::absolute>();
+ case 0x2D: return run_and<detail::addressing_mode::absolute>();
+ case 0x2E: return run_rol<detail::addressing_mode::absolute>();
+ case 0x2F: return run_rla<detail::addressing_mode::absolute>();
+ case 0x30: return run_bmi<detail::addressing_mode::relative>();
+ case 0x31: return run_and<detail::addressing_mode::indirect_indexed>();
case 0x32: return run_stp();
- case 0x33: return run_rla<addressing_mode::indirect_indexed>();
- case 0x34: return run_nop<addressing_mode::zero_page_indexed_x>();
- case 0x35: return run_and<addressing_mode::zero_page_indexed_x>();
- case 0x36: return run_rol<addressing_mode::zero_page_indexed_x>();
- case 0x37: return run_rla<addressing_mode::zero_page_indexed_x>();
+ case 0x33: return run_rla<detail::addressing_mode::indirect_indexed>();
+ case 0x34: return run_nop<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x35: return run_and<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x36: return run_rol<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x37: return run_rla<detail::addressing_mode::zero_page_indexed_x>();
case 0x38: return run_sec();
- case 0x39: return run_and<addressing_mode::absolute_indexed_y>();
+ case 0x39: return run_and<detail::addressing_mode::absolute_indexed_y>();
case 0x3A: return run_nop();
- case 0x3B: return run_rla<addressing_mode::absolute_indexed_y>();
- case 0x3C: return run_nop<addressing_mode::absolute_indexed_x>();
- case 0x3D: return run_and<addressing_mode::absolute_indexed_x>();
- case 0x3E: return run_rol<addressing_mode::absolute_indexed_x>();
- case 0x3F: return run_rla<addressing_mode::absolute_indexed_x>();
+ case 0x3B: return run_rla<detail::addressing_mode::absolute_indexed_y>();
+ case 0x3C: return run_nop<detail::addressing_mode::absolute_indexed_x>();
+ case 0x3D: return run_and<detail::addressing_mode::absolute_indexed_x>();
+ case 0x3E: return run_rol<detail::addressing_mode::absolute_indexed_x>();
+ case 0x3F: return run_rla<detail::addressing_mode::absolute_indexed_x>();
case 0x40: return run_rti();
- case 0x41: return run_eor<addressing_mode::indexed_indirect>();
+ case 0x41: return run_eor<detail::addressing_mode::indexed_indirect>();
case 0x42: return run_stp();
- case 0x43: return run_sre<addressing_mode::indexed_indirect>();
- case 0x44: return run_nop<addressing_mode::zero_page>();
- case 0x45: return run_eor<addressing_mode::zero_page>();
- case 0x46: return run_lsr<addressing_mode::zero_page>();
- case 0x47: return run_sre<addressing_mode::zero_page>();
+ case 0x43: return run_sre<detail::addressing_mode::indexed_indirect>();
+ case 0x44: return run_nop<detail::addressing_mode::zero_page>();
+ case 0x45: return run_eor<detail::addressing_mode::zero_page>();
+ case 0x46: return run_lsr<detail::addressing_mode::zero_page>();
+ case 0x47: return run_sre<detail::addressing_mode::zero_page>();
case 0x48: return run_pha();
- case 0x49: return run_eor<addressing_mode::immediate>();
- case 0x4A: return run_lsr<addressing_mode::accumulator>();
- case 0x4B: return run_alr<addressing_mode::immediate>();
- case 0x4C: return run_jmp<addressing_mode::absolute>();
- case 0x4D: return run_eor<addressing_mode::absolute>();
- case 0x4E: return run_lsr<addressing_mode::absolute>();
- case 0x4F: return run_sre<addressing_mode::absolute>();
- case 0x50: return run_bvc<addressing_mode::relative>();
- case 0x51: return run_eor<addressing_mode::indirect_indexed>();
+ case 0x49: return run_eor<detail::addressing_mode::immediate>();
+ case 0x4A: return run_lsr<detail::addressing_mode::accumulator>();
+ case 0x4B: return run_alr<detail::addressing_mode::immediate>();
+ case 0x4C: return run_jmp<detail::addressing_mode::absolute>();
+ case 0x4D: return run_eor<detail::addressing_mode::absolute>();
+ case 0x4E: return run_lsr<detail::addressing_mode::absolute>();
+ case 0x4F: return run_sre<detail::addressing_mode::absolute>();
+ case 0x50: return run_bvc<detail::addressing_mode::relative>();
+ case 0x51: return run_eor<detail::addressing_mode::indirect_indexed>();
case 0x52: return run_stp();
- case 0x53: return run_sre<addressing_mode::indirect_indexed>();
- case 0x54: return run_nop<addressing_mode::zero_page_indexed_x>();
- case 0x55: return run_eor<addressing_mode::zero_page_indexed_x>();
- case 0x56: return run_lsr<addressing_mode::zero_page_indexed_x>();
- case 0x57: return run_sre<addressing_mode::zero_page_indexed_x>();
+ case 0x53: return run_sre<detail::addressing_mode::indirect_indexed>();
+ case 0x54: return run_nop<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x55: return run_eor<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x56: return run_lsr<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x57: return run_sre<detail::addressing_mode::zero_page_indexed_x>();
case 0x58: return run_cli();
- case 0x59: return run_eor<addressing_mode::absolute_indexed_y>();
+ case 0x59: return run_eor<detail::addressing_mode::absolute_indexed_y>();
case 0x5A: return run_nop();
- case 0x5B: return run_sre<addressing_mode::absolute_indexed_y>();
- case 0x5C: return run_nop<addressing_mode::absolute_indexed_x>();
- case 0x5D: return run_eor<addressing_mode::absolute_indexed_x>();
- case 0x5E: return run_lsr<addressing_mode::absolute_indexed_x>();
- case 0x5F: return run_sre<addressing_mode::absolute_indexed_x>();
+ case 0x5B: return run_sre<detail::addressing_mode::absolute_indexed_y>();
+ case 0x5C: return run_nop<detail::addressing_mode::absolute_indexed_x>();
+ case 0x5D: return run_eor<detail::addressing_mode::absolute_indexed_x>();
+ case 0x5E: return run_lsr<detail::addressing_mode::absolute_indexed_x>();
+ case 0x5F: return run_sre<detail::addressing_mode::absolute_indexed_x>();
case 0x60: return run_rts();
- case 0x61: return run_adc<addressing_mode::indexed_indirect>();
+ case 0x61: return run_adc<detail::addressing_mode::indexed_indirect>();
case 0x62: return run_stp();
- case 0x63: return run_rra<addressing_mode::indexed_indirect>();
- case 0x64: return run_nop<addressing_mode::zero_page>();
- case 0x65: return run_adc<addressing_mode::zero_page>();
- case 0x66: return run_ror<addressing_mode::zero_page>();
- case 0x67: return run_rra<addressing_mode::zero_page>();
+ case 0x63: return run_rra<detail::addressing_mode::indexed_indirect>();
+ case 0x64: return run_nop<detail::addressing_mode::zero_page>();
+ case 0x65: return run_adc<detail::addressing_mode::zero_page>();
+ case 0x66: return run_ror<detail::addressing_mode::zero_page>();
+ case 0x67: return run_rra<detail::addressing_mode::zero_page>();
case 0x68: return run_pla();
- case 0x69: return run_adc<addressing_mode::immediate>();
- case 0x6A: return run_ror<addressing_mode::accumulator>();
- case 0x6B: return run_arr<addressing_mode::immediate>();
- case 0x6C: return run_jmp<addressing_mode::indirect>();
- case 0x6D: return run_adc<addressing_mode::absolute>();
- case 0x6E: return run_ror<addressing_mode::absolute>();
- case 0x6F: return run_rra<addressing_mode::absolute>();
- case 0x70: return run_bvs<addressing_mode::relative>();
- case 0x71: return run_adc<addressing_mode::indirect_indexed>();
+ case 0x69: return run_adc<detail::addressing_mode::immediate>();
+ case 0x6A: return run_ror<detail::addressing_mode::accumulator>();
+ case 0x6B: return run_arr<detail::addressing_mode::immediate>();
+ case 0x6C: return run_jmp<detail::addressing_mode::indirect>();
+ case 0x6D: return run_adc<detail::addressing_mode::absolute>();
+ case 0x6E: return run_ror<detail::addressing_mode::absolute>();
+ case 0x6F: return run_rra<detail::addressing_mode::absolute>();
+ case 0x70: return run_bvs<detail::addressing_mode::relative>();
+ case 0x71: return run_adc<detail::addressing_mode::indirect_indexed>();
case 0x72: return run_stp();
- case 0x73: return run_rra<addressing_mode::indirect_indexed>();
- case 0x74: return run_nop<addressing_mode::zero_page_indexed_x>();
- case 0x75: return run_adc<addressing_mode::zero_page_indexed_x>();
- case 0x76: return run_ror<addressing_mode::zero_page_indexed_x>();
- case 0x77: return run_rra<addressing_mode::zero_page_indexed_x>();
+ case 0x73: return run_rra<detail::addressing_mode::indirect_indexed>();
+ case 0x74: return run_nop<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x75: return run_adc<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x76: return run_ror<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x77: return run_rra<detail::addressing_mode::zero_page_indexed_x>();
case 0x78: return run_sei();
- case 0x79: return run_adc<addressing_mode::absolute_indexed_y>();
+ case 0x79: return run_adc<detail::addressing_mode::absolute_indexed_y>();
case 0x7A: return run_nop();
- case 0x7B: return run_rra<addressing_mode::absolute_indexed_y>();
- case 0x7C: return run_nop<addressing_mode::absolute_indexed_x>();
- case 0x7D: return run_adc<addressing_mode::absolute_indexed_x>();
- case 0x7E: return run_ror<addressing_mode::absolute_indexed_x>();
- case 0x7F: return run_rra<addressing_mode::absolute_indexed_x>();
- case 0x80: return run_nop<addressing_mode::immediate>();
- case 0x81: return run_sta<addressing_mode::indexed_indirect>();
- case 0x82: return run_nop<addressing_mode::immediate>();
- case 0x83: return run_sax<addressing_mode::indexed_indirect>();
- case 0x84: return run_sty<addressing_mode::zero_page>();
- case 0x85: return run_sta<addressing_mode::zero_page>();
- case 0x86: return run_stx<addressing_mode::zero_page>();
- case 0x87: return run_sax<addressing_mode::zero_page>();
+ case 0x7B: return run_rra<detail::addressing_mode::absolute_indexed_y>();
+ case 0x7C: return run_nop<detail::addressing_mode::absolute_indexed_x>();
+ case 0x7D: return run_adc<detail::addressing_mode::absolute_indexed_x>();
+ case 0x7E: return run_ror<detail::addressing_mode::absolute_indexed_x>();
+ case 0x7F: return run_rra<detail::addressing_mode::absolute_indexed_x>();
+ case 0x80: return run_nop<detail::addressing_mode::immediate>();
+ case 0x81: return run_sta<detail::addressing_mode::indexed_indirect>();
+ case 0x82: return run_nop<detail::addressing_mode::immediate>();
+ case 0x83: return run_sax<detail::addressing_mode::indexed_indirect>();
+ case 0x84: return run_sty<detail::addressing_mode::zero_page>();
+ case 0x85: return run_sta<detail::addressing_mode::zero_page>();
+ case 0x86: return run_stx<detail::addressing_mode::zero_page>();
+ case 0x87: return run_sax<detail::addressing_mode::zero_page>();
case 0x88: return run_dey();
- case 0x89: return run_nop<addressing_mode::immediate>();
+ case 0x89: return run_nop<detail::addressing_mode::immediate>();
case 0x8A: return run_txa();
- case 0x8B: return run_xaa<addressing_mode::immediate>();
- case 0x8C: return run_sty<addressing_mode::absolute>();
- case 0x8D: return run_sta<addressing_mode::absolute>();
- case 0x8E: return run_stx<addressing_mode::absolute>();
- case 0x8F: return run_sax<addressing_mode::absolute>();
- case 0x90: return run_bcc<addressing_mode::relative>();
- case 0x91: return run_sta<addressing_mode::indirect_indexed>();
+ case 0x8B: return run_xaa<detail::addressing_mode::immediate>();
+ case 0x8C: return run_sty<detail::addressing_mode::absolute>();
+ case 0x8D: return run_sta<detail::addressing_mode::absolute>();
+ case 0x8E: return run_stx<detail::addressing_mode::absolute>();
+ case 0x8F: return run_sax<detail::addressing_mode::absolute>();
+ case 0x90: return run_bcc<detail::addressing_mode::relative>();
+ case 0x91: return run_sta<detail::addressing_mode::indirect_indexed>();
case 0x92: return run_stp();
- case 0x93: return run_ahx<addressing_mode::indirect_indexed>();
- case 0x94: return run_sty<addressing_mode::zero_page_indexed_x>();
- case 0x95: return run_sta<addressing_mode::zero_page_indexed_x>();
- case 0x96: return run_stx<addressing_mode::zero_page_indexed_y>();
- case 0x97: return run_sax<addressing_mode::zero_page_indexed_y>();
+ case 0x93: return run_ahx<detail::addressing_mode::indirect_indexed>();
+ case 0x94: return run_sty<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x95: return run_sta<detail::addressing_mode::zero_page_indexed_x>();
+ case 0x96: return run_stx<detail::addressing_mode::zero_page_indexed_y>();
+ case 0x97: return run_sax<detail::addressing_mode::zero_page_indexed_y>();
case 0x98: return run_tya();
- case 0x99: return run_sta<addressing_mode::absolute_indexed_y>();
+ case 0x99: return run_sta<detail::addressing_mode::absolute_indexed_y>();
case 0x9A: return run_txs();
- case 0x9B: return run_tas<addressing_mode::absolute_indexed_y>();
- case 0x9C: return run_shy<addressing_mode::absolute_indexed_x>();
- case 0x9D: return run_sta<addressing_mode::absolute_indexed_x>();
- case 0x9E: return run_shx<addressing_mode::absolute_indexed_y>();
- case 0x9F: return run_ahx<addressing_mode::absolute_indexed_y>();
- case 0xA0: return run_ldy<addressing_mode::immediate>();
- case 0xA1: return run_lda<addressing_mode::indexed_indirect>();
- case 0xA2: return run_ldx<addressing_mode::immediate>();
- case 0xA3: return run_lax<addressing_mode::indexed_indirect>();
- case 0xA4: return run_ldy<addressing_mode::zero_page>();
- case 0xA5: return run_lda<addressing_mode::zero_page>();
- case 0xA6: return run_ldx<addressing_mode::zero_page>();
- case 0xA7: return run_lax<addressing_mode::zero_page>();
+ case 0x9B: return run_tas<detail::addressing_mode::absolute_indexed_y>();
+ case 0x9C: return run_shy<detail::addressing_mode::absolute_indexed_x>();
+ case 0x9D: return run_sta<detail::addressing_mode::absolute_indexed_x>();
+ case 0x9E: return run_shx<detail::addressing_mode::absolute_indexed_y>();
+ case 0x9F: return run_ahx<detail::addressing_mode::absolute_indexed_y>();
+ case 0xA0: return run_ldy<detail::addressing_mode::immediate>();
+ case 0xA1: return run_lda<detail::addressing_mode::indexed_indirect>();
+ case 0xA2: return run_ldx<detail::addressing_mode::immediate>();
+ case 0xA3: return run_lax<detail::addressing_mode::indexed_indirect>();
+ case 0xA4: return run_ldy<detail::addressing_mode::zero_page>();
+ case 0xA5: return run_lda<detail::addressing_mode::zero_page>();
+ case 0xA6: return run_ldx<detail::addressing_mode::zero_page>();
+ case 0xA7: return run_lax<detail::addressing_mode::zero_page>();
case 0xA8: return run_tay();
- case 0xA9: return run_lda<addressing_mode::immediate>();
+ case 0xA9: return run_lda<detail::addressing_mode::immediate>();
case 0xAA: return run_tax();
- case 0xAB: return run_lax<addressing_mode::immediate>();
- case 0xAC: return run_ldy<addressing_mode::absolute>();
- case 0xAD: return run_lda<addressing_mode::absolute>();
- case 0xAE: return run_ldx<addressing_mode::absolute>();
- case 0xAF: return run_lax<addressing_mode::absolute>();
- case 0xB0: return run_bcs<addressing_mode::relative>();
- case 0xB1: return run_lda<addressing_mode::indirect_indexed>();
+ case 0xAB: return run_lax<detail::addressing_mode::immediate>();
+ case 0xAC: return run_ldy<detail::addressing_mode::absolute>();
+ case 0xAD: return run_lda<detail::addressing_mode::absolute>();
+ case 0xAE: return run_ldx<detail::addressing_mode::absolute>();
+ case 0xAF: return run_lax<detail::addressing_mode::absolute>();
+ case 0xB0: return run_bcs<detail::addressing_mode::relative>();
+ case 0xB1: return run_lda<detail::addressing_mode::indirect_indexed>();
case 0xB2: return run_stp();
- case 0xB3: return run_lax<addressing_mode::indirect_indexed>();
- case 0xB4: return run_ldy<addressing_mode::zero_page_indexed_x>();
- case 0xB5: return run_lda<addressing_mode::zero_page_indexed_x>();
- case 0xB6: return run_ldx<addressing_mode::zero_page_indexed_y>();
- case 0xB7: return run_lax<addressing_mode::zero_page_indexed_y>();
+ case 0xB3: return run_lax<detail::addressing_mode::indirect_indexed>();
+ case 0xB4: return run_ldy<detail::addressing_mode::zero_page_indexed_x>();
+ case 0xB5: return run_lda<detail::addressing_mode::zero_page_indexed_x>();
+ case 0xB6: return run_ldx<detail::addressing_mode::zero_page_indexed_y>();
+ case 0xB7: return run_lax<detail::addressing_mode::zero_page_indexed_y>();
case 0xB8: return run_clv();
- case 0xB9: return run_lda<addressing_mode::absolute_indexed_y>();
+ case 0xB9: return run_lda<detail::addressing_mode::absolute_indexed_y>();
case 0xBA: return run_tsx();
- case 0xBB: return run_las<addressing_mode::absolute_indexed_y>();
- case 0xBC: return run_ldy<addressing_mode::absolute_indexed_x>();
- case 0xBD: return run_lda<addressing_mode::absolute_indexed_x>();
- case 0xBE: return run_ldx<addressing_mode::absolute_indexed_y>();
- case 0xBF: return run_lax<addressing_mode::absolute_indexed_y>();
- case 0xC0: return run_cpy<addressing_mode::immediate>();
- case 0xC1: return run_cmp<addressing_mode::indexed_indirect>();
- case 0xC2: return run_nop<addressing_mode::immediate>();
- case 0xC3: return run_dcp<addressing_mode::indexed_indirect>();
- case 0xC4: return run_cpy<addressing_mode::zero_page>();
- case 0xC5: return run_cmp<addressing_mode::zero_page>();
- case 0xC6: return run_dec<addressing_mode::zero_page>();
- case 0xC7: return run_dcp<addressing_mode::zero_page>();
+ case 0xBB: return run_las<detail::addressing_mode::absolute_indexed_y>();
+ case 0xBC: return run_ldy<detail::addressing_mode::absolute_indexed_x>();
+ case 0xBD: return run_lda<detail::addressing_mode::absolute_indexed_x>();
+ case 0xBE: return run_ldx<detail::addressing_mode::absolute_indexed_y>();
+ case 0xBF: return run_lax<detail::addressing_mode::absolute_indexed_y>();
+ case 0xC0: return run_cpy<detail::addressing_mode::immediate>();
+ case 0xC1: return run_cmp<detail::addressing_mode::indexed_indirect>();
+ case 0xC2: return run_nop<detail::addressing_mode::immediate>();
+ case 0xC3: return run_dcp<detail::addressing_mode::indexed_indirect>();
+ case 0xC4: return run_cpy<detail::addressing_mode::zero_page>();
+ case 0xC5: return run_cmp<detail::addressing_mode::zero_page>();
+ case 0xC6: return run_dec<detail::addressing_mode::zero_page>();
+ case 0xC7: return run_dcp<detail::addressing_mode::zero_page>();
case 0xC8: return run_iny();
- case 0xC9: return run_cmp<addressing_mode::immediate>();
+ case 0xC9: return run_cmp<detail::addressing_mode::immediate>();
case 0xCA: return run_dex();
- case 0xCB: return run_axs<addressing_mode::immediate>();
- case 0xCC: return run_cpy<addressing_mode::absolute>();
- case 0xCD: return run_cmp<addressing_mode::absolute>();
- case 0xCE: return run_dec<addressing_mode::absolute>();
- case 0xCF: return run_dcp<addressing_mode::absolute>();
- case 0xD0: return run_bne<addressing_mode::relative>();
- case 0xD1: return run_cmp<addressing_mode::indirect_indexed>();
+ case 0xCB: return run_axs<detail::addressing_mode::immediate>();
+ case 0xCC: return run_cpy<detail::addressing_mode::absolute>();
+ case 0xCD: return run_cmp<detail::addressing_mode::absolute>();
+ case 0xCE: return run_dec<detail::addressing_mode::absolute>();
+ case 0xCF: return run_dcp<detail::addressing_mode::absolute>();
+ case 0xD0: return run_bne<detail::addressing_mode::relative>();
+ case 0xD1: return run_cmp<detail::addressing_mode::indirect_indexed>();
case 0xD2: return run_stp();
- case 0xD3: return run_dcp<addressing_mode::indirect_indexed>();
- case 0xD4: return run_nop<addressing_mode::zero_page_indexed_x>();
- case 0xD5: return run_cmp<addressing_mode::zero_page_indexed_x>();
- case 0xD6: return run_dec<addressing_mode::zero_page_indexed_x>();
- case 0xD7: return run_dcp<addressing_mode::zero_page_indexed_x>();
+ case 0xD3: return run_dcp<detail::addressing_mode::indirect_indexed>();
+ case 0xD4: return run_nop<detail::addressing_mode::zero_page_indexed_x>();
+ case 0xD5: return run_cmp<detail::addressing_mode::zero_page_indexed_x>();
+ case 0xD6: return run_dec<detail::addressing_mode::zero_page_indexed_x>();
+ case 0xD7: return run_dcp<detail::addressing_mode::zero_page_indexed_x>();
case 0xD8: return run_cld();
- case 0xD9: return run_cmp<addressing_mode::absolute_indexed_y>();
+ case 0xD9: return run_cmp<detail::addressing_mode::absolute_indexed_y>();
case 0xDA: return run_nop();
- case 0xDB: return run_dcp<addressing_mode::absolute_indexed_y>();
- case 0xDC: return run_nop<addressing_mode::absolute_indexed_x>();
- case 0xDD: return run_cmp<addressing_mode::absolute_indexed_x>();
- case 0xDE: return run_dec<addressing_mode::absolute_indexed_x>();
- case 0xDF: return run_dcp<addressing_mode::absolute_indexed_x>();
- case 0xE0: return run_cpx<addressing_mode::immediate>();
- case 0xE1: return run_sbc<addressing_mode::indexed_indirect>();
- case 0xE2: return run_nop<addressing_mode::immediate>();
- case 0xE3: return run_isc<addressing_mode::indexed_indirect>();
- case 0xE4: return run_cpx<addressing_mode::zero_page>();
- case 0xE5: return run_sbc<addressing_mode::zero_page>();
- case 0xE6: return run_inc<addressing_mode::zero_page>();
- case 0xE7: return run_isc<addressing_mode::zero_page>();
+ case 0xDB: return run_dcp<detail::addressing_mode::absolute_indexed_y>();
+ case 0xDC: return run_nop<detail::addressing_mode::absolute_indexed_x>();
+ case 0xDD: return run_cmp<detail::addressing_mode::absolute_indexed_x>();
+ case 0xDE: return run_dec<detail::addressing_mode::absolute_indexed_x>();
+ case 0xDF: return run_dcp<detail::addressing_mode::absolute_indexed_x>();
+ case 0xE0: return run_cpx<detail::addressing_mode::immediate>();
+ case 0xE1: return run_sbc<detail::addressing_mode::indexed_indirect>();
+ case 0xE2: return run_nop<detail::addressing_mode::immediate>();
+ case 0xE3: return run_isc<detail::addressing_mode::indexed_indirect>();
+ case 0xE4: return run_cpx<detail::addressing_mode::zero_page>();
+ case 0xE5: return run_sbc<detail::addressing_mode::zero_page>();
+ case 0xE6: return run_inc<detail::addressing_mode::zero_page>();
+ case 0xE7: return run_isc<detail::addressing_mode::zero_page>();
case 0xE8: return run_inx();
- case 0xE9: return run_sbc<addressing_mode::immediate>();
+ case 0xE9: return run_sbc<detail::addressing_mode::immediate>();
case 0xEA: return run_nop();
- case 0xEB: return run_sbc<addressing_mode::immediate>();
- case 0xEC: return run_cpx<addressing_mode::absolute>();
- case 0xED: return run_sbc<addressing_mode::absolute>();
- case 0xEE: return run_inc<addressing_mode::absolute>();
- case 0xEF: return run_isc<addressing_mode::absolute>();
- case 0xF0: return run_beq<addressing_mode::relative>();
- case 0xF1: return run_sbc<addressing_mode::indirect_indexed>();
+ case 0xEB: return run_sbc<detail::addressing_mode::immediate>();
+ case 0xEC: return run_cpx<detail::addressing_mode::absolute>();
+ case 0xED: return run_sbc<detail::addressing_mode::absolute>();
+ case 0xEE: return run_inc<detail::addressing_mode::absolute>();
+ case 0xEF: return run_isc<detail::addressing_mode::absolute>();
+ case 0xF0: return run_beq<detail::addressing_mode::relative>();
+ case 0xF1: return run_sbc<detail::addressing_mode::indirect_indexed>();
case 0xF2: return run_stp();
- case 0xF3: return run_isc<addressing_mode::indirect_indexed>();
- case 0xF4: return run_nop<addressing_mode::zero_page_indexed_x>();
- case 0xF5: return run_sbc<addressing_mode::zero_page_indexed_x>();
- case 0xF6: return run_inc<addressing_mode::zero_page_indexed_x>();
- case 0xF7: return run_isc<addressing_mode::zero_page_indexed_x>();
+ case 0xF3: return run_isc<detail::addressing_mode::indirect_indexed>();
+ case 0xF4: return run_nop<detail::addressing_mode::zero_page_indexed_x>();
+ case 0xF5: return run_sbc<detail::addressing_mode::zero_page_indexed_x>();
+ case 0xF6: return run_inc<detail::addressing_mode::zero_page_indexed_x>();
+ case 0xF7: return run_isc<detail::addressing_mode::zero_page_indexed_x>();
case 0xF8: return run_sed();
- case 0xF9: return run_sbc<addressing_mode::absolute_indexed_y>();
+ case 0xF9: return run_sbc<detail::addressing_mode::absolute_indexed_y>();
case 0xFA: return run_nop();
- case 0xFB: return run_isc<addressing_mode::absolute_indexed_y>();
- case 0xFC: return run_nop<addressing_mode::absolute_indexed_x>();
- case 0xFD: return run_sbc<addressing_mode::absolute_indexed_x>();
- case 0xFE: return run_inc<addressing_mode::absolute_indexed_x>();
- case 0xFF: return run_isc<addressing_mode::absolute_indexed_x>();
+ case 0xFB: return run_isc<detail::addressing_mode::absolute_indexed_y>();
+ case 0xFC: return run_nop<detail::addressing_mode::absolute_indexed_x>();
+ case 0xFD: return run_sbc<detail::addressing_mode::absolute_indexed_x>();
+ case 0xFE: return run_inc<detail::addressing_mode::absolute_indexed_x>();
+ case 0xFF: return run_isc<detail::addressing_mode::absolute_indexed_x>();
default: return status::error_unsupported_instruction;
}
}
@@ -325,20 +325,20 @@ namespace nes::sys
// Instructions
// -----------------------------------------------------------------------------------------------------------------
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_brk() -> status
{
// BRK: Break
- fetch_operand<Mode>();
+ detail::fetch_operand<Mode>(*this);
execute_interrupt(address{ 0xFFFE });
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_ora() -> status
{
// ORA: Logical Inclusive OR
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
eval_ora(operand.read());
current_cycles_ += operand.get_cycles();
return status::success;
@@ -349,11 +349,11 @@ namespace nes::sys
return status::error_unsupported_instruction;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_slo() -> status
{
// SLO: ASL + ORA
- auto operand = fetch_operand<Mode>(force_page_crossing::yes);
+ auto operand = detail::fetch_operand<Mode>(*this, detail::force_page_crossing::yes);
auto const tmp = eval_asl(operand.read());
operand.write(tmp);
eval_ora(tmp);
@@ -361,11 +361,11 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_nop() -> status
{
// NOP: NOP
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
current_cycles_ += operand.get_cycles();
return status::success;
}
@@ -385,28 +385,28 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_asl() -> status
{
// ASL: Arithmetic Shift Left
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
operand.write(eval_asl(operand.read()));
- current_cycles_ += shift_cycle_count<Mode>();
+ current_cycles_ += detail::shift_cycle_count<Mode>();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_anc() -> status
{
// ANC: AND #i + copy N to C
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
eval_and(operand.read());
registers_.p.set_c(registers_.p.get_n());
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_bpl() -> status
{
// BPL: Break If Positive
@@ -422,35 +422,35 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_jsr() -> status
{
// JSR: Jump to Subroutine
- static_assert(Mode == addressing_mode::absolute, "JSR only supports absolute addressing.");
+ static_assert(Mode == detail::addressing_mode::absolute, "JSR only supports absolute addressing.");
push_stack16(registers_.pc + 1);
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
registers_.pc = operand.get_address().get_absolute();
current_cycles_ += cycle_count::from_cpu(6);
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_and() -> status
{
// AND: Logical AND
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
eval_and(operand.read());
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_rla() -> status
{
// RLA: ROL + AND
- auto operand = fetch_operand<Mode>(force_page_crossing::yes);
+ auto operand = detail::fetch_operand<Mode>(*this, detail::force_page_crossing::yes);
auto const tmp = eval_rol(operand.read());
operand.write(tmp);
eval_and(tmp);
@@ -458,11 +458,11 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_bit() -> status
{
// BIT: Bit Test
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
auto const arg = operand.read();
auto const res = (registers_.a & arg) != 0;
registers_.p.set_z(res == 0);
@@ -472,14 +472,14 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_rol() -> status
{
// ROR: Rotate Left
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
auto const result = eval_rol(operand.read());
operand.write(result);
- current_cycles_ += shift_cycle_count<Mode>();
+ current_cycles_ += detail::shift_cycle_count<Mode>();
return status::success;
}
@@ -491,7 +491,7 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_bmi() -> status
{
branch<Mode>(registers_.p.get_n());
@@ -515,21 +515,21 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_eor() -> status
{
// EOR: Exclusive OR
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
eval_eor(operand.read());
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_sre() -> status
{
// SRE: LSR + EOR
- auto operand = fetch_operand<Mode>(force_page_crossing::yes);
+ auto operand = detail::fetch_operand<Mode>(*this, detail::force_page_crossing::yes);
auto const tmp = eval_lsr(operand.read());
operand.write(tmp);
eval_eor(tmp);
@@ -537,25 +537,25 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_lsr() -> status
{
// LSR: Logical Shift Right
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
auto const old_val = operand.read();
auto const new_val = static_cast<u8>(old_val >> 1);
operand.write(new_val);
registers_.p.set_c((old_val & 0x1) != 0);
update_zn(new_val);
- current_cycles_ += shift_cycle_count<Mode>();
+ current_cycles_ += detail::shift_cycle_count<Mode>();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_alr() -> status
{
// ALR: AND #i + LSR A
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
eval_and(operand.read());
registers_.a = eval_lsr(registers_.a);
current_cycles_ += operand.get_cycles();
@@ -570,17 +570,17 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_jmp() -> status
{
// JMP: Jump
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
registers_.pc = operand.get_address().get_absolute();
- current_cycles_ += jump_cycle_count<Mode>();
+ current_cycles_ += detail::jump_cycle_count<Mode>();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_bvc() -> status
{
// BVC: Branch If Overflow Clear
@@ -605,21 +605,21 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_adc() -> status
{
// ADC: Add With Carry
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
eval_adc(operand.read());
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_rra() -> status
{
// RRA: ROR + ADC
- auto operand = fetch_operand<Mode>(force_page_crossing::yes);
+ auto operand = detail::fetch_operand<Mode>(*this, detail::force_page_crossing::yes);
auto const tmp = eval_ror(operand.read());
operand.write(tmp);
eval_adc(tmp);
@@ -627,18 +627,18 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_ror() -> status
{
// ROR: Rotate Right
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
auto const result = eval_ror(operand.read());
operand.write(result);
- current_cycles_ += shift_cycle_count<Mode>();
+ current_cycles_ += detail::shift_cycle_count<Mode>();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_arr() -> status
{
// ARR: AND #i + ROR A but with different flags
@@ -655,7 +655,7 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_bvs() -> status
{
// BVS: Branch If Overflow Set
@@ -671,17 +671,17 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_sta() -> status
{
// STA: Store Accumulator
- auto operand = fetch_operand<Mode>(force_page_crossing::yes);
+ auto operand = detail::fetch_operand<Mode>(*this, detail::force_page_crossing::yes);
operand.write(registers_.a);
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_ahx() -> status
{
// AHX: ???
@@ -689,32 +689,32 @@ namespace nes::sys
return status::error_unsupported_instruction;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_sax() -> status
{
// SAX: AND A X
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
auto const result = static_cast<u8>(registers_.a & registers_.x);
operand.write(result);
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_sty() -> status
{
// STX: Store Y
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
operand.write(registers_.y);
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_stx() -> status
{
// STX: Store X
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
operand.write(registers_.x);
current_cycles_ += operand.get_cycles();
return status::success;
@@ -738,7 +738,7 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_xaa() -> status
{
// XAA: Depends on analog behavior.
@@ -746,7 +746,7 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_bcc() -> status
{
// BCC: Branch If Carry Clear
@@ -771,7 +771,7 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_tas() -> status
{
// TAS: ???
@@ -779,7 +779,7 @@ namespace nes::sys
return status::error_unsupported_instruction;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_shy() -> status
{
// SHY: ???
@@ -787,7 +787,7 @@ namespace nes::sys
return status::error_unsupported_instruction;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_shx() -> status
{
// SHY: ???
@@ -795,44 +795,44 @@ namespace nes::sys
return status::error_unsupported_instruction;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_ldy() -> status
{
// LDY: Load Y Register
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
registers_.y = operand.read();
update_zn(registers_.y);
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_lda() -> status
{
// LDA: Load Accumulator
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
registers_.a = operand.read();
update_zn(registers_.a);
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_ldx() -> status
{
// LDX: Load X Register
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
registers_.x = operand.read();
update_zn(registers_.x);
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_lax() -> status
{
// LAX: LDA + TAX
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
registers_.x = registers_.a = operand.read();
update_zn(registers_.a);
current_cycles_ += operand.get_cycles();
@@ -857,7 +857,7 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_bcs() -> status
{
// BCS: Branch If Carry Set
@@ -882,7 +882,7 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_las() -> status
{
// LAS: ???
@@ -890,17 +890,17 @@ namespace nes::sys
return status::error_unsupported_instruction;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_cpy() -> status
{
// CPY: Compare Y Register
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
eval_cmp(registers_.y, operand.read());
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_axs() -> status
{
// AXS: Set X to ((A AND X) - #value without borrow), updates NZC
@@ -908,21 +908,21 @@ namespace nes::sys
return status::error_unsupported_instruction;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_cmp() -> status
{
// CMP: Compare
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
eval_cmp(registers_.a, operand.read());
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_dcp() -> status
{
// DCP: DEC + CMP
- auto operand = fetch_operand<Mode>(force_page_crossing::yes);
+ auto operand = detail::fetch_operand<Mode>(*this, detail::force_page_crossing::yes);
auto const tmp = static_cast<u8>(operand.read() - 1);
operand.write(tmp);
eval_cmp(registers_.a, tmp);
@@ -930,16 +930,16 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_dec() -> status
{
// DEC: Decrement Memory
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
auto const old_val = read8(operand.get_address());
auto const new_val = static_cast<u8>(old_val - 1);
write8(operand.get_address(), new_val);
update_zn(new_val);
- current_cycles_ += inc_dec_cycle_count<Mode>();
+ current_cycles_ += detail::inc_dec_cycle_count<Mode>();
return status::success;
}
@@ -961,7 +961,7 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_bne() -> status
{
// BNE: Branch If Not Equal
@@ -977,31 +977,31 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_cpx() -> status
{
// CPX: Compare X Register
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
eval_cmp(registers_.x, operand.read());
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_sbc() -> status
{
// SBC: Subtract With Carry
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
eval_adc(~operand.read());
current_cycles_ += operand.get_cycles();
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_isc() -> status
{
// ISC: INC + SBC
- auto operand = fetch_operand<Mode>(force_page_crossing::yes);
+ auto operand = detail::fetch_operand<Mode>(*this, detail::force_page_crossing::yes);
auto const tmp = static_cast<u8>(operand.read() + 1);
operand.write(tmp);
eval_adc(~tmp);
@@ -1009,16 +1009,16 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_inc() -> status
{
// INC: Increment Memory
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
auto const old_val = read8(operand.get_address());
auto const new_val = static_cast<u8>(old_val + 1);
write8(operand.get_address(), new_val);
update_zn(new_val);
- current_cycles_ += inc_dec_cycle_count<Mode>();
+ current_cycles_ += detail::inc_dec_cycle_count<Mode>();
return status::success;
}
@@ -1031,7 +1031,7 @@ namespace nes::sys
return status::success;
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::run_beq() -> status
{
// BEQ: Branch If Equal
@@ -1098,12 +1098,12 @@ namespace nes::sys
registers_.p.set_n((value & 0x80) != 0);
}
- template<cpu::addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto cpu::branch(bool const condition) -> void
{
- static_assert(Mode == addressing_mode::relative, "Branch should only be used with relative operands.");
+ static_assert(Mode == detail::addressing_mode::relative, "Branch should only be used with relative operands.");
- auto operand = fetch_operand<Mode>();
+ auto operand = detail::fetch_operand<Mode>(*this);
if (condition)
{
registers_.pc = operand.get_address().get_absolute();
@@ -1210,127 +1210,131 @@ namespace nes::sys
// Operands
// -----------------------------------------------------------------------------------------------------------------
- //
- // See: https://www.nesdev.org/wiki/CPU_addressing_modes
- //
-
- template<cpu::addressing_mode Mode>
- auto cpu::fetch_operand(force_page_crossing const force_page_crossing) -> operand<Mode>
+ namespace detail
{
- auto addr = address{};
- auto cycles = cycle_count{};
- switch (Mode)
+ //
+ // See: https://www.nesdev.org/wiki/CPU_addressing_modes
+ //
+
+ template<addressing_mode Mode>
+ auto fetch_operand(cpu& cpu, force_page_crossing const force_page_crossing) -> operand<Mode>
{
- case addressing_mode::immediate: static_assert(Mode != addressing_mode::immediate);
- case addressing_mode::accumulator: static_assert(Mode != addressing_mode::accumulator);
- case addressing_mode::zero_page:
- {
- addr = address{ advance_pc8() };
- cycles = cycle_count::from_cpu(3);
- break;
- }
- case addressing_mode::absolute:
- {
- addr = address{ advance_pc16() };
- cycles = cycle_count::from_cpu(4);
- break;
- }
- case addressing_mode::relative:
- {
- auto const offset = static_cast<i8>(advance_pc8());
- auto const base = address{ registers_.pc };
- addr = address{ static_cast<u16>(registers_.pc + offset) };
- auto const page_crossing =
- base.get_page() != addr.get_page() || force_page_crossing == force_page_crossing::yes;
- cycles = cycle_count::from_cpu(page_crossing ? 4 : 3);
- break;
- }
- case addressing_mode::indirect:
- {
- auto const arg = address{ advance_pc16() };
- // Account for buggy indirect read: https://www.nesdev.org/wiki/Errata
- addr = arg.get_offset() == 0xFF
- ? address{ read8(address{ arg.get_page(), 0x00 }), read8(arg) }
- : address{ read16(arg) };
- cycles = cycle_count::from_cpu(6);
- break;
- }
- case addressing_mode::zero_page_indexed_x:
- {
- // PEEK((arg + X) % 256)
- addr = address{ 0x00, static_cast<u8>(advance_pc8() + registers_.x) };
- cycles = cycle_count::from_cpu(4);
- break;
- }
- case addressing_mode::zero_page_indexed_y:
- {
- // PEEK((arg + Y) % 256)
- addr = address{ 0x00, static_cast<u8>(advance_pc8() + registers_.y) };
- cycles = cycle_count::from_cpu(4);
- break;
- }
- case addressing_mode::absolute_indexed_x:
- {
- // PEEK(arg + X)
- auto const arg = address{ advance_pc16() };
- addr = arg + registers_.x;
- auto const page_crossing =
- addr.get_page() != arg.get_page() || force_page_crossing == force_page_crossing::yes;
- cycles = cycle_count::from_cpu(page_crossing ? 5 : 4);
- break;
- }
- case addressing_mode::absolute_indexed_y:
- {
- // PEEK(arg + Y)
- auto const arg = address{ advance_pc16() };
- addr = arg + registers_.y;
- auto const page_crossing =
- addr.get_page() != arg.get_page() || force_page_crossing == force_page_crossing::yes;
- cycles = cycle_count::from_cpu(page_crossing ? 5 : 4);
- break;
- }
- case addressing_mode::indexed_indirect:
- {
- // PEEK(PEEK((arg + X) % 256) + PEEK((arg + X + 1) % 256) * 256)
- auto const arg = advance_pc8();
- auto const page = read8(address{ 0x00, static_cast<u8>(arg + registers_.x + 1) });
- auto const offset = read8(address{ 0x00, static_cast<u8>(arg + registers_.x) });
- addr = address{ page, offset };
- cycles = cycle_count::from_cpu(6);
- break;
- }
- case addressing_mode::indirect_indexed:
+ auto addr = address{};
+ auto cycles = cycle_count{};
+
+ switch (Mode)
{
- // PEEK(PEEK(arg) + PEEK((arg + 1) % 256) * 256 + Y)
- auto const arg = advance_pc8();
- auto const page = read8(address{ 0x00, static_cast<u8>(arg + 1) });
- auto const offset = read8(address{ 0x00, static_cast<u8>(arg) });
- auto const base = address{ page, offset };
- addr = base + registers_.y;
- auto const page_crossing =
- addr.get_page() != base.get_page() || force_page_crossing == force_page_crossing::yes;
- cycles = cycle_count::from_cpu(page_crossing ? 6 : 5);
- break;
+ case addressing_mode::immediate: static_assert(Mode != addressing_mode::immediate);
+ case addressing_mode::accumulator: static_assert(Mode != addressing_mode::accumulator);
+ case addressing_mode::zero_page:
+ {
+ addr = address{ cpu.advance_pc8() };
+ cycles = cycle_count::from_cpu(3);
+ break;
+ }
+ case addressing_mode::absolute:
+ {
+ addr = address{ cpu.advance_pc16() };
+ cycles = cycle_count::from_cpu(4);
+ break;
+ }
+ case addressing_mode::relative:
+ {
+ auto const offset = static_cast<i8>(cpu.advance_pc8());
+ auto const base = address{ cpu.registers_.pc };
+ addr = address{ static_cast<u16>(cpu.registers_.pc + offset) };
+ auto const page_crossing =
+ base.get_page() != addr.get_page() || force_page_crossing == force_page_crossing::yes;
+ cycles = cycle_count::from_cpu(page_crossing ? 4 : 3);
+ break;
+ }
+ case addressing_mode::indirect:
+ {
+ auto const arg = address{ cpu.advance_pc16() };
+ // Account for buggy indirect read: https://www.nesdev.org/wiki/Errata
+ addr = arg.get_offset() == 0xFF
+ ? address{ cpu.read8(address{ arg.get_page(), 0x00 }), cpu.read8(arg) }
+ : address{ cpu.read16(arg) };
+ cycles = cycle_count::from_cpu(6);
+ break;
+ }
+ case addressing_mode::zero_page_indexed_x:
+ {
+ // PEEK((arg + X) % 256)
+ addr = address{ 0x00, static_cast<u8>(cpu.advance_pc8() + cpu.registers_.x) };
+ cycles = cycle_count::from_cpu(4);
+ break;
+ }
+ case addressing_mode::zero_page_indexed_y:
+ {
+ // PEEK((arg + Y) % 256)
+ addr = address{ 0x00, static_cast<u8>(cpu.advance_pc8() + cpu.registers_.y) };
+ cycles = cycle_count::from_cpu(4);
+ break;
+ }
+ case addressing_mode::absolute_indexed_x:
+ {
+ // PEEK(arg + X)
+ auto const arg = address{ cpu.advance_pc16() };
+ addr = arg + cpu.registers_.x;
+ auto const page_crossing =
+ addr.get_page() != arg.get_page() || force_page_crossing == force_page_crossing::yes;
+ cycles = cycle_count::from_cpu(page_crossing ? 5 : 4);
+ break;
+ }
+ case addressing_mode::absolute_indexed_y:
+ {
+ // PEEK(arg + Y)
+ auto const arg = address{ cpu.advance_pc16() };
+ addr = arg + cpu.registers_.y;
+ auto const page_crossing =
+ addr.get_page() != arg.get_page() || force_page_crossing == force_page_crossing::yes;
+ cycles = cycle_count::from_cpu(page_crossing ? 5 : 4);
+ break;
+ }
+ case addressing_mode::indexed_indirect:
+ {
+ // PEEK(PEEK((arg + X) % 256) + PEEK((arg + X + 1) % 256) * 256)
+ auto const arg = cpu.advance_pc8();
+ auto const page = cpu.read8(address{ 0x00, static_cast<u8>(arg + cpu.registers_.x + 1) });
+ auto const offset = cpu.read8(address{ 0x00, static_cast<u8>(arg + cpu.registers_.x) });
+ addr = address{ page, offset };
+ cycles = cycle_count::from_cpu(6);
+ break;
+ }
+ case addressing_mode::indirect_indexed:
+ {
+ // PEEK(PEEK(arg) + PEEK((arg + 1) % 256) * 256 + Y)
+ auto const arg = cpu.advance_pc8();
+ auto const page = cpu.read8(address{ 0x00, static_cast<u8>(arg + 1) });
+ auto const offset = cpu.read8(address{ 0x00, static_cast<u8>(arg) });
+ auto const base = address{ page, offset };
+ addr = base + cpu.registers_.y;
+ auto const page_crossing =
+ addr.get_page() != base.get_page() || force_page_crossing == force_page_crossing::yes;
+ cycles = cycle_count::from_cpu(page_crossing ? 6 : 5);
+ break;
+ }
}
- }
- return operand<Mode>{ *this, addr, cycles };
- }
+ return operand<Mode>{ cpu, addr, cycles };
+ }
- template<>
- auto cpu::fetch_operand<cpu::addressing_mode::accumulator>(force_page_crossing)
- -> operand<addressing_mode::accumulator>
- {
- return operand<addressing_mode::accumulator>{ *this };
- }
+ template<>
+ auto fetch_operand<addressing_mode::accumulator>(cpu& cpu, force_page_crossing)
+ -> operand<addressing_mode::accumulator>
+ {
+ return operand<addressing_mode::accumulator>{ cpu };
+ }
- template<>
- auto cpu::fetch_operand<cpu::addressing_mode::immediate>(force_page_crossing)
- -> operand<addressing_mode::immediate>
- {
- return operand<addressing_mode::immediate>{ advance_pc8() };
- }
+ template<>
+ auto fetch_operand<addressing_mode::immediate>(cpu& cpu, force_page_crossing)
+ -> operand<addressing_mode::immediate>
+ {
+ return operand<addressing_mode::immediate>{ cpu.advance_pc8() };
+ }
+ } // namespace detail
// -----------------------------------------------------------------------------------------------------------------
// Memory Access
@@ -1357,6 +1361,7 @@ namespace nes::sys
case 6: return ppu_.read_latch();
case 7: return ppu_.read_ppudata();
default: return 0x0;
+
}
#else
return 0x0;
diff --git a/lib/nes/sys/cpu.hh b/lib/nes/sys/cpu.hh
index 795039c..d9d0dd0 100644
--- a/lib/nes/sys/cpu.hh
+++ b/lib/nes/sys/cpu.hh
@@ -9,11 +9,47 @@
namespace nes::sys
{
class ppu;
+ class cpu;
class controller;
class cartridge;
+ namespace detail
+ {
+ enum class addressing_mode
+ {
+ accumulator, // A
+ immediate, // #v
+ zero_page, // d
+ absolute, // a
+ relative, // *+d
+ indirect, // (a)
+ zero_page_indexed_x, // d,x
+ zero_page_indexed_y, // d,y
+ absolute_indexed_x, // a,x
+ absolute_indexed_y, // a,y
+ indexed_indirect, // (d,x)
+ indirect_indexed, // (d),y
+ };
+
+ enum class force_page_crossing
+ {
+ no,
+ yes,
+ };
+
+ template<detail::addressing_mode Mode>
+ class operand;
+ template<detail::addressing_mode Mode>
+ auto fetch_operand(cpu&, force_page_crossing = force_page_crossing::no) -> operand<Mode>;
+ } // namespace detail
+
class cpu
{
+ template<detail::addressing_mode Mode>
+ friend class detail::operand;
+ template<detail::addressing_mode Mode>
+ friend auto detail::fetch_operand(cpu&, detail::force_page_crossing) -> detail::operand<Mode>;
+
static constexpr auto ram_size = u32{ 0x800 };
static constexpr auto stack_offset = address{ 0x100 };
@@ -55,80 +91,6 @@ namespace nes::sys
} p{};
} registers_{};
- enum class addressing_mode
- {
- accumulator, // A
- immediate, // #v
- zero_page, // d
- absolute, // a
- relative, // *+d
- indirect, // (a)
- zero_page_indexed_x, // d,x
- zero_page_indexed_y, // d,y
- absolute_indexed_x, // a,x
- absolute_indexed_y, // a,y
- indexed_indirect, // (d,x)
- indirect_indexed, // (d),y
- };
-
- enum class force_page_crossing
- {
- no,
- yes,
- };
-
- template<addressing_mode>
- class operand
- {
- cpu& cpu_;
- address address_;
- cycle_count cycles_;
-
- public:
- explicit operand(cpu& cpu, address const address, cycle_count const cycles)
- : cpu_{ cpu }
- , address_{ address }
- , cycles_{ cycles }
- {
- }
-
- auto read() -> u8 { return cpu_.read8(address_); }
- auto write(u8 const value) -> void { cpu_.write8(address_, value); }
- auto get_address() -> address { return address_; }
- auto get_cycles() -> cycle_count { return cycles_; }
- };
-
- template<>
- class operand<addressing_mode::accumulator>
- {
- cpu& cpu_;
-
- public:
- explicit operand(cpu& cpu)
- : cpu_{ cpu }
- {
- }
-
- auto read() -> u8 { return cpu_.registers_.a; }
- auto write(u8 const value) -> void { cpu_.registers_.a = value; }
- auto get_cycles() -> cycle_count { return cycle_count::from_cpu(2); }
- };
-
- template<>
- class operand<addressing_mode::immediate>
- {
- u8 value_{ 0 };
-
- public:
- explicit operand(u8 const value)
- : value_{ value }
- {
- }
-
- auto read() -> u8 { return value_; }
- auto get_cycles() -> cycle_count { return cycle_count::from_cpu(2); }
- };
-
public:
explicit cpu(ppu&, cartridge&, controller& controller_1, controller& controller_2);
@@ -159,7 +121,7 @@ namespace nes::sys
#define DEFINE_SIMPLE_INSTRUCTION(name) \
auto run_##name() -> status;
#define DEFINE_OPERAND_INSTRUCTION(name) \
- template<addressing_mode Mode> auto run_##name() -> status;
+ template<detail::addressing_mode Mode> auto run_##name() -> status;
DEFINE_OPERAND_INSTRUCTION(brk)
DEFINE_OPERAND_INSTRUCTION(ora)
@@ -250,7 +212,7 @@ namespace nes::sys
auto pop_stack8() -> u8;
auto pop_stack16() -> u16;
auto update_zn(u8 value) -> void;
- template<addressing_mode Mode>
+ template<detail::addressing_mode Mode>
auto branch(bool condition) -> void;
auto execute_interrupt(address) -> void;
@@ -265,9 +227,69 @@ namespace nes::sys
auto eval_cmp(u8 a, u8 b) -> void;
auto eval_plp() -> void;
auto eval_php() -> void;
+ };
+
+ namespace detail
+ {
+ template<addressing_mode>
+ class operand
+ {
+ cpu& cpu_;
+ address address_;
+ cycle_count cycles_;
+
+ public:
+ explicit operand(cpu& cpu, address const address, cycle_count const cycles)
+ : cpu_{ cpu }
+ , address_{ address }
+ , cycles_{ cycles }
+ {
+ }
+
+ auto read() -> u8 { return cpu_.read8(address_); }
+ auto write(u8 const value) -> void { cpu_.write8(address_, value); }
+ auto get_address() -> address { return address_; }
+ auto get_cycles() -> cycle_count { return cycles_; }
+ };
+
+ template<>
+ class operand<addressing_mode::accumulator>
+ {
+ cpu& cpu_;
+
+ public:
+ explicit operand(cpu& cpu)
+ : cpu_{ cpu }
+ {
+ }
+
+ auto read() -> u8 { return cpu_.registers_.a; }
+ auto write(u8 const value) -> void { cpu_.registers_.a = value; }
+ auto get_cycles() -> cycle_count { return cycle_count::from_cpu(2); }
+ };
+
+ template<>
+ class operand<addressing_mode::immediate>
+ {
+ u8 value_{ 0 };
+
+ public:
+ explicit operand(u8 const value)
+ : value_{ value }
+ {
+ }
- // Operands
+ auto read() -> u8 { return value_; }
+ auto get_cycles() -> cycle_count { return cycle_count::from_cpu(2); }
+ };
+ template<addressing_mode Mode>
+ auto fetch_operand(cpu&, force_page_crossing) -> operand<Mode>;
+ template<>
+ auto fetch_operand<addressing_mode::accumulator>(cpu&, force_page_crossing) -> operand<addressing_mode::accumulator>;
+ template<>
+ auto fetch_operand<addressing_mode::immediate>(cpu&, force_page_crossing) -> operand<addressing_mode::immediate>;
+
#define DEFINE_CYCLE_COUNT(name) \
template<addressing_mode Mode> static auto name##_cycle_count() -> cycle_count;
#define DEFINE_CYCLE_COUNT_INSTANCE(name, mode, value) \
@@ -292,12 +314,5 @@ namespace nes::sys
#undef DEFINE_CYCLE_COUNT
#undef DEFINE_CYCLE_COUNT_INSTANCE
-
- template<addressing_mode Mode>
- auto fetch_operand(force_page_crossing = force_page_crossing::no) -> operand<Mode>;
- template<>
- auto fetch_operand<addressing_mode::accumulator>(force_page_crossing) -> operand<addressing_mode::accumulator>;
- template<>
- auto fetch_operand<addressing_mode::immediate>(force_page_crossing) -> operand<addressing_mode::immediate>;
- };
+ } // namespace detail
} // namespace nes::sys \ No newline at end of file