├── .gitignore ├── .gitmodules ├── .travis.yml ├── Cargo.toml ├── LICENSE-APACHE.txt ├── LICENSE-MIT.txt ├── README.md ├── emumisc ├── Cargo.toml └── src │ ├── bits.rs │ ├── indexing.rs │ ├── lib.rs │ ├── memory.rs │ ├── misc.rs │ └── wrapping.rs ├── mos6502 ├── Cargo.toml ├── roms │ ├── 6502_functional_test.bin │ ├── TTL6502.bin │ ├── bcd_verify.bin │ └── sources │ │ ├── 6502_functional_test.asm │ │ ├── TTL6502.asm │ │ └── bcd_verify.asm ├── src │ ├── generate_decoder.rb │ ├── lib.rs │ ├── mos6502_opcodes.dat │ ├── virtual_mos6502.rs │ └── virtual_mos6502_decoder.rs └── tests │ └── lib.rs ├── nes-testsuite ├── Cargo.toml ├── roms │ ├── apu_test │ │ ├── 1-len_ctr.nes │ │ ├── 2-len_table.nes │ │ ├── 3-irq_flag.nes │ │ ├── 4-jitter.nes │ │ ├── 5-len_timing.nes │ │ ├── 6-irq_flag_timing.nes │ │ ├── 7-dmc_basics.nes │ │ ├── 8-dmc_rates.nes │ │ ├── readme.txt │ │ └── source │ │ │ ├── 1-len_ctr.s │ │ │ ├── 2-len_table.s │ │ │ ├── 3-irq_flag.s │ │ │ ├── 4-jitter.s │ │ │ ├── 5-len_timing.s │ │ │ ├── 6-irq_flag_timing.s │ │ │ ├── 7-dmc_basics.s │ │ │ ├── 8-dmc_rates.s │ │ │ ├── common │ │ │ ├── apu_shell.inc │ │ │ ├── ascii.chr │ │ │ ├── build_rom.s │ │ │ ├── console.s │ │ │ ├── crc.s │ │ │ ├── delay.s │ │ │ ├── devcart.bin │ │ │ ├── macros.inc │ │ │ ├── neshw.inc │ │ │ ├── ppu.s │ │ │ ├── print.s │ │ │ ├── shell.inc │ │ │ ├── shell.s │ │ │ ├── shell_misc.s │ │ │ ├── sync_apu.s │ │ │ ├── sync_dmc.s │ │ │ ├── test_main_chans.s │ │ │ ├── testing.s │ │ │ └── text_out.s │ │ │ └── nes.cfg │ ├── blargg_apu_2005.07.30 │ │ ├── 01.len_ctr.nes │ │ ├── 02.len_table.nes │ │ ├── 03.irq_flag.nes │ │ ├── 04.clock_jitter.nes │ │ ├── 05.len_timing_mode0.nes │ │ ├── 06.len_timing_mode1.nes │ │ ├── 07.irq_flag_timing.nes │ │ ├── 08.irq_timing.nes │ │ ├── 09.reset_timing.nes │ │ ├── 10.len_halt_timing.nes │ │ ├── 11.len_reload_timing.nes │ │ ├── readme.txt │ │ ├── source │ │ │ ├── 01.len_ctr.asm │ │ │ ├── 02.len_table.asm │ │ │ ├── 03.irq_flag.asm │ │ │ ├── 04.clock_jitter.asm │ │ │ ├── 05.len_timing_mode0.asm │ │ │ ├── 06.len_timing_mode1.asm │ │ │ ├── 07.irq_flag_timing.asm │ │ │ ├── 08.irq_timing.asm │ │ │ ├── 09.reset_timing.asm │ │ │ ├── 10.len_halt_timing.asm │ │ │ ├── 11.len_reload_timing.asm │ │ │ ├── apu_util.asm │ │ │ └── prefix_apu.asm │ │ └── tests.txt │ ├── blargg_ppu_tests_2005.09.15b │ │ ├── palette_ram.nes │ │ ├── power_up_palette.nes │ │ ├── readme.txt │ │ ├── source │ │ │ ├── palette_ram.asm │ │ │ ├── power_up_palette.asm │ │ │ ├── prefix_ppu.asm │ │ │ ├── sprite_ram.asm │ │ │ ├── vbl_clear_time.asm │ │ │ └── vram_access.asm │ │ ├── sprite_ram.nes │ │ ├── vbl_clear_time.nes │ │ └── vram_access.nes │ ├── branch_timing_tests │ │ ├── 1.Branch_Basics.nes │ │ ├── 2.Backward_Branch.nes │ │ ├── 3.Forward_Branch.nes │ │ ├── readme.txt │ │ └── source │ │ │ ├── 1.Branch_Basics.a │ │ │ ├── 2.Backward_Branch.a │ │ │ ├── 3.Forward_Branch.a │ │ │ ├── console.a │ │ │ ├── debug.a │ │ │ ├── delays.a │ │ │ ├── ppu_util.a │ │ │ ├── prefix.a │ │ │ ├── runtime_rom.a │ │ │ ├── runtime_rom_common.a │ │ │ └── validation.a │ ├── cli_latency_tests │ │ ├── cli_latency.nes │ │ ├── readme.txt │ │ └── source │ │ │ ├── cli_latency.a │ │ │ ├── console.a │ │ │ ├── debug.a │ │ │ ├── delays.a │ │ │ ├── ppu_util.a │ │ │ ├── runtime_rom.a │ │ │ ├── runtime_rom_common.a │ │ │ └── validation.a │ ├── cpu_timing_test6 │ │ ├── cpu_timing_test.nes │ │ ├── readme.txt │ │ └── source │ │ │ ├── console.a │ │ │ ├── cpu_timing_test.asm │ │ │ ├── debug.a │ │ │ ├── delays.a │ │ │ ├── ppu_util.a │ │ │ ├── runtime_rom.a │ │ │ └── runtime_rom_common.a │ ├── dmc_dma_during_read4 │ │ ├── dma_2007_read.nes │ │ ├── dma_2007_write.nes │ │ ├── dma_4016_read.nes │ │ ├── double_2007_read.nes │ │ ├── read_write_2007.nes │ │ ├── readme.txt │ │ └── source │ │ │ ├── common │ │ │ ├── ascii.chr │ │ │ ├── common.inc │ │ │ ├── console.s │ │ │ ├── crc.s │ │ │ ├── delay.s │ │ │ ├── macros.inc │ │ │ ├── nes.inc │ │ │ ├── print.s │ │ │ ├── serial.s │ │ │ ├── shell.inc │ │ │ ├── sync_dmc.s │ │ │ └── testing.s │ │ │ ├── dma_2007_read.s │ │ │ ├── dma_2007_write.s │ │ │ ├── dma_4016_read.s │ │ │ ├── double_2007_read.s │ │ │ ├── nes.cfg │ │ │ └── read_write_2007.s │ ├── holy_diver_batman │ │ ├── 32k.sav │ │ ├── 8k.sav │ │ ├── M0_P32K_C8K_V.nes │ │ ├── M10_P128K_C64K_S8K.nes │ │ ├── M10_P128K_C64K_W8K.nes │ │ ├── M118_P128K_C64K.nes │ │ ├── M180_P128K_H.nes │ │ ├── M1_P128K.nes │ │ ├── M1_P128K_C128K.nes │ │ ├── M1_P128K_C128K_S8K.nes │ │ ├── M1_P128K_C128K_W8K.nes │ │ ├── M1_P128K_C32K.nes │ │ ├── M1_P128K_C32K_S8K.nes │ │ ├── M1_P128K_C32K_W8K.nes │ │ ├── M1_P512K_S32K.nes │ │ ├── M1_P512K_S8K.nes │ │ ├── M28_P512K.nes │ │ ├── M2_P128K_V.nes │ │ ├── M34_P128K_H.nes │ │ ├── M3_P32K_C32K_H.nes │ │ ├── M4_P128K.nes │ │ ├── M4_P256K_C256K.nes │ │ ├── M66_P64K_C16K_V.nes │ │ ├── M69_P128K_C64K_S8K.nes │ │ ├── M69_P128K_C64K_W8K.nes │ │ ├── M78.3_P128K_C64K.nes │ │ ├── M7_P128K.nes │ │ ├── M9_P128K_C64K.nes │ │ └── source │ │ │ ├── CHANGES.txt │ │ │ ├── README.txt │ │ │ ├── hdbm-master.nes │ │ │ ├── makefile │ │ │ ├── nes.ini │ │ │ ├── obj │ │ │ └── nes │ │ │ │ └── index.txt │ │ │ ├── src │ │ │ ├── bcd.s │ │ │ ├── beepcode.s │ │ │ ├── boardletter.s │ │ │ ├── drivers.s │ │ │ ├── loadchr.s │ │ │ ├── main.s │ │ │ ├── mapper_detect.s │ │ │ ├── mmc3drivers.s │ │ │ ├── mmcdrivers.s │ │ │ ├── morse.h │ │ │ ├── nes.h │ │ │ ├── pads.s │ │ │ ├── ppuclear.s │ │ │ ├── ram.h │ │ │ ├── wram.s │ │ │ └── wrongbanks.s │ │ │ ├── tilesets │ │ │ └── font8x5.png │ │ │ ├── tools │ │ │ ├── cvt8x5.py │ │ │ ├── make_roms.py │ │ │ └── pilbmp2nes.py │ │ │ └── zip.in │ ├── instr_misc │ │ ├── 01-abs_x_wrap.nes │ │ ├── 02-branch_wrap.nes │ │ ├── 03-dummy_reads.nes │ │ ├── 04-dummy_reads_apu.nes │ │ ├── readme.txt │ │ └── source │ │ │ ├── 01-abs_x_wrap.s │ │ │ ├── 02-branch_wrap.s │ │ │ ├── 03-dummy_reads.s │ │ │ ├── 04-dummy_reads_apu.s │ │ │ ├── common │ │ │ ├── ascii.chr │ │ │ ├── bootloader.bin │ │ │ ├── build_rom.s │ │ │ ├── console.s │ │ │ ├── crc.s │ │ │ ├── delay.s │ │ │ ├── macros.inc │ │ │ ├── neshw.inc │ │ │ ├── ppu.s │ │ │ ├── print.s │ │ │ ├── shell.inc │ │ │ ├── shell.s │ │ │ ├── shell_misc.s │ │ │ ├── testing.s │ │ │ └── text_out.s │ │ │ ├── nes.cfg │ │ │ └── readme.txt │ ├── instr_test-v5 │ │ ├── 01-basics.nes │ │ ├── 02-implied.nes │ │ ├── 03-immediate.nes │ │ ├── 04-zero_page.nes │ │ ├── 05-zp_xy.nes │ │ ├── 06-absolute.nes │ │ ├── 07-abs_xy.nes │ │ ├── 08-ind_x.nes │ │ ├── 09-ind_y.nes │ │ ├── 10-branches.nes │ │ ├── 11-stack.nes │ │ ├── 12-jmp_jsr.nes │ │ ├── 13-rts.nes │ │ ├── 14-rti.nes │ │ ├── 15-brk.nes │ │ ├── 16-special.nes │ │ ├── readme.txt │ │ └── source │ │ │ ├── 01-basics.s │ │ │ ├── 02-implied.s │ │ │ ├── 03-immediate.s │ │ │ ├── 04-zero_page.s │ │ │ ├── 05-zp_xy.s │ │ │ ├── 06-absolute.s │ │ │ ├── 07-abs_xy.s │ │ │ ├── 08-ind_x.s │ │ │ ├── 09-ind_y.s │ │ │ ├── 10-branches.s │ │ │ ├── 11-stack.s │ │ │ ├── 12-jmp_jsr.s │ │ │ ├── 13-rts.s │ │ │ ├── 14-rti.s │ │ │ ├── 15-brk.s │ │ │ ├── 16-special.s │ │ │ ├── common │ │ │ ├── ascii.chr │ │ │ ├── bootloader.bin │ │ │ ├── build_rom.s │ │ │ ├── console.s │ │ │ ├── crc.s │ │ │ ├── crc_fast.s │ │ │ ├── delay.s │ │ │ ├── instr_test.inc │ │ │ ├── instr_test_end.s │ │ │ ├── macros.inc │ │ │ ├── neshw.inc │ │ │ ├── ppu.s │ │ │ ├── print.s │ │ │ ├── shell.inc │ │ │ ├── shell.s │ │ │ ├── shell_misc.s │ │ │ ├── testing.s │ │ │ └── text_out.s │ │ │ ├── nes.cfg │ │ │ └── readme.txt │ ├── mmc3_irq_tests │ │ ├── 1.Clocking.nes │ │ ├── 2.Details.nes │ │ ├── 3.A12_clocking.nes │ │ ├── 4.Scanline_timing.nes │ │ ├── 5.MMC3_rev_A.nes │ │ ├── 6.MMC3_rev_B.nes │ │ ├── readme.txt │ │ └── source │ │ │ ├── 1.Clocking.asm │ │ │ ├── 2.Details.asm │ │ │ ├── 3.A12_clocking.asm │ │ │ ├── 4.Scanline_timing.asm │ │ │ ├── 5.MMC3_rev_A.asm │ │ │ ├── 6.MMC3_rev_B.asm │ │ │ ├── console.asm │ │ │ ├── debug.asm │ │ │ ├── delays.asm │ │ │ ├── ppu_sync.asm │ │ │ ├── ppu_util.asm │ │ │ ├── prefix_cpu.asm │ │ │ ├── prefix_mmc3.asm │ │ │ ├── prefix_mmc3_validation.asm │ │ │ ├── prefix_swap.asm │ │ │ ├── runtime_swapcart.asm │ │ │ └── validation.asm │ ├── oam_read │ │ ├── oam_read.nes │ │ ├── readme.txt │ │ └── source │ │ │ ├── common │ │ │ ├── ascii.chr │ │ │ ├── build_rom.s │ │ │ ├── console.s │ │ │ ├── crc.s │ │ │ ├── delay.s │ │ │ ├── devcart.bin │ │ │ ├── macros.inc │ │ │ ├── neshw.inc │ │ │ ├── ppu.s │ │ │ ├── print.s │ │ │ ├── shell.inc │ │ │ ├── shell.s │ │ │ ├── testing.s │ │ │ └── text_out.s │ │ │ ├── nes.cfg │ │ │ ├── oam_read.s │ │ │ └── readme.txt │ ├── sprdma_and_dmc_dma │ │ ├── readme.txt │ │ ├── source │ │ │ ├── common │ │ │ │ ├── ascii.chr │ │ │ │ ├── bin2dec_mini16.s │ │ │ │ ├── bootloader.bin │ │ │ │ ├── build_rom.s │ │ │ │ ├── code_timer.s │ │ │ │ ├── console.s │ │ │ │ ├── crc.s │ │ │ │ ├── delay.s │ │ │ │ ├── dma_timing.inc │ │ │ │ ├── dmc_timer.s │ │ │ │ ├── macros.inc │ │ │ │ ├── neshw.inc │ │ │ │ ├── ppu.s │ │ │ │ ├── print.s │ │ │ │ ├── shell.inc │ │ │ │ ├── shell.s │ │ │ │ ├── shell_misc.s │ │ │ │ ├── sync_dmc.s │ │ │ │ ├── testing.s │ │ │ │ └── text_out.s │ │ │ ├── nes.cfg │ │ │ └── sprdma_and_dmc_dma.s │ │ └── sprdma_and_dmc_dma.nes │ ├── sprite_hit_tests_2005.10.05 │ │ ├── 01.basics.nes │ │ ├── 02.alignment.nes │ │ ├── 03.corners.nes │ │ ├── 04.flip.nes │ │ ├── 05.left_clip.nes │ │ ├── 06.right_edge.nes │ │ ├── 07.screen_bottom.nes │ │ ├── 08.double_height.nes │ │ ├── 09.timing_basics.nes │ │ ├── 10.timing_order.nes │ │ ├── 11.edge_timing.nes │ │ ├── readme.txt │ │ └── source │ │ │ ├── 01.basics.asm │ │ │ ├── 02.alignment.asm │ │ │ ├── 03.corners.asm │ │ │ ├── 04.flip.asm │ │ │ ├── 05.left_clip.asm │ │ │ ├── 06.right_edge.asm │ │ │ ├── 07.screen_bottom.asm │ │ │ ├── 08.double_height.asm │ │ │ ├── 09.timing_basics.asm │ │ │ ├── 10.timing_order.asm │ │ │ ├── 11.edge_timing.asm │ │ │ ├── prefix_sprite_hit.a │ │ │ └── runtime │ │ │ ├── console.a │ │ │ ├── debug.a │ │ │ ├── delays.a │ │ │ ├── ppu_sync.a │ │ │ ├── ppu_util.a │ │ │ ├── prefix_ppu.a │ │ │ ├── runtime_rom.a │ │ │ ├── runtime_rom_common.a │ │ │ └── validation.a │ ├── sprite_hit_timing │ │ ├── source │ │ │ └── sprite_hit_timing.asm │ │ └── sprite_hit_timing.nes │ ├── sprite_overflow_tests │ │ ├── 1.Basics.nes │ │ ├── 2.Details.nes │ │ ├── 3.Timing.nes │ │ ├── 4.Obscure.nes │ │ ├── 5.Emulator.nes │ │ ├── readme.txt │ │ └── source │ │ │ ├── 1.Basics.a │ │ │ ├── 2.Details.a │ │ │ ├── 3.Timing.a │ │ │ ├── 4.Obscure.a │ │ │ ├── 5.Emulator.a │ │ │ ├── console.a │ │ │ ├── debug.a │ │ │ ├── delays.a │ │ │ ├── ppu_sync.a │ │ │ ├── ppu_util.a │ │ │ ├── prefix.a │ │ │ ├── prefix_ppu.a │ │ │ ├── runtime_rom.a │ │ │ ├── runtime_rom_common.a │ │ │ └── validation.a │ └── vbl_nmi_timing │ │ ├── 1.frame_basics.nes │ │ ├── 2.vbl_timing.nes │ │ ├── 3.even_odd_frames.nes │ │ ├── 4.vbl_clear_timing.nes │ │ ├── 5.nmi_suppression.nes │ │ ├── 6.nmi_disable.nes │ │ ├── 7.nmi_timing.nes │ │ ├── readme.txt │ │ └── source │ │ ├── 1.frame_basics.a │ │ ├── 2.vbl_timing.a │ │ ├── 3.even_odd_frames.a │ │ ├── 4.vbl_clear_timing.a │ │ ├── 5.nmi_suppression.a │ │ ├── 6.nmi_disable.a │ │ ├── 7.nmi_timing.a │ │ └── support │ │ ├── chr.bin │ │ ├── console.a │ │ ├── debug.a │ │ ├── delays.a │ │ ├── ppu_sync.a │ │ ├── ppu_util.a │ │ ├── prefix_ppu.a │ │ ├── runtime_rom.a │ │ ├── runtime_rom_common.a │ │ └── validation.a ├── src │ ├── generate.rb │ ├── harness.rs │ ├── lib.rs │ └── tests.rs └── testcases │ ├── apu_test │ ├── 1-len_ctr.json │ ├── 2-len_table.json │ ├── 3-irq_flag.json │ ├── 4-jitter.json │ ├── 5-len_timing.json │ ├── 6-irq_flag_timing.json │ ├── 7-dmc_basics.json │ └── 8-dmc_rates.json │ ├── blargg_apu_2005.07.30 │ ├── 01.len_ctr.json │ ├── 02.len_table.json │ ├── 03.irq_flag.json │ ├── 04.clock_jitter.json │ ├── 05.len_timing_mode0.json │ ├── 06.len_timing_mode1.json │ └── 07.irq_flag_timing.json │ ├── blargg_ppu_tests_2005.09.15b │ ├── palette_ram.json │ ├── vbl_clear_time.json │ └── vram_access.json │ ├── branch_timing_tests │ ├── 1.Branch_Basics.json │ ├── 2.Backward_Branch.json │ └── 3.Forward_Branch.json │ ├── dmc_dma_during_read4 │ └── read_write_2007.json │ ├── holy_diver_batman │ └── M1_P128K_C128K_W8K.json │ ├── instr_misc │ ├── 01-abs_x_wrap.json │ ├── 02-branch_wrap.json │ └── 03-dummy_reads.json │ ├── oam_read │ └── oam_read.json │ ├── sprite_hit_tests_2005.10.05 │ ├── 01.basics.json │ ├── 02.alignment.json │ ├── 03.corners.json │ ├── 04.flip.json │ ├── 05.left_clip.json │ ├── 06.right_edge.json │ ├── 07.screen_bottom.json │ ├── 08.double_height.json │ ├── 09.timing_basics.json │ ├── 10.timing_order.json │ └── 11.edge_timing.json │ ├── sprite_hit_timing │ └── sprite_hit_timing.json │ └── vbl_nmi_timing │ ├── 1.frame_basics.json │ ├── 2.vbl_timing.json │ ├── 3.even_odd_frames.json │ ├── 4.vbl_clear_timing.json │ ├── 5.nmi_suppression.json │ ├── 6.nmi_disable.json │ └── 7.nmi_timing.json ├── nes ├── Cargo.toml ├── data │ └── FBX-Final.pal └── src │ ├── dma.rs │ ├── filter.rs │ ├── float_native.rs │ ├── float_softfloat.rs │ ├── generate_ppu.rb │ ├── generic_mapper.rs │ ├── lib.rs │ ├── mapper_axrom.rs │ ├── mapper_mmc1.rs │ ├── mapper_unrom512.rs │ ├── mapper_uxrom.rs │ ├── mappers.rs │ ├── memory_map.rs │ ├── orphan.rs │ ├── rom.rs │ ├── rp2c02.rs │ ├── rp2c02_scheduler.rs │ ├── rp2c02_scheduling.dat │ ├── testsuite.rs │ ├── virtual_apu.rs │ └── virtual_nes.rs ├── pinky-devui ├── Cargo.toml └── src │ ├── frame_limiter.rs │ ├── main.rs │ ├── renderer.rs │ └── user_interface.rs ├── pinky-libretro ├── Cargo.toml └── src │ └── lib.rs ├── pinky-web ├── Cargo.toml ├── README.md ├── Web.toml ├── src │ └── main.rs └── static │ ├── css │ └── normalize.css │ ├── index.html │ └── roms │ ├── alter_ego.nes │ ├── cheril_the_goddess.nes │ ├── dushlan.nes │ ├── index.json │ ├── lawn_mower.nes │ ├── mad_wizard.nes │ ├── micro_knight_4_v1_02.nes │ ├── nebs_n_debs_2_15_2017.nes │ ├── owlia.nes │ ├── streemerz_v02.nes │ ├── super_painter_1_0.nes │ ├── tiger_jenny.nes │ └── yun.nes └── rp2c02-testsuite ├── Cargo.toml ├── build.rs ├── generator ├── common.js ├── generate_current_address_during_background_rendering.js ├── generate_current_address_during_sprite_rendering.js ├── generate_current_address_during_sprite_rendering_without_sprites.js ├── generate_current_address_when_not_rendering.js ├── generate_vram_access_after_scrolling.js ├── generate_vram_access_during_background_rendering.js ├── generate_vram_access_during_sprite_rendering.js ├── generate_vram_access_during_sprite_rendering_double_height.js ├── generate_vram_access_during_sprite_rendering_out_of_range.js └── generate_vram_access_during_sprite_rendering_without_sprites.js └── src ├── lib.rs └── tests ├── mod.rs ├── test_current_address_during_background_rendering.rs ├── test_current_address_during_sprite_rendering.rs ├── test_current_address_during_sprite_rendering_without_sprites.rs ├── test_current_address_when_not_rendering.rs ├── test_vram_access_after_scrolling.rs ├── test_vram_access_during_background_rendering.rs ├── test_vram_access_during_sprite_rendering.rs ├── test_vram_access_during_sprite_rendering_double_height.rs ├── test_vram_access_during_sprite_rendering_without_sprites.rs └── test_vram_access_sprite_rendering_out_of_range.rs /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.toml 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "rp2c02-testsuite/generator/phantom2c02"] 2 | path = rp2c02-testsuite/generator/phantom2c02 3 | url = https://github.com/koute/phantom2c02.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | 7 | matrix: 8 | allow_failures: 9 | - rust: nightly 10 | 11 | script: 12 | - cd emumisc 13 | - cargo test --verbose 14 | - cd ../mos6502 15 | - cargo test --verbose 16 | - cd ../nes 17 | - cargo test --verbose 18 | - cd ../pinky-libretro 19 | - cargo build --verbose 20 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "emumisc", 4 | "mos6502", 5 | "nes", 6 | "nes-testsuite", 7 | "pinky-devui", 8 | "pinky-libretro", 9 | "pinky-web", 10 | "rp2c02-testsuite" 11 | ] 12 | 13 | [profile.test] 14 | opt-level = 2 15 | -------------------------------------------------------------------------------- /LICENSE-MIT.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Jan Bujak 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /emumisc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "emumisc" 3 | version = "0.1.0" 4 | authors = ["Jan Bujak "] 5 | 6 | [dependencies] 7 | "unreachable" = "0.1" -------------------------------------------------------------------------------- /emumisc/src/memory.rs: -------------------------------------------------------------------------------- 1 | use core::ptr; 2 | use core::slice; 3 | use core::mem; 4 | use alloc::boxed::Box; 5 | use alloc::vec::Vec; 6 | 7 | #[inline] 8 | pub fn as_bytes< T: Copy >( array: &[T] ) -> &[u8] { 9 | unsafe { 10 | slice::from_raw_parts( mem::transmute( array.as_ptr() ), mem::size_of::() * array.len() ) 11 | } 12 | } 13 | 14 | #[inline] 15 | pub fn allocate_slice< T: Default + Copy + Sized >( size: usize ) -> Box< [T] > { 16 | let mut vector = Vec::with_capacity( size ); 17 | unsafe { 18 | vector.set_len( size ); 19 | } 20 | 21 | for p in vector.iter_mut() { 22 | *p = T::default(); 23 | } 24 | 25 | vector.into_boxed_slice() 26 | } 27 | 28 | // Since copy_memory got deprecated and copy_from_slice is still unstable. 29 | #[inline] 30 | pub fn copy_memory( src: &[u8], dst: &mut [u8] ) { 31 | let length = src.len(); 32 | assert!( dst.len() >= length ); 33 | 34 | unsafe { 35 | ptr::copy_nonoverlapping( src.as_ptr(), dst.as_mut_ptr(), length ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /emumisc/src/misc.rs: -------------------------------------------------------------------------------- 1 | pub use unreachable::unreachable as unreachable; 2 | 3 | #[macro_export] 4 | macro_rules! fast_unreachable { 5 | () => ( 6 | if cfg!( debug_assertions ) { 7 | unreachable!(); 8 | } else { 9 | $crate::unreachable(); 10 | } 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /emumisc/src/wrapping.rs: -------------------------------------------------------------------------------- 1 | pub trait WrappingExtra { 2 | fn wrapping_inc( &mut self ); 3 | fn wrapping_dec( &mut self ); 4 | } 5 | 6 | macro_rules! impl_wrapping_extra { 7 | ($typ:ty) => ( 8 | impl WrappingExtra for $typ { 9 | #[inline(always)] 10 | fn wrapping_inc( &mut self ) { 11 | *self = self.wrapping_add( 1 ); 12 | } 13 | 14 | #[inline(always)] 15 | fn wrapping_dec( &mut self ) { 16 | *self = self.wrapping_sub( 1 ); 17 | } 18 | } 19 | ) 20 | } 21 | 22 | impl_wrapping_extra!(u8); 23 | impl_wrapping_extra!(u16); 24 | impl_wrapping_extra!(u32); 25 | -------------------------------------------------------------------------------- /mos6502/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mos6502" 3 | version = "0.1.0" 4 | authors = ["Jan Bujak "] 5 | 6 | [dependencies] 7 | bitflags = "2.4.0" 8 | 9 | [dependencies.emumisc] 10 | path = "../emumisc" 11 | 12 | [features] 13 | default = ["std"] 14 | std = [] 15 | -------------------------------------------------------------------------------- /mos6502/roms/6502_functional_test.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/mos6502/roms/6502_functional_test.bin -------------------------------------------------------------------------------- /mos6502/roms/TTL6502.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/mos6502/roms/TTL6502.bin -------------------------------------------------------------------------------- /mos6502/roms/bcd_verify.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/mos6502/roms/bcd_verify.bin -------------------------------------------------------------------------------- /mos6502/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | #![allow(non_snake_case)] 4 | #![allow(non_upper_case_globals)] 5 | 6 | #[cfg(feature = "std")] 7 | extern crate std as core; 8 | 9 | #[macro_use] 10 | extern crate emumisc; 11 | 12 | #[macro_use] 13 | extern crate bitflags; 14 | 15 | mod virtual_mos6502_decoder; 16 | mod virtual_mos6502; 17 | 18 | pub use virtual_mos6502::{Interface, State, Context, Address, EmulationError, EmulationStatus, decode_instruction}; 19 | -------------------------------------------------------------------------------- /nes-testsuite/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nes-testsuite" 3 | version = "0.1.0" 4 | authors = ["Jan Bujak "] 5 | 6 | [dependencies] 7 | "md5" = "0.1" 8 | -------------------------------------------------------------------------------- /nes-testsuite/roms/apu_test/1-len_ctr.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/apu_test/1-len_ctr.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/apu_test/2-len_table.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/apu_test/2-len_table.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/apu_test/3-irq_flag.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/apu_test/3-irq_flag.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/apu_test/4-jitter.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/apu_test/4-jitter.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/apu_test/5-len_timing.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/apu_test/5-len_timing.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/apu_test/6-irq_flag_timing.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/apu_test/6-irq_flag_timing.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/apu_test/7-dmc_basics.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/apu_test/7-dmc_basics.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/apu_test/8-dmc_rates.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/apu_test/8-dmc_rates.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/apu_test/source/2-len_table.s: -------------------------------------------------------------------------------- 1 | ; Verifies all length table entries 2 | 3 | .include "apu_shell.inc" 4 | 5 | main: test_main_chans test 6 | jmp tests_passed 7 | 8 | test: loop_n_times test_entry,32 9 | rts 10 | 11 | test_entry: 12 | tay 13 | setb SNDMODE,0 14 | 15 | ; Load 16 | tya 17 | asl a 18 | asl a 19 | asl a 20 | ldx chan_off 21 | sta $4003,x 22 | 23 | ; Verify 24 | lda table,y 25 | tax 26 | dex 27 | : setb SNDMODE,$C0 ; clock length counter 28 | dex 29 | bne :- 30 | jsr len_should_be_1 31 | rts 32 | 33 | table: .byte 10, 254, 20, 2, 40, 4, 80, 6 34 | .byte 160, 8, 60, 10, 14, 12, 26, 14 35 | .byte 12, 16, 24, 18, 48, 20, 96, 22 36 | .byte 192, 24, 72, 26, 16, 28, 32, 30 37 | -------------------------------------------------------------------------------- /nes-testsuite/roms/apu_test/source/3-irq_flag.s: -------------------------------------------------------------------------------- 1 | ; Verifies basic operation of frame irq flag 2 | 3 | .include "shell.inc" 4 | 5 | should_be_clear: 6 | lda $4015 7 | and #$40 8 | jne test_failed 9 | rts 10 | 11 | should_be_set: 12 | lda $4015 13 | and #$40 14 | jeq test_failed 15 | rts 16 | 17 | main: 18 | set_test 2,"Flag shouldn't be set in $4017 mode $40" 19 | setb $4017,$40 20 | delay_msec 20 21 | jsr should_be_clear 22 | 23 | set_test 3,"Flag shouldn't be set in $4017 mode $80" 24 | setb $4017,$80 25 | delay_msec 20 26 | jsr should_be_clear 27 | 28 | set_test 4,"Flag should be set in $4017 mode $00" 29 | setb $4017,0 30 | delay_msec 20 31 | jsr should_be_set 32 | 33 | set_test 5,"Reading flag should clear it" 34 | setb $4017,0 35 | delay_msec 20 36 | jsr should_be_set 37 | jsr should_be_clear 38 | 39 | set_test 6,"Writing $00 or $80 to $4017 shouldn't affect flag" 40 | setb $4017,0 41 | delay_msec 20 42 | setb $4017,0 43 | setb $4017,$80 44 | jsr should_be_set 45 | 46 | set_test 7,"Writing $40 or $C0 to $4017 should clear flag" 47 | setb $4017,0 48 | delay_msec 20 49 | setb $4017,$40 50 | setb $4017,0 51 | jsr should_be_clear 52 | 53 | jmp tests_passed 54 | -------------------------------------------------------------------------------- /nes-testsuite/roms/apu_test/source/4-jitter.s: -------------------------------------------------------------------------------- 1 | ; Tests for APU clock jitter. Also tests basic timing of frame irq flag 2 | ; since it's needed to determine jitter. 3 | 4 | .include "shell.inc" 5 | 6 | ; Returns current jitter in A. Takes an even number of clocks. 7 | get_jitter: 8 | delay 3 ; make routine an even number of clocks 9 | setb SNDMODE,$40 ; clear frame irq flag 10 | setb SNDMODE,$00 ; begin mode 0, frame irq enabled 11 | delay 29827 12 | lda SNDCHN ; read at 29831 13 | and #$40 14 | rts 15 | 16 | main: set_test 2,"Frame irq is set too soon" 17 | setb SNDMODE,$40 ; clear frame irq flag 18 | setb SNDMODE,$00 ; begin mode 0, frame irq enabled 19 | delay 29826 20 | lda SNDCHN ; read at 29830 21 | and #$40 22 | jne test_failed 23 | 24 | set_test 3,"Frame irq is set too late" 25 | setb SNDMODE,$40 ; clear frame irq flag 26 | setb SNDMODE,$00 ; begin mode 0, frame irq enabled 27 | delay 29828 28 | lda SNDCHN ; read at 29832 29 | and #$40 30 | jeq test_failed 31 | 32 | set_test 4,"Even jitter not handled properly" 33 | jsr get_jitter 34 | sta text_out_base 29 | stx text_out_addr+1 30 | setb text_out_addr,Addr 40 | sta addr+1 41 | pla 42 | jsr routine 43 | seg_data "STRINGS",{Addr: data} 44 | .endmacro 45 | 46 | ; If name isn't yet defined, defines it with value 47 | .macro SET_DEFAULT name,value 48 | .ifndef name 49 | name=value 50 | .endif 51 | .endmacro 52 | 53 | ; Calls routine multiple times, with A having the 54 | ; value 'start' the first time, 'start+step' the 55 | ; second time, up to 'end' for the last time. 56 | .macro for_loop routine,start,end,step 57 | lda #start 58 | : pha 59 | jsr routine 60 | pla 61 | clc 62 | adc #step 63 | cmp #<((end)+(step)) 64 | bne :- 65 | .endmacro 66 | -------------------------------------------------------------------------------- /nes-testsuite/roms/dmc_dma_during_read4/source/common/nes.inc: -------------------------------------------------------------------------------- 1 | ; NES I/O locations and masks 2 | 3 | ; Clocks per second 4 | CLOCK_RATE = 1789773 5 | ;CLOCK_RATE = 1662607 6 | 7 | .ifndef BUILD_NSF 8 | 9 | ; PPU 10 | PPUCTRL = $2000 11 | PPUMASK = $2001 12 | PPUSTATUS = $2002 13 | SPRADDR = $2003 14 | SPRDATA = $2004 15 | PPUSCROLL = $2005 16 | PPUADDR = $2006 17 | PPUDATA = $2007 18 | SPRDMA = $4014 19 | 20 | PPUCTRL_NMI = $80 21 | PPUMASK_BG0 = $0A 22 | PPUCTRL_8X8 = $00 23 | PPUCTRL_8X16 = $20 24 | PPUMASK_SPR = $14 25 | PPUMASK_BG0CLIP = $08 26 | 27 | .endif 28 | 29 | ; APU 30 | SNDCHN = $4015 31 | JOY1 = $4016 32 | JOY2 = $4017 33 | SNDMODE = $4017 34 | 35 | SNDMODE_NOIRQ = $40 36 | -------------------------------------------------------------------------------- /nes-testsuite/roms/dmc_dma_during_read4/source/common/serial.s: -------------------------------------------------------------------------------- 1 | ; Serial output at 57600 bits/sec on controller port 2 2 | ; 3 | ; Uses stack and register A only, and doesn't mind page crossing 4 | ; (uses subroutines instead of loops). 5 | 6 | ; Initializes serial. If this isn't done, first byte sent to 7 | ; PC might be corrupt. 8 | ; Preserved: X, Y 9 | serial_init: 10 | sec 11 | lda #$FF 12 | bne serial_write_ ; always branches 13 | 14 | 15 | ; Writes byte A to serial 16 | ; Preserved: X, Y 17 | serial_write: 18 | clc 19 | serial_write_: 20 | jsr @bit ; start 21 | nop ; TODO: why the extra delay? 22 | jsr @first ; bit 0 23 | jsr @bit ; bit 1 24 | jsr @bit ; bit 2 25 | jsr @bit ; bit 3 26 | jsr @bit ; bit 4 27 | jsr @bit ; bit 5 28 | jsr @bit ; bit 6 29 | jsr @bit ; bit 7 30 | sec ; 2 stop bit 31 | @first: nop ; 4 32 | nop 33 | @bit: ; 6 jsr 34 | pha ; 3 35 | rol a ; 2 36 | and #1 ; 2 37 | sta JOY1 ; 4 38 | pla ; 4 39 | ror a ; 2 40 | .if CLOCK_RATE = 1789773 41 | nop ; 2 42 | .endif 43 | rts ; 6 44 | -------------------------------------------------------------------------------- /nes-testsuite/roms/dmc_dma_during_read4/source/dma_2007_read.s: -------------------------------------------------------------------------------- 1 | ; DMC DMA during $2007 read causes 2-3 extra $2007 2 | ; reads before real read. 3 | ; 4 | ; Number of extra reads depends in CPU-PPU 5 | ; synchronization at reset. 6 | ; 7 | ; Output: 8 | ;11 22 9 | ;11 22 10 | ;33 44 or 44 55 11 | ;11 22 12 | ;11 22 13 | ;159A7A8F or 5E3DF9C4 14 | 15 | iter = 5 ; how many times the test is run 16 | time = 14 ; adjusts time of first DMA 17 | dma = 1 ; set to 0 to disable DMA 18 | 19 | .include "common.inc" 20 | 21 | ; Setup things before time-critical part of test 22 | begin: 23 | ; Disable PPU 24 | jsr wait_vbl 25 | lda #0 26 | sta PPUMASK 27 | 28 | ; Fill VRAM with $11 22 33 44 55 66 77 29 | lda #0 30 | sta PPUADDR 31 | sta PPUADDR 32 | ldx #7 33 | lda #$11 34 | : sta PPUDATA 35 | clc 36 | adc #$11 37 | dex 38 | bne :- 39 | 40 | ; PPUADDR=0, and read once to fill buffer 41 | lda #0 42 | sta PPUADDR 43 | sta PPUADDR 44 | lda PPUDATA 45 | 46 | rts 47 | 48 | ; DMC DMA occurs during this code 49 | test: nop 50 | nop 51 | ldx $2007 52 | nop 53 | nop 54 | rts 55 | 56 | ; Dump results 57 | end: lda $2007 58 | jsr print_x 59 | jsr print_a 60 | jsr print_newline 61 | rts 62 | 63 | main: ; Run above routines with synchronized DMC DMA 64 | jsr run_tests 65 | 66 | jsr print_crc 67 | rts 68 | -------------------------------------------------------------------------------- /nes-testsuite/roms/dmc_dma_during_read4/source/dma_2007_write.s: -------------------------------------------------------------------------------- 1 | ; DMC DMA during $2007 write has no effect. 2 | ; 3 | ; Output: 4 | ;22 11 22 AA 44 55 66 77 5 | ;22 11 22 AA 44 55 66 77 6 | ;22 11 22 AA 44 55 66 77 7 | ;22 11 22 AA 44 55 66 77 8 | ;22 11 22 AA 44 55 66 77 9 | 10 | iter = 5 ; how many times the test is run 11 | time = 11 ; adjusts time of first DMA 12 | dma = 1 ; set to 0 to disable DMA 13 | 14 | .include "common.inc" 15 | 16 | ; Setup things before time-critical part of test 17 | begin: 18 | ; Disable PPU 19 | jsr wait_vbl 20 | lda #0 21 | sta PPUMASK 22 | 23 | ; Fill VRAM with $11 22 33 44 55 66 77 24 | lda #0 25 | sta PPUADDR 26 | sta PPUADDR 27 | ldx #7 28 | lda #$11 29 | : sta PPUDATA 30 | clc 31 | adc #$11 32 | dex 33 | bne :- 34 | 35 | ; PPUADDR=0, and read once to fill buffer 36 | lda #0 37 | sta PPUADDR 38 | sta PPUADDR 39 | lda PPUDATA 40 | 41 | rts 42 | 43 | ; DMC DMA occurs during this code 44 | test: nop 45 | nop 46 | lda #$AA 47 | sta $2007 48 | nop 49 | nop 50 | rts 51 | 52 | ; Dump results 53 | end: lda #0 54 | sta PPUADDR 55 | sta PPUADDR 56 | ldx #8 57 | : lda PPUDATA 58 | jsr print_a 59 | dex 60 | bne :- 61 | jsr print_newline 62 | 63 | rts 64 | 65 | main: ; Run above routines with synchronized DMC DMA 66 | jsr run_tests 67 | 68 | check_crc $28F53CA4 69 | jmp tests_passed 70 | -------------------------------------------------------------------------------- /nes-testsuite/roms/dmc_dma_during_read4/source/dma_4016_read.s: -------------------------------------------------------------------------------- 1 | ; DMC DMA during $4016 read causes extra $4016 2 | ; read. 3 | ; 4 | ; Output: 5 | ;08 08 07 08 08 6 | 7 | iter = 5 ; how many times the test is run 8 | time = 14 ; adjusts time of first DMA 9 | dma = 1 ; set to 0 to disable DMA 10 | 11 | .include "common.inc" 12 | 13 | ; Setup things before time-critical part of test 14 | begin: 15 | ; Start controller read 16 | lda #1 17 | sta $4016 18 | lda #0 19 | sta $4016 20 | rts 21 | 22 | ; DMC DMA occurs during this code 23 | test: nop 24 | nop 25 | lda $4016 26 | nop 27 | nop 28 | rts 29 | 30 | ; Dump results 31 | end: ; Count number of bits until controller 32 | ; returns 1 33 | ldx #0 34 | : inx 35 | lda $4016 36 | lsr a 37 | bcc :- 38 | 39 | jsr print_x 40 | rts 41 | 42 | main: ; Run above routines with synchronized DMC DMA 43 | jsr run_tests 44 | check_crc $F0AB808C 45 | jmp tests_passed 46 | 47 | -------------------------------------------------------------------------------- /nes-testsuite/roms/dmc_dma_during_read4/source/double_2007_read.s: -------------------------------------------------------------------------------- 1 | ; Double read of $2007 sometimes ignores extra 2 | ; read, and puts odd things into buffer. 3 | ; 4 | ; Output (depends on CPU-PPU synchronization): 5 | ;22 33 44 55 66 6 | ;22 44 55 66 77 or 7 | ;22 33 44 55 66 or 8 | ;02 44 55 66 77 or 9 | ;32 44 55 66 77 or 10 | ;85CFD627 or F018C287 or 440EF923 or E52F41A5 11 | 12 | CHR_RAM=1 13 | .include "shell.inc" 14 | 15 | begin: 16 | ; Disable PPU 17 | jsr wait_vbl 18 | lda #0 19 | sta PPUMASK 20 | 21 | ; Fill VRAM with $11 22 33 44 55 66 77 22 | lda #0 23 | sta PPUADDR 24 | sta PPUADDR 25 | ldx #7 26 | lda #$11 27 | : sta PPUDATA 28 | clc 29 | adc #$11 30 | dex 31 | bne :- 32 | 33 | ; PPUADDR=1, and fill buffer 34 | lda #$00 35 | sta PPUADDR 36 | lda #$01 37 | sta PPUADDR 38 | lda PPUDATA 39 | rts 40 | 41 | end: 42 | jsr print_a 43 | 44 | ; Read several bytes 45 | ldx #4 46 | : lda PPUDATA 47 | jsr print_a 48 | dex 49 | bne :- 50 | jsr print_newline 51 | rts 52 | 53 | main: jsr begin 54 | ldx #$00 55 | lda $20F7,x ; reads $2007 once 56 | jsr end 57 | 58 | jsr begin 59 | ldx #$10 60 | lda $20F7,x ; reads $2007 twice in succession 61 | jsr end 62 | 63 | jsr print_crc 64 | rts 65 | -------------------------------------------------------------------------------- /nes-testsuite/roms/dmc_dma_during_read4/source/nes.cfg: -------------------------------------------------------------------------------- 1 | # ca65 configuration for CNROM with code at $E000 2 | 3 | # fill=yes forces area to be padded to specified size in output 4 | MEMORY 5 | { 6 | ZP: start = $10, size = $F0, type = rw; 7 | RAM: start = $0200, size = $0600, type = rw; 8 | 9 | # My devcart only has memory from $E000-$FFFF 10 | HEADER: start = 0, size = $10, type = ro, fill=yes; 11 | UNUSED: start = $8000, size = $6000, type = ro, fill=yes; 12 | ROM: start = $E000, size = $1FF4, type = ro, fill=yes; 13 | 14 | # Extra 6 bytes in vectors because built-in NES configuration 15 | # does the same. Stupid, but better to keep compatible with it 16 | # so small examples can use the built-in configuration. 17 | VECTORS:start = $FFF4, size = $C, type = ro, fill=yes; 18 | 19 | CHARS: start = 0, size = $2000, type = ro; 20 | } 21 | 22 | # align=$100 allows use of .align directive with a value up to $100 23 | # optional=yes avoids warning if segment is never used 24 | SEGMENTS 25 | { 26 | ZEROPAGE: load = ZP, type = zp; 27 | BSS: load = RAM, type = bss; 28 | 29 | HEADER: load = HEADER, type = ro; 30 | CODE: load = ROM, type = ro, align=$100; 31 | 32 | # Library code goes into this segment, keeping user code same 33 | # length regardless of runtime: devcart, ROM, NSF, etc. 34 | CODE2: load = ROM, type = ro, align=$100, optional=yes; 35 | RODATA: load = ROM, type = ro; 36 | 37 | # Separate segment for strings so RODATA can have pointers to 38 | # strings 39 | STRINGS: load = ROM, type = ro, optional=yes; 40 | VECTORS: load = VECTORS,type = ro; 41 | 42 | CHARS: load = CHARS, type = ro, align=$2000, optional=yes; 43 | } 44 | -------------------------------------------------------------------------------- /nes-testsuite/roms/dmc_dma_during_read4/source/read_write_2007.s: -------------------------------------------------------------------------------- 1 | ; Read of $2007 just before write behaves normally. 2 | ; 3 | ; Output: 4 | ;33 11 22 33 09 55 66 77 5 | ;33 11 22 33 09 55 66 77 6 | 7 | CHR_RAM=1 8 | .include "shell.inc" 9 | 10 | begin: 11 | ; Disable PPU 12 | jsr wait_vbl 13 | lda #0 14 | sta PPUMASK 15 | 16 | ; Fill VRAM with $11 22 33 44 55 66 77 17 | lda #0 18 | sta PPUADDR 19 | sta PPUADDR 20 | ldx #7 21 | lda #$11 22 | : sta PPUDATA 23 | clc 24 | adc #$11 25 | dex 26 | bne :- 27 | 28 | ; PPUADDR=1, and fill buffer 29 | lda #$00 30 | sta PPUADDR 31 | lda #$01 32 | sta PPUADDR 33 | lda PPUDATA 34 | rts 35 | 36 | end: 37 | ; Dump VRAM 38 | lda #0 39 | sta PPUADDR 40 | sta PPUADDR 41 | ldx #8 42 | : lda PPUDATA 43 | jsr print_a 44 | dex 45 | bne :- 46 | jsr print_newline 47 | rts 48 | 49 | main: ; Manually read before write 50 | jsr begin 51 | ldx #0 52 | lda #9 53 | ldx $2007 54 | sta $2007 55 | jsr end 56 | 57 | ; Read one clock before write 58 | jsr begin 59 | ldx #0 60 | lda #9 61 | sta $2007,x ; reads then writes $2007 62 | jsr end 63 | 64 | check_crc $0F877C4B 65 | jmp tests_passed 66 | -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M0_P32K_C8K_V.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M0_P32K_C8K_V.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M10_P128K_C64K_S8K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M10_P128K_C64K_S8K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M10_P128K_C64K_W8K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M10_P128K_C64K_W8K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M118_P128K_C64K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M118_P128K_C64K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M180_P128K_H.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M180_P128K_H.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M1_P128K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M1_P128K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M1_P128K_C128K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M1_P128K_C128K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M1_P128K_C128K_S8K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M1_P128K_C128K_S8K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M1_P128K_C128K_W8K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M1_P128K_C128K_W8K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M1_P128K_C32K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M1_P128K_C32K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M1_P128K_C32K_S8K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M1_P128K_C32K_S8K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M1_P128K_C32K_W8K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M1_P128K_C32K_W8K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M1_P512K_S32K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M1_P512K_S32K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M1_P512K_S8K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M1_P512K_S8K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M28_P512K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M28_P512K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M2_P128K_V.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M2_P128K_V.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M34_P128K_H.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M34_P128K_H.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M3_P32K_C32K_H.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M3_P32K_C32K_H.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M4_P128K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M4_P128K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M4_P256K_C256K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M4_P256K_C256K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M66_P64K_C16K_V.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M66_P64K_C16K_V.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M69_P128K_C64K_S8K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M69_P128K_C64K_S8K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M69_P128K_C64K_W8K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M69_P128K_C64K_W8K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M78.3_P128K_C64K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M78.3_P128K_C64K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M7_P128K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M7_P128K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/M9_P128K_C64K.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/M9_P128K_C64K.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/source/hdbm-master.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/source/hdbm-master.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/source/obj/nes/index.txt: -------------------------------------------------------------------------------- 1 | Files produced by build tools go here, but caulk goes where? 2 | -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/source/src/beepcode.s: -------------------------------------------------------------------------------- 1 | ; 2 | ; Beep code output for Holy Diver Batman 3 | ; Copyright 2013 Damian Yerrick 4 | ; Copying and distribution of this file, with or without 5 | ; modification, are permitted in any medium without royalty provided 6 | ; the copyright notice and this notice are preserved in all source 7 | ; code copies. This file is offered as-is, without any warranty. 8 | ; 9 | .include "src/nes.h" 10 | .include "src/ram.h" 11 | 12 | .proc beepcode_byte 13 | pha 14 | lsr a 15 | lsr a 16 | lsr a 17 | lsr a 18 | jsr beepcode_nibble 19 | pla 20 | and #$0F 21 | .endproc 22 | .proc beepcode_nibble 23 | asl a 24 | tax 25 | lda #$02 << 1 26 | cpx #8*2 27 | ror a 28 | sta $4000 29 | lda #$08 30 | sta $4001 31 | lda pitches,x 32 | sta $4002 33 | lda pitches+1,x 34 | sta $4003 35 | ldy #12 36 | jmp wait_y_frames 37 | .pushseg 38 | .segment "RODATA" 39 | pitches: 40 | .word $13BF,$1356,$12F9,$12CE,$127F,$123A,$11FB,$11DF 41 | .word $11AB,$117C,$1152,$113F,$111C,$10FD,$10E2,$10D2 42 | .popseg 43 | .endproc 44 | 45 | .proc beepcode_tweet 46 | ldx #2 47 | loop: 48 | ldy #$BC 49 | sty $4000 50 | ldy #$08 51 | sty $4001 52 | ldy pitches,x 53 | sty $4002 54 | ldy #$00 55 | sty $4003 56 | ldy #2 57 | jsr wait_y_frames 58 | dex 59 | bpl loop 60 | ldy #$B0 61 | sty $4000 62 | rts 63 | .pushseg 64 | .segment "RODATA" 65 | pitches: 66 | .byte $2F,$3F,$5F 67 | .popseg 68 | .endproc 69 | 70 | .proc beepcode_ding 71 | ldy #$83 72 | bne beepcode_noisey 73 | .endproc 74 | .proc beepcode_null 75 | ldy #$89 76 | .endproc 77 | .proc beepcode_noisey 78 | lda #$05 79 | sta $400C 80 | sty $400E 81 | lda #$20 82 | sta $400F 83 | ldy #24 84 | jmp wait_y_frames 85 | .endproc 86 | -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/source/src/morse.h: -------------------------------------------------------------------------------- 1 | MORSE_B = %10001000 ; _... 2 | MORSE_C = %10101000 ; _._. 3 | MORSE_D = %10010000 ; _.. 4 | MORSE_F = %00101000 ; .._. 5 | MORSE_I = %00100000 ; .. 6 | MORSE_L = %01001000 ; ._.. 7 | MORSE_M = %11100000 ; __ 8 | MORSE_N = %10100000 ; _. 9 | MORSE_O = %11110000 ; ___ 10 | MORSE_R = %01010000 ; ._. 11 | MORSE_S = %00010000 ; ... 12 | MORSE_T = %11000000 ; _ 13 | MORSE_U = %00110000 ; .._ 14 | MORSE_V = %00011000 ; ..._ 15 | MORSE_W = %01110000 ; .__ 16 | 17 | -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/source/src/nes.h: -------------------------------------------------------------------------------- 1 | ; 2 | ; NES I/O definitions 3 | ; Copyright 2010 Damian Yerrick 4 | ; 5 | ; Copying and distribution of this file, with or without 6 | ; modification, are permitted in any medium without royalty provided 7 | ; the copyright notice and this notice are preserved in any source 8 | ; code copies. This file is offered as-is, without any warranty. 9 | ; 10 | 11 | PPUCTRL = $2000 12 | NT_2000 = $00 13 | NT_2400 = $01 14 | NT_2800 = $02 15 | NT_2C00 = $03 16 | VRAM_DOWN = $04 17 | OBJ_0000 = $00 18 | OBJ_1000 = $08 19 | OBJ_8X16 = $20 20 | BG_0000 = $00 21 | BG_1000 = $10 22 | VBLANK_NMI = $80 23 | 24 | PPUMASK = $2001 25 | LIGHTGRAY = $01 26 | BG_OFF = $00 27 | BG_CLIP = $08 28 | BG_ON = $0A 29 | OBJ_OFF = $00 30 | OBJ_CLIP = $10 31 | OBJ_ON = $14 32 | TINT_R = $20 33 | TINT_G = $40 34 | TINT_B = $80 35 | 36 | PPUSTATUS = $2002 37 | OAMADDR = $2003 38 | ; Don't worry about $2004; let OAM_DMA do the work for you. 39 | PPUSCROLL = $2005 40 | PPUADDR = $2006 41 | PPUDATA = $2007 42 | 43 | OAM_DMA = $4014 44 | SNDCHN = $4015 45 | P1 = $4016 46 | P2 = $4017 47 | 48 | KEY_A = %10000000 49 | KEY_B = %01000000 50 | KEY_SELECT = %00100000 51 | KEY_START = %00010000 52 | KEY_UP = %00001000 53 | KEY_DOWN = %00000100 54 | KEY_LEFT = %00000010 55 | KEY_RIGHT = %00000001 56 | -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/source/tilesets/font8x5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/holy_diver_batman/source/tilesets/font8x5.png -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/source/tools/cvt8x5.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | 4 | Converts 8x5 font to interleaved ROM data for quick expander 5 | by Damian Yerrick 6 | """ 7 | 8 | from __future__ import with_statement, division 9 | from PIL import Image 10 | from array import array 11 | import sys 12 | 13 | def main(argv=None): 14 | argv = argv or sys.argv 15 | im = Image.open(argv[1]) 16 | w = im.size[0] // 8 17 | data = array('B', im.getdata()) 18 | data = array('B', 19 | (sum(0x80 >> i if d else 0 for i, d in enumerate(data[i:i + 8])) 20 | for i in range(0, len(data), 8))) 21 | idxs = (b 22 | for i in range(0, 5 * w, w) 23 | for j in range(i, i + 2) 24 | for k in range(j, len(data), 8 * w) 25 | for b in range(k, k + w, 2)) 26 | data = array('B', (data[b] for b in idxs)) 27 | with open(argv[2], "wb") as outfp: 28 | outfp.write(data.tostring()) 29 | 30 | if __name__=="__main__": 31 | main() 32 | ## main(['main', "../tilesets/font8x5.png", "out.bin"]) 33 | -------------------------------------------------------------------------------- /nes-testsuite/roms/holy_diver_batman/source/zip.in: -------------------------------------------------------------------------------- 1 | hdbm-master.nes 2 | makefile 3 | nes.ini 4 | README.txt 5 | CHANGES.txt 6 | obj/nes/index.txt 7 | src/bcd.s 8 | src/beepcode.s 9 | src/boardletter.s 10 | src/drivers.s 11 | src/loadchr.s 12 | src/main.s 13 | src/mapper_detect.s 14 | src/mmcdrivers.s 15 | src/mmc3drivers.s 16 | src/morse.h 17 | src/nes.h 18 | src/pads.s 19 | src/ppuclear.s 20 | src/ram.h 21 | src/wram.s 22 | src/wrongbanks.s 23 | tilesets/font8x5.png 24 | tools/cvt8x5.py 25 | tools/make_roms.py 26 | tools/pilbmp2nes.py 27 | zip.in 28 | 29 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_misc/01-abs_x_wrap.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/instr_misc/01-abs_x_wrap.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_misc/02-branch_wrap.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/instr_misc/02-branch_wrap.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_misc/03-dummy_reads.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/instr_misc/03-dummy_reads.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_misc/04-dummy_reads_apu.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/instr_misc/04-dummy_reads_apu.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_misc/source/01-abs_x_wrap.s: -------------------------------------------------------------------------------- 1 | ; Verifies that $FFFF wraps around to 0 for 2 | ; STA abs,X and LDA abs,X 3 | 4 | .include "shell.inc" 5 | 6 | main: 7 | setb <0,0 8 | setb <1,0 9 | 10 | ldx #1 11 | lda #$12 12 | sta $FFFF,x 13 | 14 | ldx #2 15 | lda #$34 16 | sta $FFFF,x 17 | 18 | set_test 2,"Write wrap-around failed" 19 | 20 | lda <$00 21 | cmp #$12 22 | jne test_failed 23 | 24 | lda <$01 25 | cmp #$34 26 | jne test_failed 27 | 28 | set_test 3,"Read wrap-around failed" 29 | 30 | ldx #1 31 | lda $FFFF,x 32 | cmp #$12 33 | jne test_failed 34 | 35 | ldx #2 36 | lda $FFFF,x 37 | cmp #$34 38 | jne test_failed 39 | 40 | jmp tests_passed 41 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_misc/source/02-branch_wrap.s: -------------------------------------------------------------------------------- 1 | ; Verifies that branching past end or before beginning 2 | ; of RAM wraps around 3 | 4 | .include "shell.inc" 5 | 6 | main: 7 | set_test 2,"Branch from $FF8x to $000x" 8 | setb <0,$E8 ; INX 9 | setb <1,$E8 ; INX 10 | setb <2,$60 ; RTS 11 | ldx #0 12 | clc 13 | jsr forward 14 | cpx #1 15 | jne test_failed 16 | 17 | set_test 3,"Branch from $000x to $FFFx" 18 | setb <0,$90 ; BCC 19 | setb <1,-$3F 20 | ldx #0 21 | clc 22 | jsr <0 23 | cpx #1 24 | jne test_failed 25 | 26 | jmp tests_passed 27 | 28 | 29 | .segment "FF00" 30 | .res $C0 31 | ; This code is at $FFC0: 32 | forward: 33 | .byte $90,$3F ; BCC $3F 34 | inx 35 | return: 36 | inx 37 | rts 38 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_misc/source/common/ascii.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/instr_misc/source/common/ascii.chr -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_misc/source/common/bootloader.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/instr_misc/source/common/bootloader.bin -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_misc/source/common/neshw.inc: -------------------------------------------------------------------------------- 1 | ; NES I/O locations and masks 2 | 3 | .ifndef BUILD_NSF 4 | 5 | ; PPU 6 | PPUCTRL = $2000 7 | PPUMASK = $2001 8 | PPUSTATUS = $2002 9 | SPRADDR = $2003 10 | SPRDATA = $2004 11 | PPUSCROLL = $2005 12 | PPUADDR = $2006 13 | PPUDATA = $2007 14 | SPRDMA = $4014 15 | 16 | PPUCTRL_NMI = $80 17 | PPUMASK_BG0 = $0A 18 | PPUCTRL_8X8 = $00 19 | PPUCTRL_8X16 = $20 20 | PPUMASK_SPR = $14 21 | PPUMASK_BG0CLIP = $08 22 | 23 | .endif 24 | 25 | ; APU 26 | SNDCHN = $4015 27 | JOY1 = $4016 28 | JOY2 = $4017 29 | SNDMODE = $4017 30 | 31 | SNDMODE_NOIRQ = $40 32 | 33 | .ifndef REGION_FREE 34 | .ifndef PAL_ONLY 35 | .ifndef NTSC_ONLY 36 | NTSC_ONLY = 1 37 | .endif 38 | .endif 39 | .else 40 | .ifdef NTSC_ONLY 41 | .error "NTSC_ONLY and REGION_FREE defined" 42 | .endif 43 | .ifdef PAL_ONLY 44 | .error "PAL_ONLY and REGION_FREE defined" 45 | .endif 46 | .endif 47 | 48 | .ifdef NTSC_ONLY 49 | CLOCK_RATE = 1789773 50 | PPU_FRAMELEN = 29781 51 | .endif 52 | 53 | .ifdef PAL_ONLY 54 | CLOCK_RATE = 1662607 55 | PPU_FRAMELEN = 33248 56 | .endif 57 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_misc/source/common/shell.inc: -------------------------------------------------------------------------------- 1 | ; Included at beginning of program 2 | 3 | .ifdef CUSTOM_PREFIX 4 | .include "custom_prefix.s" 5 | .endif 6 | 7 | ; Sub-test in a multi-test ROM 8 | .ifdef BUILD_MULTI 9 | .include "build_multi.s" 10 | .else 11 | 12 | ; NSF music file 13 | .ifdef BUILD_NSF 14 | .include "build_nsf.s" 15 | .endif 16 | 17 | ; Devcart 18 | .ifdef BUILD_DEVCART 19 | .include "build_devcart.s" 20 | .endif 21 | 22 | ; NES internal RAM 23 | .ifdef BUILD_NOCART 24 | .include "build_nocart.s" 25 | .endif 26 | 27 | ; NES ROM (default) 28 | .ifndef SHELL_INCLUDED 29 | .include "build_rom.s" 30 | .endif 31 | 32 | .endif ; .ifdef BUILD_MULTI 33 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_misc/source/common/text_out.s: -------------------------------------------------------------------------------- 1 | ; Text output as expanding zero-terminated string at text_out_base 2 | 3 | ; The final exit result byte is written here 4 | final_result = $6000 5 | 6 | ; Text output is written here as an expanding 7 | ; zero-terminated string 8 | text_out_base = $6004 9 | 10 | bss_res text_out_temp 11 | zp_res text_out_addr,2 12 | 13 | init_text_out: 14 | ldx #0 15 | 16 | ; Put valid data first 17 | setb text_out_base,0 18 | 19 | lda #$80 20 | jsr set_final_result 21 | 22 | ; Now fill in signature that tells emulator there's 23 | ; useful data there 24 | setb text_out_base-3,$DE 25 | setb text_out_base-2,$B0 26 | setb text_out_base-1,$61 27 | 28 | ldx #>text_out_base 29 | stx text_out_addr+1 30 | setb text_out_addr,:+ 71 | jmp $6FE 72 | : pla 73 | cmp #$00 74 | jne test_failed 75 | pla 76 | cmp #$07 77 | jne test_failed 78 | 79 | set_test 7,"RTS should return to addr+1" 80 | lda #>:+ 81 | pha 82 | lda #<:+ 83 | pha 84 | ldx #0 85 | rts 86 | inx 87 | : inx 88 | inx 89 | cpx #1 90 | jne test_failed 91 | 92 | jmp tests_passed 93 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/02-implied.s: -------------------------------------------------------------------------------- 1 | .include "instr_test.inc" 2 | instrs: 3 | entry $2A,"ROL A" ; A = op A 4 | entry $0A,"ASL A" 5 | entry $6A,"ROR A" 6 | entry $4A,"LSR A" 7 | 8 | entry $8A,"TXA" ; AXY = AXY 9 | entry $98,"TYA" 10 | entry $AA,"TAX" 11 | entry $A8,"TAY" 12 | 13 | entry $E8,"INX" ; XY = op XY 14 | entry $C8,"INY" 15 | entry $CA,"DEX" 16 | entry $88,"DEY" 17 | 18 | entry $38,"SEC" ; flags = op flags 19 | entry $18,"CLC" 20 | entry $F8,"SED" 21 | entry $D8,"CLD" 22 | entry $78,"SEI" 23 | entry $58,"CLI" 24 | entry $B8,"CLV" 25 | 26 | entry $EA,"NOP" 27 | 28 | .ifndef OFFICIAL_ONLY 29 | entry $1A,"NOP" 30 | entry $3A,"NOP" 31 | entry $5A,"NOP" 32 | entry $7A,"NOP" 33 | entry $DA,"NOP" 34 | entry $FA,"NOP" 35 | .endif 36 | instrs_size = * - instrs 37 | 38 | instr_template: 39 | nop 40 | jmp instr_done 41 | instr_template_size = * - instr_template 42 | 43 | operand = in_a 44 | 45 | .define set_in set_paxyso 46 | .define check_out check_paxyso 47 | 48 | .include "instr_test_end.s" 49 | 50 | test_values: 51 | test_normal 52 | rts 53 | 54 | correct_checksums: 55 | .dword $B129E6BE 56 | .dword $965A320E 57 | .dword $905D41EE 58 | .dword $51FA7AD7 59 | .dword $A60AE5B1 60 | .dword $8FA16B44 61 | .dword $D311C870 62 | .dword $453F27CD 63 | .dword $4F91B466 64 | .dword $604DB29C 65 | .dword $4BCFE982 66 | .dword $8E0D1602 67 | .dword $26DBEBEC 68 | .dword $49214BA2 69 | .dword $8C4FB749 70 | .dword $37962351 71 | .dword $99E7216C 72 | .dword $6408D38D 73 | .dword $C334A2A7 74 | .dword $55827CC6 75 | .dword $55827CC6 76 | .dword $55827CC6 77 | .dword $55827CC6 78 | .dword $55827CC6 79 | .dword $55827CC6 80 | .dword $55827CC6 81 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/03-immediate.s: -------------------------------------------------------------------------------- 1 | .include "instr_test.inc" 2 | 3 | instrs: 4 | entry $A9,"LDA #n" ; AXY = #n 5 | entry $A2,"LDX #n" 6 | entry $A0,"LDY #n" 7 | 8 | entry $69,"ADC #n" ; A = A op #n 9 | entry $E9,"SBC #n" 10 | entry $09,"ORA #n" 11 | entry $29,"AND #n" 12 | entry $49,"EOR #n" 13 | 14 | entry $C9,"CMP #n" ; AXY op #n 15 | entry $E0,"CPX #n" 16 | entry $C0,"CPY #n" 17 | .ifndef OFFICIAL_ONLY 18 | entry $EB,"SBC #n" 19 | 20 | entry $80,"DOP #n" 21 | entry $82,"DOP #n" 22 | entry $89,"DOP #n" 23 | entry $C2,"DOP #n" 24 | entry $E2,"DOP #n" 25 | 26 | entry $0B,"AAC #n" 27 | entry $2B,"AAC #n" 28 | entry $4B,"ASR #n" 29 | entry $6B,"ARR #n" 30 | entry $AB,"ATX #n" 31 | entry $CB,"AXS #n" 32 | .endif 33 | instrs_size = * - instrs 34 | 35 | operand = instr+1 36 | 37 | instr_template: 38 | lda #0 39 | jmp instr_done 40 | instr_template_size = * - instr_template 41 | 42 | .define set_in set_paxyso 43 | .define check_out check_paxyso 44 | 45 | .include "instr_test_end.s" 46 | 47 | test_values: 48 | test_normal 49 | rts 50 | 51 | correct_checksums: 52 | .dword $5D5728B8 53 | .dword $EA228F76 54 | .dword $7C0C60CB 55 | .dword $49288BFC 56 | .dword $14C7EA46 57 | .dword $42684E66 58 | .dword $EA1D7F06 59 | .dword $512F9D2A 60 | .dword $70AA1B34 61 | .dword $D3DC4002 62 | .dword $6675067C 63 | .dword $14C7EA46 64 | .dword $6CB13BC0 65 | .dword $6CB13BC0 66 | .dword $6CB13BC0 67 | .dword $6CB13BC0 68 | .dword $6CB13BC0 69 | .dword $FE191060 70 | .dword $FE191060 71 | .dword $27355577 72 | .dword $C6B8642B 73 | .dword $D311C870 74 | .dword $EE21BFAD 75 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/09-ind_y.s: -------------------------------------------------------------------------------- 1 | .include "instr_test.inc" 2 | 3 | instrs: 4 | entry $B1,"LDA (z),Y" ; A = (z),Y 5 | 6 | entry $91,"STA (z),Y" ; (z),Y = A 7 | 8 | entry $D1,"CMP (z),Y" ; A op (z),Y 9 | 10 | entry $11,"ORA (z),Y" ; A = A op (z),Y 11 | entry $F1,"SBC (z),Y" 12 | entry $71,"ADC (z),Y" 13 | entry $31,"AND (z),Y" 14 | entry $51,"EOR (z),Y" 15 | .ifndef OFFICIAL_ONLY 16 | entry $13,"SLO (z),Y" 17 | entry $33,"RLA (z),Y" 18 | entry $53,"SRE (z),Y" 19 | entry $73,"RRA (z),Y" 20 | entry $B3,"LAX (z),Y" 21 | entry $D3,"DCP (z),Y" 22 | entry $F3,"ISC (z),Y" 23 | .endif 24 | instrs_size = * - instrs 25 | 26 | address = <$FF 27 | operand = $2FF 28 | 29 | instr_template: 30 | lda (address),y 31 | jmp instr_done 32 | instr_template_size = * - instr_template 33 | 34 | .macro set_in 35 | lda values+1,y 36 | sta operand+1 37 | 38 | lda values+2,y 39 | sta operand+2 40 | 41 | set_paxyso 42 | .endmacro 43 | 44 | .macro check_out 45 | check_paxyso 46 | 47 | lda operand+1 48 | jsr update_crc_fast 49 | 50 | lda operand+2 51 | jsr update_crc_fast 52 | 53 | lda address 54 | jsr update_crc_fast 55 | .endmacro 56 | 57 | .include "instr_test_end.s" 58 | 59 | test_values: 60 | lda #operand 63 | sta <(address+1) 64 | 65 | lda #0 66 | jsr :+ 67 | lda #1 68 | : sta in_y 69 | test_normal 70 | rts 71 | 72 | correct_checksums: 73 | .dword $C34014B1 74 | .dword $AD463B54 75 | .dword $7CAFE848 76 | .dword $95D8B24C 77 | .dword $0899C34E 78 | .dword $7628348A 79 | .dword $43F06A17 80 | .dword $9908C2BA 81 | .dword $539E725A 82 | .dword $6C3D4FCF 83 | .dword $459EFD3F 84 | .dword $189E2939 85 | .dword $B1EC2D77 86 | .dword $2B0E7B04 87 | .dword $43FB4CDE 88 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/10-branches.s: -------------------------------------------------------------------------------- 1 | .include "instr_test.inc" 2 | 3 | instrs: 4 | entry $90,"BCC r" ; PC = PC op flags 5 | entry $50,"BVC r" 6 | entry $D0,"BNE r" 7 | entry $30,"BMI r" 8 | entry $10,"BPL r" 9 | entry $F0,"BEQ r" 10 | entry $B0,"BCS r" 11 | entry $70,"BVS r" 12 | instrs_size = * - instrs 13 | 14 | zp_byte operand 15 | 16 | instr_template: 17 | bne :+ 18 | sta operand 19 | : jmp instr_done 20 | instr_template_size = * - instr_template 21 | 22 | values2: 23 | .byte 0,$FF,$01,$02,$04,$08,$10,$20,$40,$80 24 | values2_size = * - values2 25 | 26 | .macro set_in 27 | sta in_p 28 | set_paxyso 29 | .endmacro 30 | 31 | .define check_out check_paxyso 32 | 33 | .include "instr_test_end.s" 34 | 35 | test_values: 36 | test_normal 37 | rts 38 | 39 | correct_checksums: 40 | .dword $70FED976 41 | .dword $423DD402 42 | .dword $EFA864F5 43 | .dword $987425C4 44 | .dword $3095ECE9 45 | .dword $4749ADD8 46 | .dword $D81F105B 47 | .dword $EADC1D2F 48 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/12-jmp_jsr.s: -------------------------------------------------------------------------------- 1 | .include "instr_test.inc" 2 | 3 | instrs: 4 | entry $4C,"JMP" 5 | entry $20,"JSR" 6 | instrs_size = * - instrs 7 | 8 | instr_template: 9 | jsr :+ 10 | inx 11 | : inx 12 | jmp instr_done 13 | instr_template_size = * - instr_template 14 | 15 | operand = in_a 16 | 17 | .define set_in set_paxyso 18 | .define check_out check_paxyso 19 | 20 | .include "instr_test_end.s" 21 | 22 | test_values: 23 | test_normal 24 | rts 25 | 26 | correct_checksums: 27 | .dword $4F91B466 28 | .dword $D794E018 29 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/13-rts.s: -------------------------------------------------------------------------------- 1 | .include "instr_test.inc" 2 | 3 | instrs: 4 | entry $60,"RTS" 5 | instrs_size = * - instrs 6 | 7 | instr_template: 8 | rts 9 | inx 10 | inx 11 | jmp instr_done 12 | instr_template_size = * - instr_template 13 | 14 | operand = in_a 15 | 16 | .define check_out check_paxyso 17 | 18 | .macro set_in 19 | ; Put return address on stack 20 | ldx in_s 21 | inx 22 | lda #<(instr+1) 23 | sta $100,x 24 | inx 25 | lda #>(instr+1) 26 | sta $100,x 27 | 28 | set_paxyso 29 | .endmacro 30 | 31 | .include "instr_test_end.s" 32 | 33 | test_values: 34 | test_normal 35 | rts 36 | 37 | correct_checksums: 38 | .dword $E1EB954A 39 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/14-rti.s: -------------------------------------------------------------------------------- 1 | .include "instr_test.inc" 2 | 3 | instrs: 4 | entry $40,"RTI" 5 | instrs_size = * - instrs 6 | 7 | instr_template: 8 | rti 9 | inx 10 | inx 11 | jmp instr_done 12 | instr_template_size = * - instr_template 13 | 14 | zp_res operand 15 | 16 | .define check_out check_paxyso 17 | 18 | .macro set_in 19 | ; Put return address and P on stack 20 | ldx in_s 21 | inx 22 | lda operand 23 | sta $100,x 24 | inx 25 | lda #<(instr+1) 26 | sta $100,x 27 | inx 28 | lda #>(instr+1) 29 | sta $100,x 30 | 31 | set_paxyso 32 | .endmacro 33 | 34 | .include "instr_test_end.s" 35 | 36 | test_values: 37 | test_normal 38 | rts 39 | 40 | correct_checksums: 41 | .dword $F4B30222 42 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/15-brk.s: -------------------------------------------------------------------------------- 1 | CUSTOM_IRQ = 1 2 | .include "instr_test.inc" 3 | 4 | zp_byte p_inside_brk 5 | 6 | irq: pha 7 | php 8 | pla 9 | sta p_inside_brk 10 | pla 11 | rti 12 | 13 | instrs: 14 | entry $00,"BRK" 15 | instrs_size = * - instrs 16 | 17 | instr_template: 18 | brk 19 | inx 20 | inx 21 | jmp instr_done 22 | instr_template_size = * - instr_template 23 | 24 | operand = in_a 25 | 26 | .macro set_in 27 | set_stack 28 | set_paxyso 29 | .endmacro 30 | 31 | .macro check_out 32 | ; By looking at stack, we verify 33 | ; values BRK pushed on it 34 | check_paxyso 35 | check_stack 36 | lda p_inside_brk 37 | jsr update_crc_fast 38 | .endmacro 39 | 40 | .include "instr_test_end.s" 41 | 42 | test_values: 43 | test_normal 44 | rts 45 | 46 | correct_checksums: 47 | .dword $1392F39C 48 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/16-special.s: -------------------------------------------------------------------------------- 1 | CUSTOM_IRQ=1 2 | .include "shell.inc" 3 | 4 | irq: pla 5 | pha 6 | rti 7 | 8 | jmp_6ff: 9 | .byte $6C ; JMP ($6FF) (to avoid warning) 10 | .word $6FF 11 | 12 | main: 13 | setb SNDMODE,$40 ; disable frame IRQ 14 | 15 | set_test 3,"JMP ($6FF) should get high byte from $600" 16 | setb $6FF,$F0 17 | setb $600,$07 18 | setb $700,$06 19 | setb $7F0,$E8 ; INX 20 | setb $7F1,$60 ; RTS 21 | setb $6F0,$60 ; RTS 22 | ldx #0 23 | jsr jmp_6ff 24 | cpx #1 25 | jne test_failed 26 | 27 | set_test 4,"RTI should return to addr" 28 | lda #>:+ 29 | pha 30 | lda #<:+ 31 | pha 32 | ldx #0 33 | php 34 | rti 35 | inx 36 | : inx 37 | inx 38 | cpx #2 39 | jne test_failed 40 | 41 | set_test 5,"BRK should push status with bits 4 and 5 set" 42 | lda #$00 43 | pha 44 | plp 45 | brk 46 | nop 47 | cmp #$30 48 | jne test_failed 49 | lda #$FF 50 | pha 51 | plp 52 | brk 53 | nop 54 | cmp #$FF 55 | jne test_failed 56 | 57 | set_test 6,"BRK should push address BRK + 2" 58 | ldx #1 59 | brk 60 | inx 61 | inx 62 | cpx #2 63 | jne test_failed 64 | 65 | jmp tests_passed 66 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/common/ascii.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/instr_test-v5/source/common/ascii.chr -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/common/bootloader.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/instr_test-v5/source/common/bootloader.bin -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/common/neshw.inc: -------------------------------------------------------------------------------- 1 | ; NES I/O locations and masks 2 | 3 | .ifndef BUILD_NSF 4 | 5 | ; PPU 6 | PPUCTRL = $2000 7 | PPUMASK = $2001 8 | PPUSTATUS = $2002 9 | SPRADDR = $2003 10 | SPRDATA = $2004 11 | PPUSCROLL = $2005 12 | PPUADDR = $2006 13 | PPUDATA = $2007 14 | SPRDMA = $4014 15 | 16 | PPUCTRL_NMI = $80 17 | PPUMASK_BG0 = $0A 18 | PPUCTRL_8X8 = $00 19 | PPUCTRL_8X16 = $20 20 | PPUMASK_SPR = $14 21 | PPUMASK_BG0CLIP = $08 22 | 23 | .endif 24 | 25 | ; APU 26 | SNDCHN = $4015 27 | JOY1 = $4016 28 | JOY2 = $4017 29 | SNDMODE = $4017 30 | 31 | SNDMODE_NOIRQ = $40 32 | 33 | .ifndef REGION_FREE 34 | .ifndef PAL_ONLY 35 | .ifndef NTSC_ONLY 36 | NTSC_ONLY = 1 37 | .endif 38 | .endif 39 | .else 40 | .ifdef NTSC_ONLY 41 | .error "NTSC_ONLY and REGION_FREE defined" 42 | .endif 43 | .ifdef PAL_ONLY 44 | .error "PAL_ONLY and REGION_FREE defined" 45 | .endif 46 | .endif 47 | 48 | .ifdef NTSC_ONLY 49 | CLOCK_RATE = 1789773 50 | PPU_FRAMELEN = 29781 51 | .endif 52 | 53 | .ifdef PAL_ONLY 54 | CLOCK_RATE = 1662607 55 | PPU_FRAMELEN = 33248 56 | .endif 57 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/common/shell.inc: -------------------------------------------------------------------------------- 1 | ; Included at beginning of program 2 | 3 | .ifdef CUSTOM_PREFIX 4 | .include "custom_prefix.s" 5 | .endif 6 | 7 | ; Sub-test in a multi-test ROM 8 | .ifdef BUILD_MULTI 9 | .include "build_multi.s" 10 | .else 11 | 12 | ; NSF music file 13 | .ifdef BUILD_NSF 14 | .include "build_nsf.s" 15 | .endif 16 | 17 | ; Devcart 18 | .ifdef BUILD_DEVCART 19 | .include "build_devcart.s" 20 | .endif 21 | 22 | ; NES internal RAM 23 | .ifdef BUILD_NOCART 24 | .include "build_nocart.s" 25 | .endif 26 | 27 | ; NES ROM (default) 28 | .ifndef SHELL_INCLUDED 29 | .include "build_rom.s" 30 | .endif 31 | 32 | .endif ; .ifdef BUILD_MULTI 33 | -------------------------------------------------------------------------------- /nes-testsuite/roms/instr_test-v5/source/common/text_out.s: -------------------------------------------------------------------------------- 1 | ; Text output as expanding zero-terminated string at text_out_base 2 | 3 | ; The final exit result byte is written here 4 | final_result = $6000 5 | 6 | ; Text output is written here as an expanding 7 | ; zero-terminated string 8 | text_out_base = $6004 9 | 10 | bss_res text_out_temp 11 | zp_res text_out_addr,2 12 | 13 | init_text_out: 14 | ldx #0 15 | 16 | ; Put valid data first 17 | setb text_out_base,0 18 | 19 | lda #$80 20 | jsr set_final_result 21 | 22 | ; Now fill in signature that tells emulator there's 23 | ; useful data there 24 | setb text_out_base-3,$DE 25 | setb text_out_base-2,$B0 26 | setb text_out_base-1,$61 27 | 28 | ldx #>text_out_base 29 | stx text_out_addr+1 30 | setb text_out_addr,text_out_base 29 | stx text_out_addr+1 30 | setb text_out_addr,text_out_base 29 | stx text_out_addr+1 30 | setb text_out_addr,= 239 25 | ldx #$1e 26 | jsr sprite_should_miss 27 | 28 | lda #238 29 | sta sprite_y 30 | lda #3;) Can hit when Y < 239 31 | ldx #$1e 32 | jsr sprite_should_hit 33 | 34 | lda #255 35 | sta sprite_y 36 | lda #4;) Should always miss when Y = 255 37 | ldx #$1e 38 | jsr sprite_should_miss 39 | 40 | ; Detailed 41 | 42 | lda #lower_right_tile 43 | sta sprite_tile 44 | lda #231 45 | sta sprite_y 46 | lda #5;) Should hit; sprite pixel is at 238 47 | ldx #$1e 48 | jsr sprite_should_hit 49 | 50 | lda #232 51 | sta sprite_y 52 | lda #6;) Should miss; sprite pixel is at 239 53 | ldx #$1e 54 | jsr sprite_should_miss 55 | 56 | lda #upper_left_tile 57 | sta sprite_tile 58 | lda #238 59 | sta sprite_y 60 | lda #7;) Should hit; sprite pixel is at 238 61 | ldx #$1e 62 | jsr sprite_should_hit 63 | 64 | jmp tests_passed 65 | 66 | -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_hit_tests_2005.10.05/source/08.double_height.asm: -------------------------------------------------------------------------------- 1 | ; Tests basic sprite 0 hit double-height operation. 2 | 3 | .include "prefix_sprite_hit.a" 4 | 5 | test_name: 6 | .db "SPRITE HIT DOUBLE HEIGHT",0 7 | .code 8 | 9 | reset: 10 | jsr begin_sprite_hit_tests 11 | 12 | lda #$20 ; double-height sprites 13 | sta $2000 14 | 15 | ; Single solid tile in middle of screen 16 | lda #$21 17 | ldx #$f0 18 | jsr set_vaddr 19 | lda #solid_tile 20 | sta $2007 21 | 22 | lda #0 23 | sta sprite_attr 24 | lda #0 ; tiles 0 and 1 25 | sta sprite_tile 26 | 27 | ldx #128 28 | ldy #119 29 | jsr set_sprite_xy 30 | lda #2;) Lower sprite tile should miss bottom of bg tile 31 | ldx #$18 32 | jsr sprite_should_miss 33 | 34 | ldx #128 35 | ldy #118 36 | jsr set_sprite_xy 37 | lda #3;) Lower sprite tile should hit bottom of bg tile 38 | ldx #$18 39 | jsr sprite_should_hit 40 | 41 | ldx #128 42 | ldy #103 43 | jsr set_sprite_xy 44 | lda #3;) Lower sprite tile should miss top of bg tile 45 | ldx #$18 46 | jsr sprite_should_miss 47 | 48 | ldx #128 49 | ldy #104 50 | jsr set_sprite_xy 51 | lda #4;) Lower sprite tile should hit top of bg tile 52 | ldx #$18 53 | jsr sprite_should_hit 54 | 55 | jmp tests_passed 56 | -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_hit_tests_2005.10.05/source/10.timing_order.asm: -------------------------------------------------------------------------------- 1 | ; Tests sprite 0 hit timing for which pixel it first reports hit on. 2 | ; Each test hits at the same location on screen, though different 3 | ; relative to the position of the sprite. 4 | 5 | .include "prefix_sprite_hit.a" 6 | 7 | test_name: 8 | .db "SPRITE HIT ORDER",0 9 | .code 10 | 11 | test_hit_time: 12 | jsr set_sprite_xy 13 | ldx #$18 14 | jsr begin_sprite_hit_timing 15 | ldy #88 ; 15511 delay 16 | lda #34 17 | jsr delay_ya6 18 | ldx $2002 ; timing really tight here 19 | ldy $2002 20 | jsr check_sprite_hit_timing 21 | rts 22 | .code 23 | 24 | reset: 25 | jsr begin_sprite_hit_tests 26 | 27 | ; Solid tile in middle of screen 28 | lda #blank_tile 29 | jsr fill_nametable 30 | lda #$21 31 | ldx #$f0 32 | jsr set_vaddr 33 | lda #solid_tile 34 | sta $2007 35 | 36 | lda #0 37 | sta sprite_attr 38 | lda #solid_tile 39 | sta sprite_tile 40 | 41 | lda #2;) Upper-left corner 42 | ldx #128 43 | ldy #119 44 | jsr test_hit_time 45 | 46 | lda #4;) Upper-right corner 47 | ldx #123 48 | ldy #119 49 | jsr test_hit_time 50 | 51 | lda #6;) Lower-left corner 52 | ldx #128 53 | ldy #114 54 | jsr test_hit_time 55 | 56 | lda #8;) Lower-right corner 57 | ldx #123 58 | ldy #114 59 | jsr test_hit_time 60 | 61 | jmp tests_passed 62 | -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_hit_tests_2005.10.05/source/11.edge_timing.asm: -------------------------------------------------------------------------------- 1 | ; Tests sprite 0 hit timing for which pixel it first reports hit on 2 | ; when some pixels are under clip, or at or beyond right edge. 3 | 4 | .include "prefix_sprite_hit.a" 5 | 6 | test_name: 7 | .db "SPRITE HIT EDGE TIMING",0 8 | .code 9 | 10 | reset: 11 | jsr begin_sprite_hit_tests 12 | 13 | lda #solid_tile 14 | jsr fill_nametable 15 | 16 | lda #120 17 | sta sprite_y 18 | lda #two_corners_tile 19 | sta sprite_tile 20 | lda #0 21 | sta sprite_attr 22 | 23 | lda #7 24 | sta sprite_x 25 | lda #2;) Hit time shouldn't be based on pixels under left clip 26 | ldx #$18 27 | jsr begin_sprite_hit_timing 28 | ldy #27 ; 16380 delay 29 | lda #120 30 | jsr delay_ya1 31 | lda $2002 32 | and #$40 33 | jsr error_if_ne 34 | 35 | lda #$80 36 | sta sprite_attr 37 | 38 | lda #248 39 | sta sprite_x 40 | lda #3;) Hit time shouldn't be based on pixels at X=255 41 | ldx #$18 42 | jsr begin_sprite_hit_timing 43 | ldy #41 ; 16458 delay 44 | lda #79 45 | jsr delay_ya0 46 | lda $2002 47 | and #$40 48 | jsr error_if_ne 49 | 50 | lda #249 51 | sta sprite_x 52 | lda #4;) Hit time shouldn't be based on pixels off right edge 53 | ldx #$18 54 | jsr begin_sprite_hit_timing 55 | ldy #41 ; 16458 delay 56 | lda #79 57 | jsr delay_ya0 58 | lda $2002 59 | and #$40 60 | jsr error_if_ne 61 | 62 | jmp tests_passed 63 | -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_hit_tests_2005.10.05/source/runtime/debug.a: -------------------------------------------------------------------------------- 1 | 2 | ; Beep A times. Made to require minimal features from APU. 3 | debug_beeps: 4 | beep_loop: 5 | pha 6 | 7 | lda #1 ; set up square 1 8 | sta $4015 9 | sta $4003 10 | sta $4001 11 | sta $4002 12 | 13 | lda #$0f ; fade volume 14 | : pha 15 | eor #$30 16 | sta $4000 17 | lda #8 18 | jsr delay_msec 19 | pla 20 | clc 21 | adc #-1 22 | bpl - 23 | 24 | sta $4015 ; silence square for a bit 25 | lda #120 26 | jsr delay_msec 27 | 28 | pla 29 | clc 30 | adc #-1 31 | bne beep_loop 32 | rts 33 | .code 34 | 35 | ; Print address YA to console as $hhhh 36 | ; Preserved: A, X, Y 37 | debug_addr: 38 | pha 39 | lda #36 ; '$' 40 | jsr debug_char 41 | tya 42 | jsr hex_byte 43 | jmp debug_byte_impl 44 | .code 45 | 46 | ; Print byte A to console as $hh 47 | ; Preserved: A, X, Y 48 | debug_byte: 49 | pha 50 | lda #36 ; '$' 51 | jsr debug_char 52 | debug_byte_impl: 53 | pla 54 | pha 55 | jsr hex_byte 56 | lda #32 ; ' ' 57 | jsr debug_char_no_wait 58 | pla 59 | rts 60 | 61 | hex_byte: 62 | pha 63 | lsr a 64 | lsr a 65 | lsr a 66 | lsr a 67 | jsr nybble 68 | pla 69 | and #$0f 70 | nybble: 71 | cmp #10 72 | bcc not_letter 73 | adc #6 ; relies on carry being set 74 | not_letter: 75 | adc #$30 76 | jmp debug_char_no_wait 77 | .code 78 | -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_hit_tests_2005.10.05/source/runtime/runtime_rom.a: -------------------------------------------------------------------------------- 1 | ; Build as standalone NES ROM using console for output 2 | 3 | .include "runtime_rom_common.a" 4 | 5 | patch_reset_then_wait: 6 | exit: jmp exit 7 | 8 | .default reset = main 9 | 10 | .org $fffa 11 | .dw nmi 12 | .dw reset 13 | .dw irq 14 | -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_hit_tests_2005.10.05/source/runtime/runtime_rom_common.a: -------------------------------------------------------------------------------- 1 | 2 | .include "delays.a" 3 | .include "console.a" 4 | .include "debug.a" 5 | .include "ppu_util.a" 6 | 7 | console_ready = $7f1 8 | 9 | debug_char: 10 | pha 11 | lda #$a5 12 | cmp console_ready 13 | beq + 14 | sta console_ready 15 | txa 16 | pha 17 | tya 18 | pha 19 | jsr init_console 20 | pla 21 | tay 22 | pla 23 | tax 24 | : pla 25 | jmp print_char 26 | 27 | debug_newline: 28 | jsr console_newline 29 | jmp console_newline 30 | 31 | debug_char_no_wait: 32 | jmp print_char_no_wait 33 | 34 | init_runtime: 35 | clear_console_ready: 36 | lda #0 37 | sta console_ready 38 | rts 39 | 40 | forever: 41 | sei ; disable interrupts 42 | lda #0 43 | sta $2000 44 | jsr clear_console_ready 45 | jmp exit 46 | -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_hit_timing/sprite_hit_timing.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/sprite_hit_timing/sprite_hit_timing.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_overflow_tests/1.Basics.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/sprite_overflow_tests/1.Basics.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_overflow_tests/2.Details.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/sprite_overflow_tests/2.Details.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_overflow_tests/3.Timing.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/sprite_overflow_tests/3.Timing.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_overflow_tests/4.Obscure.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/sprite_overflow_tests/4.Obscure.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_overflow_tests/5.Emulator.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/sprite_overflow_tests/5.Emulator.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_overflow_tests/source/runtime_rom.a: -------------------------------------------------------------------------------- 1 | ; Build as standalone NES ROM using console for output 2 | 3 | .include "runtime_rom_common.a" 4 | 5 | patch_reset_then_wait: 6 | exit: jmp exit 7 | 8 | .default reset = main 9 | 10 | .org $fffa 11 | .dw nmi 12 | .dw reset 13 | .dw irq 14 | -------------------------------------------------------------------------------- /nes-testsuite/roms/sprite_overflow_tests/source/runtime_rom_common.a: -------------------------------------------------------------------------------- 1 | 2 | .include "delays.a" 3 | .include "console.a" 4 | .include "debug.a" 5 | .include "ppu_util.a" 6 | 7 | console_ready = $7f1 8 | 9 | debug_char: 10 | pha 11 | lda #$a5 12 | cmp console_ready 13 | beq + 14 | sta console_ready 15 | txa 16 | pha 17 | tya 18 | pha 19 | jsr init_console 20 | pla 21 | tay 22 | pla 23 | tax 24 | : pla 25 | jmp print_char 26 | 27 | debug_newline: 28 | jsr console_newline 29 | jmp console_newline 30 | 31 | debug_char_no_wait: 32 | jmp print_char_no_wait 33 | 34 | init_runtime: 35 | clear_console_ready: 36 | lda #0 37 | sta console_ready 38 | rts 39 | 40 | forever: 41 | sei ; disable interrupts 42 | lda #0 43 | sta $2000 44 | jsr clear_console_ready 45 | jmp exit 46 | -------------------------------------------------------------------------------- /nes-testsuite/roms/vbl_nmi_timing/1.frame_basics.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/vbl_nmi_timing/1.frame_basics.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/vbl_nmi_timing/2.vbl_timing.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/vbl_nmi_timing/2.vbl_timing.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/vbl_nmi_timing/3.even_odd_frames.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/vbl_nmi_timing/3.even_odd_frames.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/vbl_nmi_timing/4.vbl_clear_timing.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/vbl_nmi_timing/4.vbl_clear_timing.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/vbl_nmi_timing/5.nmi_suppression.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/vbl_nmi_timing/5.nmi_suppression.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/vbl_nmi_timing/6.nmi_disable.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/vbl_nmi_timing/6.nmi_disable.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/vbl_nmi_timing/7.nmi_timing.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes-testsuite/roms/vbl_nmi_timing/7.nmi_timing.nes -------------------------------------------------------------------------------- /nes-testsuite/roms/vbl_nmi_timing/source/4.vbl_clear_timing.a: -------------------------------------------------------------------------------- 1 | ; Tests timing of VBL flag clearing. 2 | 3 | .include "prefix_ppu.a" 4 | 5 | test_name: 6 | .db "VBL CLEAR TIMING",0 7 | 8 | test_too_soon: 9 | ldy #2 ; 2291 delay 10 | lda #226 11 | jsr delay_ya2 12 | lda $2002 13 | and #$80 14 | jsr error_if_eq 15 | lda $2002 16 | and #$80 17 | jsr error_if_ne 18 | rts 19 | 20 | test_too_late: 21 | ldy #2 ; 2292 delay 22 | lda #226 23 | jsr delay_ya3 24 | lda $2002 25 | and #$80 26 | jsr error_if_ne 27 | rts 28 | .code 29 | 30 | reset: 31 | jsr begin_ppu_test 32 | 33 | lda #2;) Cleared 3 or more PPU clocks too early 34 | sta "] 5 | 6 | [dependencies] 7 | log = { version = "0.4", default-features = false, optional = true } 8 | bitflags = "2.4.0" 9 | softfloat = { version = "1.0.0" } 10 | 11 | [dependencies.emumisc] 12 | path = "../emumisc" 13 | 14 | [dependencies.mos6502] 15 | path = "../mos6502" 16 | default-features = false 17 | 18 | [dev-dependencies.nes-testsuite] 19 | path = "../nes-testsuite" 20 | 21 | [dev-dependencies.rp2c02-testsuite] 22 | path = "../rp2c02-testsuite" 23 | 24 | [features] 25 | default = ["std"] 26 | std = ["mos6502/std", "log", "log/std"] 27 | softfloat = [] 28 | -------------------------------------------------------------------------------- /nes/data/FBX-Final.pal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/nes/data/FBX-Final.pal -------------------------------------------------------------------------------- /nes/src/float_native.rs: -------------------------------------------------------------------------------- 1 | pub type F32 = f32; 2 | pub type F64 = f64; 3 | 4 | #[macro_export] 5 | macro_rules! f32 { 6 | ($value:expr) => { $value } 7 | } 8 | 9 | #[macro_export] 10 | macro_rules! f64 { 11 | ($value:expr) => { $value } 12 | } 13 | 14 | pub fn u8_to_f32( value: u8 ) -> F32 { 15 | value as f32 16 | } 17 | 18 | pub fn f32_to_u32( value: F32 ) -> u32 { 19 | value as u32 20 | } 21 | -------------------------------------------------------------------------------- /nes/src/float_softfloat.rs: -------------------------------------------------------------------------------- 1 | pub use softfloat::F32; 2 | 3 | #[cfg(feature = "softfloat")] 4 | pub use softfloat::F64; 5 | 6 | #[inline] 7 | pub const fn u8_to_f32( value: u8 ) -> F32 { 8 | F32::from_u32( value as u32 ) 9 | } 10 | 11 | #[inline] 12 | pub const fn f32_to_u32( value: F32 ) -> u32 { 13 | value.to_u32() 14 | } 15 | -------------------------------------------------------------------------------- /nes/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | #![allow(dead_code)] 4 | #![allow(non_camel_case_types)] 5 | #![allow(non_upper_case_globals)] 6 | #![allow(non_snake_case)] 7 | #![allow(missing_copy_implementations)] 8 | 9 | #[cfg(feature = "std")] 10 | extern crate std as core; 11 | 12 | #[cfg(feature = "std")] 13 | extern crate std as alloc; 14 | 15 | #[cfg(not(feature = "std"))] 16 | extern crate alloc; 17 | 18 | #[cfg(feature = "log")] 19 | #[macro_use] 20 | extern crate log; 21 | 22 | #[macro_use] 23 | extern crate emumisc; 24 | extern crate mos6502; 25 | 26 | #[macro_use] 27 | extern crate bitflags; 28 | 29 | #[cfg(test)] 30 | #[macro_use] 31 | extern crate nes_testsuite; 32 | 33 | #[cfg(test)] 34 | #[macro_use] 35 | extern crate rp2c02_testsuite; 36 | 37 | #[cfg_attr(feature = "softfloat", macro_use)] 38 | extern crate softfloat; 39 | 40 | mod float_softfloat; 41 | 42 | #[cfg(feature = "softfloat")] 43 | use float_softfloat as float; 44 | 45 | #[cfg(not(feature = "softfloat"))] 46 | #[macro_use] 47 | mod float_native; 48 | 49 | #[cfg(not(feature = "softfloat"))] 50 | use float_native as float; 51 | 52 | mod memory_map; 53 | mod rp2c02_scheduler; 54 | mod rp2c02; 55 | mod virtual_apu; 56 | mod virtual_nes; 57 | mod rom; 58 | mod mappers; 59 | mod generic_mapper; 60 | mod mapper_mmc1; 61 | mod mapper_uxrom; 62 | mod mapper_unrom512; 63 | mod mapper_axrom; 64 | mod orphan; 65 | mod dma; 66 | mod filter; 67 | 68 | #[cfg(test)] 69 | mod testsuite; 70 | 71 | pub use virtual_nes::{Interface, State, Context, Button, ControllerPort, Error}; 72 | pub use rp2c02::{Framebuffer, Palette}; 73 | pub use rom::LoadError; 74 | -------------------------------------------------------------------------------- /nes/src/mapper_axrom.rs: -------------------------------------------------------------------------------- 1 | use emumisc::BitExtra; 2 | use rom::{NesRom, LoadError}; 3 | use generic_mapper::BankedGenericMapper; 4 | use mappers::Mapper; 5 | 6 | pub struct MapperAxROM { 7 | inner: BankedGenericMapper 8 | } 9 | 10 | impl MapperAxROM { 11 | pub fn from_rom( rom: NesRom ) -> Result< Self, LoadError > { 12 | let mut mapper = MapperAxROM { 13 | inner: BankedGenericMapper::from_rom( rom )? 14 | }; 15 | 16 | mapper.inner.set_cpu_32k_bank_to_bank( 0 ); 17 | mapper.inner.set_only_lower_bank_mirroring(); 18 | 19 | Ok( mapper ) 20 | } 21 | } 22 | 23 | impl Mapper for MapperAxROM { 24 | fn peek_sram( &self, address: u16 ) -> u8 { 25 | self.inner.peek_sram( address ) 26 | } 27 | 28 | fn poke_sram( &mut self, address: u16, value: u8 ) { 29 | self.inner.poke_sram( address, value ) 30 | } 31 | 32 | fn peek_rom( &self, address: u16 ) -> u8 { 33 | self.inner.peek_rom( address ) 34 | } 35 | 36 | fn poke_rom( &mut self, _: u16, value: u8 ) { 37 | let rom_bank = value.get_bits( 0b0000_0111 ); 38 | let tilemap_bank = value.get_bits( 0b0001_0000 ); 39 | 40 | self.inner.set_cpu_32k_bank_to_bank( rom_bank ); 41 | if tilemap_bank == 0 { 42 | self.inner.set_only_lower_bank_mirroring(); 43 | } else { 44 | self.inner.set_only_upper_bank_mirroring(); 45 | } 46 | } 47 | 48 | fn peek_video_memory( &self, address: u16 ) -> u8 { 49 | self.inner.peek_video_memory( address ) 50 | } 51 | 52 | fn poke_video_memory( &mut self, address: u16, value: u8 ) { 53 | self.inner.poke_video_memory( address, value ) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /nes/src/mapper_uxrom.rs: -------------------------------------------------------------------------------- 1 | use rom::{NesRom, LoadError}; 2 | use generic_mapper::BankedGenericMapper; 3 | use mappers::Mapper; 4 | 5 | // This is a very simple mapper. At 0x8000 - 0xBFFF 6 | // we have a switchable ROM bank, and the 0xC000 - 0xFFFF 7 | // is fixed to the last bank. The lower ROM bank is 8 | // switched by writing to 0x8000 - 0xFFFF. 9 | 10 | pub struct MapperUxROM { 11 | inner: BankedGenericMapper 12 | } 13 | 14 | impl MapperUxROM { 15 | pub fn from_rom( rom: NesRom ) -> Result< Self, LoadError > { 16 | let mut mapper = MapperUxROM { 17 | inner: BankedGenericMapper::from_rom( rom )? 18 | }; 19 | 20 | let last_bank = mapper.inner.last_rom_16k_bank(); 21 | mapper.inner.set_cpu_lower_16k_bank_to_bank( 0 ); 22 | mapper.inner.set_cpu_upper_16k_bank_to_bank( last_bank ); 23 | 24 | Ok( mapper ) 25 | } 26 | } 27 | 28 | impl Mapper for MapperUxROM { 29 | fn peek_sram( &self, address: u16 ) -> u8 { 30 | self.inner.peek_sram( address ) 31 | } 32 | 33 | fn poke_sram( &mut self, address: u16, value: u8 ) { 34 | self.inner.poke_sram( address, value ) 35 | } 36 | 37 | fn peek_rom( &self, address: u16 ) -> u8 { 38 | self.inner.peek_rom( address ) 39 | } 40 | 41 | fn poke_rom( &mut self, _: u16, value: u8 ) { 42 | self.inner.set_cpu_lower_16k_bank_to_bank( value ); 43 | } 44 | 45 | fn peek_video_memory( &self, address: u16 ) -> u8 { 46 | self.inner.peek_video_memory( address ) 47 | } 48 | 49 | fn poke_video_memory( &mut self, address: u16, value: u8 ) { 50 | self.inner.poke_video_memory( address, value ) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /nes/src/orphan.rs: -------------------------------------------------------------------------------- 1 | use core::mem; 2 | use core::ops::{Deref, DerefMut}; 3 | 4 | // A shim like this is necessary to implement an orphaned instance in Rust. 5 | // It's very important to keep the structure opaque to keep it safe to use. 6 | pub struct Orphan< T >( T ); 7 | 8 | impl< T > Orphan< T > { 9 | #[inline] 10 | pub fn cast( value: &T ) -> &Orphan< T > { 11 | unsafe { 12 | mem::transmute( value ) 13 | } 14 | } 15 | 16 | #[inline] 17 | pub fn cast_mut( value: &mut T ) -> &mut Orphan< T > { 18 | unsafe { 19 | mem::transmute( value ) 20 | } 21 | } 22 | } 23 | 24 | impl< T > Deref for Orphan< T > { 25 | type Target = T; 26 | 27 | #[inline] 28 | fn deref( &self ) -> &Self::Target { 29 | &self.0 30 | } 31 | } 32 | 33 | impl< T > DerefMut for Orphan< T > { 34 | #[inline] 35 | fn deref_mut( &mut self ) -> &mut Self::Target { 36 | &mut self.0 37 | } 38 | } 39 | 40 | impl< T > AsRef< T > for Orphan< T > { 41 | #[inline] 42 | fn as_ref( &self ) -> &T { 43 | &self.0 44 | } 45 | } 46 | 47 | impl< T > AsMut< T > for Orphan< T > { 48 | #[inline] 49 | fn as_mut( &mut self ) -> &mut T { 50 | &mut self.0 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /pinky-devui/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "pinky-devui" 4 | version = "0.1.0" 5 | authors = [ "Jan Bujak " ] 6 | 7 | [[bin]] 8 | 9 | name = "pinky-devui" 10 | 11 | [dependencies] 12 | sdl2 = "0.27" 13 | clock_ticks = "0.1" 14 | serde_json = "0.7" 15 | md5 = "0.1" 16 | env_logger = "0.3" 17 | 18 | [dependencies.emumisc] 19 | path = "../emumisc" 20 | 21 | [dependencies.nes] 22 | path = "../nes" 23 | 24 | [profile.dev] 25 | opt-level = 2 26 | debug = true 27 | rpath = false 28 | lto = false 29 | debug-assertions = true 30 | codegen-units = 4 31 | 32 | [profile.release] 33 | opt-level = 3 34 | debug = false 35 | rpath = false 36 | lto = true 37 | debug-assertions = false 38 | codegen-units = 1 39 | -------------------------------------------------------------------------------- /pinky-devui/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate std as core; 2 | 3 | extern crate sdl2; 4 | extern crate clock_ticks; 5 | extern crate serde_json; 6 | extern crate md5; 7 | extern crate env_logger; 8 | 9 | #[macro_use] 10 | extern crate emumisc; 11 | 12 | extern crate nes; 13 | 14 | mod user_interface; 15 | mod renderer; 16 | mod frame_limiter; 17 | 18 | fn main() { 19 | env_logger::init().unwrap(); 20 | 21 | let mut ui = user_interface::create(); 22 | ui.run(); 23 | } 24 | -------------------------------------------------------------------------------- /pinky-libretro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pinky-libretro" 3 | version = "0.1.0" 4 | authors = ["Jan Bujak "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | libretro-backend = "0.2" 11 | 12 | [dependencies.nes] 13 | path = "../nes" 14 | 15 | [dependencies.emumisc] 16 | path = "../emumisc" 17 | 18 | [profile.dev] 19 | opt-level = 2 20 | debug = true 21 | rpath = false 22 | lto = false 23 | debug-assertions = true 24 | codegen-units = 4 25 | 26 | [profile.release] 27 | opt-level = 3 28 | debug = false 29 | rpath = false 30 | lto = true 31 | debug-assertions = false 32 | codegen-units = 1 33 | -------------------------------------------------------------------------------- /pinky-web/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pinky-web" 3 | version = "0.1.0" 4 | authors = ["Jan Bujak "] 5 | 6 | [dependencies] 7 | serde = "1" 8 | serde_derive = "1" 9 | 10 | [dependencies.stdweb] 11 | version = "0.4" 12 | 13 | [dependencies.nes] 14 | path = "../nes" 15 | 16 | [profile.dev] 17 | opt-level = 2 18 | debug = true 19 | rpath = false 20 | lto = false 21 | debug-assertions = true 22 | codegen-units = 4 23 | 24 | [profile.release] 25 | opt-level = 3 26 | debug = false 27 | rpath = false 28 | lto = true 29 | debug-assertions = false 30 | codegen-units = 1 31 | -------------------------------------------------------------------------------- /pinky-web/README.md: -------------------------------------------------------------------------------- 1 | This is the Web frontend for Pinky. 2 | 3 | It's mostly meant as a demo for Rust's WebAssembly capabilities 4 | and the [stdweb] project. 5 | 6 | [stdweb]: https://github.com/koute/stdweb 7 | 8 | [![Become a patron](https://koute.github.io/img/become_a_patron_button.png)](https://www.patreon.com/koute) 9 | 10 | ### See it in action 11 | 12 | * A version [compiled with Rust's native WebAssembly backend] (recommended!). 13 | * A version [compiled to WebAssembly with Emscripten]. 14 | * A version [compiled to asm.js with Emscripten]. 15 | 16 | [compiled with Rust's native WebAssembly backend]: https://koute.github.io/pinky-web 17 | [compiled to WebAssembly with Emscripten]: https://koute.github.io/pinky-web-webasm-emscripten 18 | [compiled to asm.js with Emscripten]: https://koute.github.io/pinky-web-asmjs-emscripten 19 | 20 | ### Building (using Rust's native WebAssembly backend) 21 | 22 | 1. Install newest Rust: 23 | 24 | $ curl https://sh.rustup.rs -sSf | sh 25 | 26 | 2. Install nightly: 27 | 28 | $ rustup install nightly 29 | $ rustup default nightly 30 | 31 | 3. Install [cargo-web]: 32 | 33 | $ cargo install -f cargo-web 34 | 35 | 4. Build it: 36 | 37 | $ cargo web start --release 38 | 39 | 5. Visit `http://localhost:8000` with your browser. 40 | 41 | [cargo-web]: https://github.com/koute/cargo-web 42 | 43 | ### Building for other backends 44 | 45 | You can add `--target=asmjs-unknown-emscripten` or `--target=wasm32-unknown-emscripten` argument 46 | to build it using another backend. 47 | -------------------------------------------------------------------------------- /pinky-web/Web.toml: -------------------------------------------------------------------------------- 1 | default-target = "wasm32-unknown-unknown" 2 | -------------------------------------------------------------------------------- /pinky-web/static/roms/alter_ego.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/pinky-web/static/roms/alter_ego.nes -------------------------------------------------------------------------------- /pinky-web/static/roms/cheril_the_goddess.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/pinky-web/static/roms/cheril_the_goddess.nes -------------------------------------------------------------------------------- /pinky-web/static/roms/dushlan.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/pinky-web/static/roms/dushlan.nes -------------------------------------------------------------------------------- /pinky-web/static/roms/index.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Alter Ego", 4 | "file": "alter_ego.nes" 5 | }, 6 | { 7 | "name": "Cheril the Goddess", 8 | "file": "cheril_the_goddess.nes" 9 | }, 10 | { 11 | "name": "Dushlan", 12 | "file": "dushlan.nes" 13 | }, 14 | { 15 | "name": "Lawn Mower", 16 | "file": "lawn_mower.nes" 17 | }, 18 | { 19 | "name": "Mad Wizard", 20 | "file": "mad_wizard.nes" 21 | }, 22 | { 23 | "name": "Micro Knight 4", 24 | "file": "micro_knight_4_v1_02.nes" 25 | }, 26 | { 27 | "name": "Nebs 'n Debs", 28 | "file": "nebs_n_debs_2_15_2017.nes" 29 | }, 30 | { 31 | "name": "Owlia", 32 | "file": "owlia.nes" 33 | }, 34 | { 35 | "name": "Streemerz", 36 | "file": "streemerz_v02.nes" 37 | }, 38 | { 39 | "name": "Super Painter", 40 | "file": "super_painter_1_0.nes" 41 | }, 42 | { 43 | "name": "Tiger Jenny", 44 | "file": "tiger_jenny.nes" 45 | }, 46 | { 47 | "name": "Yun", 48 | "file": "yun.nes" 49 | } 50 | ] 51 | -------------------------------------------------------------------------------- /pinky-web/static/roms/lawn_mower.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/pinky-web/static/roms/lawn_mower.nes -------------------------------------------------------------------------------- /pinky-web/static/roms/mad_wizard.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/pinky-web/static/roms/mad_wizard.nes -------------------------------------------------------------------------------- /pinky-web/static/roms/micro_knight_4_v1_02.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/pinky-web/static/roms/micro_knight_4_v1_02.nes -------------------------------------------------------------------------------- /pinky-web/static/roms/nebs_n_debs_2_15_2017.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/pinky-web/static/roms/nebs_n_debs_2_15_2017.nes -------------------------------------------------------------------------------- /pinky-web/static/roms/owlia.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/pinky-web/static/roms/owlia.nes -------------------------------------------------------------------------------- /pinky-web/static/roms/streemerz_v02.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/pinky-web/static/roms/streemerz_v02.nes -------------------------------------------------------------------------------- /pinky-web/static/roms/super_painter_1_0.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/pinky-web/static/roms/super_painter_1_0.nes -------------------------------------------------------------------------------- /pinky-web/static/roms/tiger_jenny.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/pinky-web/static/roms/tiger_jenny.nes -------------------------------------------------------------------------------- /pinky-web/static/roms/yun.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koute/pinky/5a9d4ff5f22731191cffd7d6202a1d144aacd740/pinky-web/static/roms/yun.nes -------------------------------------------------------------------------------- /rp2c02-testsuite/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rp2c02-testsuite" 3 | version = "0.1.0" 4 | authors = ["Jan Bujak "] 5 | build = "build.rs" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rp2c02-testsuite/generator/generate_current_address_during_background_rendering.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var common = require( "./common" ); 4 | var ppumask = common.ppumask; 5 | var sprite = common.sprite; 6 | 7 | common.generate( "current_address_during_background_rendering", function( ctx ) { 8 | var ppumask_value = ppumask() 9 | .set_show_background( true ) 10 | .set_show_background_in_leftmost_8_pixels( true ); 11 | 12 | ctx.fill_vram_with_test_data(); 13 | 14 | ctx.cpu_write_and_step( ppumask_value ); 15 | ctx.step_scanline(); 16 | 17 | var test = function() { 18 | ctx.test.current_address(); 19 | ctx.step_pixel(); 20 | }; 21 | 22 | ctx.repeat( 2 * 341, test ); 23 | ctx.repeat( 5, ctx.step_scanline ); 24 | ctx.repeat( 2 * 341, test ); 25 | }); 26 | -------------------------------------------------------------------------------- /rp2c02-testsuite/generator/generate_current_address_during_sprite_rendering.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _ = require( "./phantom2c02/lib/lodash" ); 4 | var common = require( "./common" ); 5 | var ppumask = common.ppumask; 6 | var sprite = common.sprite; 7 | 8 | common.generate( "current_address_during_sprite_rendering", function( ctx ) { 9 | var ppumask_value = ppumask() 10 | .set_show_sprites( true ) 11 | .set_show_sprites_in_leftmost_8_pixels( true ); 12 | 13 | ctx.fill_vram_with_test_data(); 14 | 15 | ctx.cpu_write_and_step( ppumask_value ); 16 | ctx.step_scanline(); 17 | 18 | var test = function() { 19 | ctx.repeat( 257, ctx.step_pixel ); // Skip sprite evaluation. 20 | ctx.repeat( 32, _.partial( ctx.write_secondary_oam, _, 0xFF ) ); 21 | 22 | ctx.write_sprite_to_secondary_oam( 0, sprite({ x: 0, y: 0, tile: 0xAA }) ); 23 | ctx.write_sprite_to_secondary_oam( 1, sprite({ x: 8, y: 0, tile: 0xBA, flip_h: true }) ); 24 | ctx.write_sprite_to_secondary_oam( 2, sprite({ x: 16, y: 0, tile: 0xCA, flip_v: true }) ); 25 | ctx.write_sprite_to_secondary_oam( 3, sprite({ x: 24, y: 0, tile: 0xDA, flip_h: true, flip_v: true }) ); 26 | 27 | ctx.repeat( 64, function() { 28 | ctx.test.current_address(); 29 | ctx.step_pixel(); 30 | }); 31 | ctx.step_scanline(); 32 | }; 33 | 34 | ctx.repeat( 3, test ); 35 | }); 36 | -------------------------------------------------------------------------------- /rp2c02-testsuite/generator/generate_current_address_during_sprite_rendering_without_sprites.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _ = require( "./phantom2c02/lib/lodash" ); 4 | var common = require( "./common" ); 5 | var ppumask = common.ppumask; 6 | var sprite = common.sprite; 7 | 8 | common.generate( "current_address_during_sprite_rendering_without_sprites", function( ctx ) { 9 | var ppumask_value = ppumask() 10 | .set_show_sprites( true ) 11 | .set_show_sprites_in_leftmost_8_pixels( true ); 12 | 13 | ctx.fill_vram_with_test_data(); 14 | 15 | ctx.cpu_write_and_step( ppumask_value ); 16 | ctx.step_scanline(); 17 | 18 | var test = function() { 19 | ctx.repeat( 257, ctx.step_pixel ); // Skip sprite evaluation. 20 | ctx.test.secondary_oam_contents(); // This should contain [0x00, 0xFF, 0xFF, 0xFF, ...]. 21 | 22 | ctx.repeat( 64, function() { 23 | ctx.test.current_address(); 24 | ctx.step_pixel(); 25 | }); 26 | ctx.step_scanline(); 27 | }; 28 | 29 | ctx.repeat( 24, test ); 30 | }); 31 | -------------------------------------------------------------------------------- /rp2c02-testsuite/generator/generate_current_address_when_not_rendering.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _ = require( "./phantom2c02/lib/lodash" ); 4 | var common = require( "./common" ); 5 | var ppumask = common.ppumask; 6 | var sprite = common.sprite; 7 | 8 | common.generate( "current_address_when_not_rendering", function( ctx ) { 9 | ctx.fill_vram_with_test_data(); 10 | ctx.step_scanline(); 11 | 12 | var test = function() { 13 | ctx.test.current_address(); 14 | ctx.step_pixel(); 15 | }; 16 | 17 | ctx.repeat( 2 * 341, test ); 18 | ctx.repeat( 5, ctx.step_scanline ); 19 | ctx.repeat( 2 * 341, test ); 20 | }); 21 | -------------------------------------------------------------------------------- /rp2c02-testsuite/generator/generate_vram_access_after_scrolling.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var common = require( "./common" ); 4 | var ppumask = common.ppumask; 5 | var ppuctrl = common.ppuctrl; 6 | var sprite = common.sprite; 7 | 8 | common.generate( "vram_access_after_scrolling", function( ctx ) { 9 | ctx.fill_vram_with_test_data(); 10 | 11 | var ppuctrl_value = ppuctrl() 12 | .set_base_background_tilemap( 1 ) 13 | .set_use_second_pattern_table_for_background( true ) 14 | .set_double_height_sprite_mode( true ) 15 | .set_should_generate_vblank_nmi( true ); 16 | 17 | ctx.cpu_write_and_step( ppuctrl_value ); 18 | 19 | var ppumask_value = ppumask() 20 | .set_show_background_in_leftmost_8_pixels( true ) 21 | .set_show_sprites_in_leftmost_8_pixels( true ) 22 | .set_show_background( true ) 23 | .set_show_sprites( true ); 24 | 25 | ctx.cpu_write_and_step( ppumask_value ); 26 | 27 | ctx.repeat( 255, ctx.step_pixel ); 28 | 29 | var test = function() { 30 | ctx.test.temporary_address(); 31 | ctx.test.current_address(); 32 | ctx.test.next_vram_read(); 33 | ctx.step_pixel(); 34 | }; 35 | 36 | ctx.test.temporary_address(); 37 | ctx.test.current_address(); 38 | ctx.cpu_write_and_step( 0x2005, 0x29 ); 39 | ctx.test.temporary_address(); 40 | ctx.test.current_address(); 41 | ctx.cpu_write_and_step( 0x2005, 0x00 ); 42 | ctx.repeat( 93, test ); 43 | 44 | ctx.repeat( 257, test ); 45 | 46 | ctx.test.cpu_read( 0x2002 ); 47 | ctx.cpu_write_and_step( 0x2005, 0x00 ); 48 | ctx.cpu_write_and_step( 0x2005, 0x29 ); 49 | ctx.step_scanline(); 50 | 51 | ctx.repeat( 257, test ); 52 | }); 53 | -------------------------------------------------------------------------------- /rp2c02-testsuite/generator/generate_vram_access_during_background_rendering.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var common = require( "./common" ); 4 | var ppumask = common.ppumask; 5 | var sprite = common.sprite; 6 | 7 | common.generate( "vram_access_during_background_rendering", function( ctx ) { 8 | var ppumask_value = ppumask() 9 | .set_show_background( true ) 10 | .set_show_background_in_leftmost_8_pixels( true ); 11 | 12 | ctx.fill_vram_with_test_data(); 13 | 14 | ctx.cpu_write_and_step( ppumask_value ); 15 | ctx.step_scanline(); 16 | 17 | ctx.repeat( 257, function() { 18 | ctx.test.next_vram_read(); 19 | ctx.step_pixel(); 20 | }); 21 | ctx.repeat( 64, ctx.step_pixel ); 22 | ctx.repeat( 20, function() { 23 | ctx.test.next_vram_read(); 24 | ctx.step_pixel(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /rp2c02-testsuite/generator/generate_vram_access_during_sprite_rendering.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _ = require( "./phantom2c02/lib/lodash" ); 4 | var common = require( "./common" ); 5 | var ppumask = common.ppumask; 6 | var sprite = common.sprite; 7 | 8 | common.generate( "vram_access_during_sprite_rendering", function( ctx ) { 9 | var ppumask_value = ppumask() 10 | .set_show_sprites( true ) 11 | .set_show_sprites_in_leftmost_8_pixels( true ); 12 | 13 | ctx.fill_vram_with_test_data(); 14 | 15 | ctx.cpu_write_and_step( ppumask_value ); 16 | ctx.step_scanline(); 17 | 18 | var test = function() { 19 | ctx.repeat( 257, ctx.step_pixel ); // Skip sprite evaluation. 20 | ctx.repeat( 32, _.partial( ctx.write_secondary_oam, _, 0xFF ) ); 21 | 22 | ctx.write_sprite_to_secondary_oam( 0, sprite({ x: 0, y: 0, tile: 0xAA }) ); 23 | ctx.write_sprite_to_secondary_oam( 1, sprite({ x: 8, y: 0, tile: 0xBA, flip_h: true }) ); 24 | ctx.write_sprite_to_secondary_oam( 2, sprite({ x: 16, y: 0, tile: 0xCA, flip_v: true }) ); 25 | ctx.write_sprite_to_secondary_oam( 3, sprite({ x: 24, y: 0, tile: 0xDA, flip_h: true, flip_v: true }) ); 26 | 27 | ctx.repeat( 64, function() { 28 | ctx.test.next_vram_read(); 29 | ctx.step_pixel(); 30 | }); 31 | ctx.step_scanline(); 32 | }; 33 | 34 | ctx.repeat( 3, test ); 35 | }); 36 | -------------------------------------------------------------------------------- /rp2c02-testsuite/generator/generate_vram_access_during_sprite_rendering_double_height.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _ = require( "./phantom2c02/lib/lodash" ); 4 | var common = require( "./common" ); 5 | var ppumask = common.ppumask; 6 | var ppuctrl = common.ppuctrl; 7 | var sprite = common.sprite; 8 | 9 | common.generate( "vram_access_during_sprite_rendering_double_height", function( ctx ) { 10 | var ppumask_value = ppumask() 11 | .set_show_sprites( true ) 12 | .set_show_sprites_in_leftmost_8_pixels( true ); 13 | 14 | var ppuctrl_value = ppuctrl() 15 | .set_double_height_sprite_mode( true ); 16 | 17 | ctx.fill_vram_with_test_data(); 18 | 19 | ctx.cpu_write_and_step( ppumask_value ); 20 | ctx.cpu_write_and_step( ppuctrl_value ); 21 | ctx.step_scanline(); 22 | 23 | var test = function() { 24 | ctx.repeat( 257, ctx.step_pixel ); // Skip sprite evaluation. 25 | ctx.repeat( 32, _.partial( ctx.write_secondary_oam, _, 0xFF ) ); 26 | 27 | ctx.write_sprite_to_secondary_oam( 0, sprite({ x: 0, y: 0, tile: 0xAA }) ); 28 | ctx.write_sprite_to_secondary_oam( 1, sprite({ x: 8, y: 0, tile: 0xBA, flip_h: true }) ); 29 | ctx.write_sprite_to_secondary_oam( 2, sprite({ x: 16, y: 0, tile: 0xCA, flip_v: true }) ); 30 | ctx.write_sprite_to_secondary_oam( 3, sprite({ x: 24, y: 0, tile: 0xDA, flip_h: true, flip_v: true }) ); 31 | 32 | ctx.repeat( 64, function() { 33 | ctx.test.next_vram_read(); 34 | ctx.step_pixel(); 35 | }); 36 | ctx.step_scanline(); 37 | }; 38 | 39 | ctx.repeat( 11, test ); 40 | }); 41 | -------------------------------------------------------------------------------- /rp2c02-testsuite/generator/generate_vram_access_during_sprite_rendering_without_sprites.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _ = require( "./phantom2c02/lib/lodash" ); 4 | var common = require( "./common" ); 5 | var ppumask = common.ppumask; 6 | var sprite = common.sprite; 7 | 8 | common.generate( "vram_access_during_sprite_rendering_without_sprites", function( ctx ) { 9 | var ppumask_value = ppumask() 10 | .set_show_sprites( true ) 11 | .set_show_sprites_in_leftmost_8_pixels( true ); 12 | 13 | ctx.fill_vram_with_test_data(); 14 | 15 | ctx.cpu_write_and_step( ppumask_value ); 16 | ctx.step_scanline(); 17 | 18 | var test = function() { 19 | ctx.repeat( 257, ctx.step_pixel ); // Skip sprite evaluation. 20 | ctx.test.secondary_oam_contents(); // This should contain [0x00, 0xFF, 0xFF, 0xFF, ...]. 21 | 22 | // In this test the OAM is filled with zeros. The PPU fills the secondary OAM 23 | // with 0xFF during dots 001..064; then during 065..256 it evaluates the OAM 24 | // and searches for sprites to copy to the secondary OAM. One of the quirks 25 | // of the PPU is that it *always* copies the first byte from a given sprite 26 | // slot from OAM to the secondary OAM when evaluating it, so if OAM is filled 27 | // with zeros and we haven't found any sprites to render on the next scanline 28 | // the secondary OAM will be filled with [0x00, 0xFF, 0xFF, 0xFF, ...]. 29 | 30 | ctx.repeat( 64, function() { 31 | ctx.test.next_vram_read(); 32 | ctx.step_pixel(); 33 | }); 34 | ctx.step_scanline(); 35 | }; 36 | 37 | ctx.repeat( 24, test ); 38 | }); 39 | -------------------------------------------------------------------------------- /rp2c02-testsuite/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | // TODO: Remove this once rustc will be able to compile 4 | // functions with many assertions in a reasonable time. 5 | // 6 | // See: https://github.com/rust-lang/rust/issues/37468 7 | fn assert_eq< T: PartialEq + fmt::Debug >( a: T, b: T ) { 8 | assert_eq!( a, b ); 9 | } 10 | 11 | pub trait TestPPU { 12 | fn expect_vram_read( &mut self, address: u16, value: u8 ); 13 | fn expect_no_vram_read( &mut self ); 14 | 15 | fn get_current_address( &self ) -> u16; 16 | fn get_temporary_address( &self ) -> u16; 17 | 18 | fn read_ioreg( &mut self, index: u8 ) -> u8; 19 | fn read_secondary_sprite_ram( &self, index: u8 ) -> u8; 20 | 21 | fn write_ioreg( &mut self, index: u8, value: u8 ); 22 | fn write_palette_ram( &mut self, index: u8, value: u8 ); 23 | fn write_sprite_ram( &mut self, index: u8, value: u8 ); 24 | fn write_secondary_sprite_ram( &mut self, index: u8, value: u8 ); 25 | fn write_vram( &mut self, address: u16, value: u8 ); 26 | 27 | fn scanline( &self ) -> u16; 28 | fn dot( &self ) -> u16; 29 | 30 | fn step_pixel( &mut self ); 31 | fn step_scanline( &mut self ) { 32 | let scanline = self.scanline(); 33 | while self.scanline() == scanline { 34 | self.step_pixel(); 35 | } 36 | } 37 | } 38 | 39 | #[macro_use] 40 | #[doc(hidden)] 41 | pub mod tests; 42 | --------------------------------------------------------------------------------