diff options
| author | Markus Gerber <markus.gerber@fau.de> | 2025-02-06 20:41:37 +0100 |
|---|---|---|
| committer | Markus Gerber <markus.gerber@fau.de> | 2025-02-06 20:41:37 +0100 |
| commit | c02f8e99460ba07f90c486b9e7388a7ab9dff3bd (patch) | |
| tree | b1dc744191071f610a4a5adaa6db532a10149d67 | |
| parent | c4ab1532769de3196afe10a0b200f631cdc438b4 (diff) | |
made compatible with gcc
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | CMakeLists.txt | 4 | ||||
| -rw-r--r-- | lib/nes/sys/cpu.cc | 853 | ||||
| -rw-r--r-- | lib/nes/sys/cpu.hh | 185 |
4 files changed, 533 insertions, 511 deletions
@@ -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 |
