diff --git a/Info.plist b/Info.plist index db639ca..f52f3bc 100644 --- a/Info.plist +++ b/Info.plist @@ -19,7 +19,7 @@ CFBundleSignature ???? CFBundleVersion - 1.22.2 + 1.23.0 NSPrincipalClass OEGameCoreController OEGameCoreClass diff --git a/Mednafen.xcodeproj/project.pbxproj b/Mednafen.xcodeproj/project.pbxproj index 20464c4..eec2e5b 100644 --- a/Mednafen.xcodeproj/project.pbxproj +++ b/Mednafen.xcodeproj/project.pbxproj @@ -4747,9 +4747,9 @@ OTHER_CFLAGS = ( "-fwrapv", "-DHAVE_MKDIR", - "-DMEDNAFEN_VERSION=\\\"1.22.2\\\"", + "-DMEDNAFEN_VERSION=\\\"1.23.0-UNSTABLE\\\"", "-DPACKAGE=\\\"mednafen\\\"", - "-DMEDNAFEN_VERSION_NUMERIC=0x00102202", + "-DMEDNAFEN_VERSION_NUMERIC=0x00102300", "-DPSS_STYLE=1", "-DMPC_FIXED_POINT", "-DARCH_X86", @@ -4813,9 +4813,9 @@ OTHER_CFLAGS = ( "-fwrapv", "-DHAVE_MKDIR", - "-DMEDNAFEN_VERSION=\\\"1.22.2\\\"", + "-DMEDNAFEN_VERSION=\\\"1.23.0-UNSTABLE\\\"", "-DPACKAGE=\\\"mednafen\\\"", - "-DMEDNAFEN_VERSION_NUMERIC=0x00102202", + "-DMEDNAFEN_VERSION_NUMERIC=0x00102300", "-DPSS_STYLE=1", "-DMPC_FIXED_POINT", "-DARCH_X86", diff --git a/mednafen/Makefile.in b/mednafen/Makefile.in index f5926a3..d20d35f 100644 --- a/mednafen/Makefile.in +++ b/mednafen/Makefile.in @@ -256,7 +256,21 @@ DIST_COMMON = $(srcdir)/cdplay/Makefile.am.inc \ @WANT_SNES_EMU_TRUE@am__append_32 = libsnes.a @WANT_SNES_EMU_TRUE@am__append_33 = libsnes.a @WANT_SNES_EMU_TRUE@am__append_34 = libsnes.a -@WANT_SNES_FAUST_EMU_TRUE@am__append_35 = snes_faust/cpu.cpp snes_faust/snes.cpp snes_faust/apu.cpp snes_faust/cart.cpp snes_faust/input.cpp snes_faust/ppu.cpp +@WANT_SNES_FAUST_EMU_TRUE@am__append_35 = snes_faust/cpu.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/snes.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/apu.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/input.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/ppu.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/dsp1.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/dsp2.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/sdd1.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/cx4.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/superfx.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/sa1.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/sa1cpu.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/debug.cpp \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/dis65816.cpp @WANT_SS_EMU_TRUE@am__append_36 = ss/libss.a @WANT_SS_EMU_TRUE@am__append_37 = ss/libss.a @WANT_SSFPLAY_EMU_TRUE@am__append_38 = ss/libssfplay.a @@ -369,17 +383,12 @@ am__libngp_a_SOURCES_DIST = ngp/bios.cpp ngp/biosHLE.cpp ngp/dma.cpp \ ngp/gfx_scanline_mono.cpp ngp/gfx_scanline_colour.cpp \ ngp/interrupt.cpp ngp/mem.cpp ngp/neopop.cpp ngp/rom.cpp \ ngp/rtc.cpp ngp/sound.cpp ngp/Z80_interface.cpp \ - ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp \ - ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp \ ngp/TLCS-900h/TLCS900h_interpret_single.cpp \ - ngp/TLCS-900h/TLCS900h_disassemble_src.cpp \ ngp/TLCS-900h/TLCS900h_interpret.cpp \ ngp/TLCS-900h/TLCS900h_registers.cpp \ ngp/TLCS-900h/TLCS900h_interpret_reg.cpp \ - ngp/TLCS-900h/TLCS900h_disassemble.cpp \ ngp/TLCS-900h/TLCS900h_interpret_src.cpp \ - ngp/TLCS-900h/TLCS900h_interpret_dst.cpp \ - ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp + ngp/TLCS-900h/TLCS900h_interpret_dst.cpp @WANT_NGP_EMU_TRUE@am_libngp_a_OBJECTS = ngp/libngp_a-bios.$(OBJEXT) \ @WANT_NGP_EMU_TRUE@ ngp/libngp_a-biosHLE.$(OBJEXT) \ @WANT_NGP_EMU_TRUE@ ngp/libngp_a-dma.$(OBJEXT) \ @@ -395,17 +404,12 @@ am__libngp_a_SOURCES_DIST = ngp/bios.cpp ngp/biosHLE.cpp ngp/dma.cpp \ @WANT_NGP_EMU_TRUE@ ngp/libngp_a-rtc.$(OBJEXT) \ @WANT_NGP_EMU_TRUE@ ngp/libngp_a-sound.$(OBJEXT) \ @WANT_NGP_EMU_TRUE@ ngp/libngp_a-Z80_interface.$(OBJEXT) \ -@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_extra.$(OBJEXT) \ -@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_reg.$(OBJEXT) \ @WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/libngp_a-TLCS900h_interpret_single.$(OBJEXT) \ -@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_src.$(OBJEXT) \ @WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/libngp_a-TLCS900h_interpret.$(OBJEXT) \ @WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/libngp_a-TLCS900h_registers.$(OBJEXT) \ @WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/libngp_a-TLCS900h_interpret_reg.$(OBJEXT) \ -@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/libngp_a-TLCS900h_disassemble.$(OBJEXT) \ @WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/libngp_a-TLCS900h_interpret_src.$(OBJEXT) \ -@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/libngp_a-TLCS900h_interpret_dst.$(OBJEXT) \ -@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_dst.$(OBJEXT) +@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/libngp_a-TLCS900h_interpret_dst.$(OBJEXT) libngp_a_OBJECTS = $(am_libngp_a_OBJECTS) libsnes_a_AR = $(AR) $(ARFLAGS) libsnes_a_LIBADD = @@ -579,16 +583,21 @@ am__mednafen_SOURCES_DIST = debug.cpp error.cpp mempatcher.cpp \ sms/romdb.cpp sms/sms.cpp sms/sound.cpp sms/system.cpp \ sms/tms.cpp sms/vdp.cpp snes_faust/cpu.cpp snes_faust/snes.cpp \ snes_faust/apu.cpp snes_faust/cart.cpp snes_faust/input.cpp \ - snes_faust/ppu.cpp vb/vb.cpp vb/timer.cpp vb/input.cpp \ - vb/vip.cpp vb/vsu.cpp vb/debug.cpp wswan/gfx.cpp \ - wswan/main.cpp wswan/memory.cpp wswan/comm.cpp wswan/v30mz.cpp \ - wswan/sound.cpp wswan/tcache.cpp wswan/interrupt.cpp \ - wswan/eeprom.cpp wswan/rtc.cpp wswan/debug.cpp \ - wswan/dis/dis_decode.cpp wswan/dis/dis_groups.cpp \ - wswan/dis/resolve.cpp wswan/dis/syntax.cpp \ - hw_cpu/m68k/m68k.cpp hw_cpu/z80-fuse/z80.cpp \ - hw_cpu/z80-fuse/z80_ops.cpp hw_cpu/v810/v810_cpu.cpp \ - hw_cpu/v810/v810_cpuD.cpp hw_cpu/v810/v810_fp_ops.cpp \ + snes_faust/ppu.cpp snes_faust/cart/dsp1.cpp \ + snes_faust/cart/dsp2.cpp snes_faust/cart/sdd1.cpp \ + snes_faust/cart/cx4.cpp snes_faust/cart/superfx.cpp \ + snes_faust/cart/sa1.cpp snes_faust/cart/sa1cpu.cpp \ + snes_faust/debug.cpp snes_faust/dis65816.cpp vb/vb.cpp \ + vb/timer.cpp vb/input.cpp vb/vip.cpp vb/vsu.cpp vb/debug.cpp \ + wswan/gfx.cpp wswan/main.cpp wswan/memory.cpp wswan/comm.cpp \ + wswan/v30mz.cpp wswan/sound.cpp wswan/tcache.cpp \ + wswan/interrupt.cpp wswan/eeprom.cpp wswan/rtc.cpp \ + wswan/debug.cpp wswan/dis/dis_decode.cpp \ + wswan/dis/dis_groups.cpp wswan/dis/resolve.cpp \ + wswan/dis/syntax.cpp hw_cpu/m68k/m68k.cpp \ + hw_cpu/z80-fuse/z80.cpp hw_cpu/z80-fuse/z80_ops.cpp \ + hw_cpu/v810/v810_cpu.cpp hw_cpu/v810/v810_cpuD.cpp \ + hw_cpu/v810/v810_fp_ops.cpp \ hw_misc/arcade_card/arcade_card.cpp \ hw_sound/ym2413/emu2413.cpp hw_sound/ym2612/Ym2612_Emu.cpp \ hw_sound/gb_apu/Gb_Apu.cpp hw_sound/gb_apu/Gb_Apu_State.cpp \ @@ -851,7 +860,16 @@ am__mednafen_SOURCES_DIST = debug.cpp error.cpp mempatcher.cpp \ @WANT_SNES_FAUST_EMU_TRUE@ snes_faust/apu.$(OBJEXT) \ @WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart.$(OBJEXT) \ @WANT_SNES_FAUST_EMU_TRUE@ snes_faust/input.$(OBJEXT) \ -@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/ppu.$(OBJEXT) +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/ppu.$(OBJEXT) \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/dsp1.$(OBJEXT) \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/dsp2.$(OBJEXT) \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/sdd1.$(OBJEXT) \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/cx4.$(OBJEXT) \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/superfx.$(OBJEXT) \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/sa1.$(OBJEXT) \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/cart/sa1cpu.$(OBJEXT) \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/debug.$(OBJEXT) \ +@WANT_SNES_FAUST_EMU_TRUE@ snes_faust/dis65816.$(OBJEXT) @WANT_VB_EMU_TRUE@am__objects_20 = vb/vb.$(OBJEXT) vb/timer.$(OBJEXT) \ @WANT_VB_EMU_TRUE@ vb/input.$(OBJEXT) vb/vip.$(OBJEXT) \ @WANT_VB_EMU_TRUE@ vb/vsu.$(OBJEXT) @@ -1325,11 +1343,12 @@ mednafen_SOURCES = debug.cpp error.cpp mempatcher.cpp settings.cpp \ @WANT_NGP_EMU_TRUE@libngp_a_SOURCES = ngp/bios.cpp ngp/biosHLE.cpp ngp/dma.cpp ngp/flash.cpp ngp/gfx.cpp ngp/T6W28_Apu.cpp \ @WANT_NGP_EMU_TRUE@ ngp/gfx_scanline_mono.cpp ngp/gfx_scanline_colour.cpp ngp/interrupt.cpp ngp/mem.cpp ngp/neopop.cpp \ @WANT_NGP_EMU_TRUE@ ngp/rom.cpp ngp/rtc.cpp ngp/sound.cpp ngp/Z80_interface.cpp \ -@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp \ -@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/TLCS900h_interpret_single.cpp ngp/TLCS-900h/TLCS900h_disassemble_src.cpp \ -@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/TLCS900h_interpret.cpp ngp/TLCS-900h/TLCS900h_registers.cpp ngp/TLCS-900h/TLCS900h_interpret_reg.cpp \ -@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/TLCS900h_disassemble.cpp ngp/TLCS-900h/TLCS900h_interpret_src.cpp \ -@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/TLCS900h_interpret_dst.cpp ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp +@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/TLCS900h_interpret_single.cpp \ +@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/TLCS900h_interpret.cpp \ +@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/TLCS900h_registers.cpp \ +@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/TLCS900h_interpret_reg.cpp \ +@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/TLCS900h_interpret_src.cpp \ +@WANT_NGP_EMU_TRUE@ ngp/TLCS-900h/TLCS900h_interpret_dst.cpp @WANT_SNES_EMU_TRUE@libsnes_a_CFLAGS = @AM_CFLAGS@ @SNES_EXTRA_FLAGS@ @WANT_SNES_EMU_TRUE@libsnes_a_CXXFLAGS = @AM_CXXFLAGS@ @SNES_EXTRA_FLAGS@ @SNES_EXTRA_CXXFLAGS@ @@ -1555,18 +1574,9 @@ ngp/TLCS-900h/$(am__dirstamp): ngp/TLCS-900h/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ngp/TLCS-900h/$(DEPDIR) @: > ngp/TLCS-900h/$(DEPDIR)/$(am__dirstamp) -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_extra.$(OBJEXT): \ - ngp/TLCS-900h/$(am__dirstamp) \ - ngp/TLCS-900h/$(DEPDIR)/$(am__dirstamp) -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_reg.$(OBJEXT): \ - ngp/TLCS-900h/$(am__dirstamp) \ - ngp/TLCS-900h/$(DEPDIR)/$(am__dirstamp) ngp/TLCS-900h/libngp_a-TLCS900h_interpret_single.$(OBJEXT): \ ngp/TLCS-900h/$(am__dirstamp) \ ngp/TLCS-900h/$(DEPDIR)/$(am__dirstamp) -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_src.$(OBJEXT): \ - ngp/TLCS-900h/$(am__dirstamp) \ - ngp/TLCS-900h/$(DEPDIR)/$(am__dirstamp) ngp/TLCS-900h/libngp_a-TLCS900h_interpret.$(OBJEXT): \ ngp/TLCS-900h/$(am__dirstamp) \ ngp/TLCS-900h/$(DEPDIR)/$(am__dirstamp) @@ -1576,18 +1586,12 @@ ngp/TLCS-900h/libngp_a-TLCS900h_registers.$(OBJEXT): \ ngp/TLCS-900h/libngp_a-TLCS900h_interpret_reg.$(OBJEXT): \ ngp/TLCS-900h/$(am__dirstamp) \ ngp/TLCS-900h/$(DEPDIR)/$(am__dirstamp) -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble.$(OBJEXT): \ - ngp/TLCS-900h/$(am__dirstamp) \ - ngp/TLCS-900h/$(DEPDIR)/$(am__dirstamp) ngp/TLCS-900h/libngp_a-TLCS900h_interpret_src.$(OBJEXT): \ ngp/TLCS-900h/$(am__dirstamp) \ ngp/TLCS-900h/$(DEPDIR)/$(am__dirstamp) ngp/TLCS-900h/libngp_a-TLCS900h_interpret_dst.$(OBJEXT): \ ngp/TLCS-900h/$(am__dirstamp) \ ngp/TLCS-900h/$(DEPDIR)/$(am__dirstamp) -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_dst.$(OBJEXT): \ - ngp/TLCS-900h/$(am__dirstamp) \ - ngp/TLCS-900h/$(DEPDIR)/$(am__dirstamp) libngp.a: $(libngp_a_OBJECTS) $(libngp_a_DEPENDENCIES) $(EXTRA_libngp_a_DEPENDENCIES) $(AM_V_at)-rm -f libngp.a @@ -2549,6 +2553,30 @@ snes_faust/input.$(OBJEXT): snes_faust/$(am__dirstamp) \ snes_faust/$(DEPDIR)/$(am__dirstamp) snes_faust/ppu.$(OBJEXT): snes_faust/$(am__dirstamp) \ snes_faust/$(DEPDIR)/$(am__dirstamp) +snes_faust/cart/$(am__dirstamp): + @$(MKDIR_P) snes_faust/cart + @: > snes_faust/cart/$(am__dirstamp) +snes_faust/cart/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) snes_faust/cart/$(DEPDIR) + @: > snes_faust/cart/$(DEPDIR)/$(am__dirstamp) +snes_faust/cart/dsp1.$(OBJEXT): snes_faust/cart/$(am__dirstamp) \ + snes_faust/cart/$(DEPDIR)/$(am__dirstamp) +snes_faust/cart/dsp2.$(OBJEXT): snes_faust/cart/$(am__dirstamp) \ + snes_faust/cart/$(DEPDIR)/$(am__dirstamp) +snes_faust/cart/sdd1.$(OBJEXT): snes_faust/cart/$(am__dirstamp) \ + snes_faust/cart/$(DEPDIR)/$(am__dirstamp) +snes_faust/cart/cx4.$(OBJEXT): snes_faust/cart/$(am__dirstamp) \ + snes_faust/cart/$(DEPDIR)/$(am__dirstamp) +snes_faust/cart/superfx.$(OBJEXT): snes_faust/cart/$(am__dirstamp) \ + snes_faust/cart/$(DEPDIR)/$(am__dirstamp) +snes_faust/cart/sa1.$(OBJEXT): snes_faust/cart/$(am__dirstamp) \ + snes_faust/cart/$(DEPDIR)/$(am__dirstamp) +snes_faust/cart/sa1cpu.$(OBJEXT): snes_faust/cart/$(am__dirstamp) \ + snes_faust/cart/$(DEPDIR)/$(am__dirstamp) +snes_faust/debug.$(OBJEXT): snes_faust/$(am__dirstamp) \ + snes_faust/$(DEPDIR)/$(am__dirstamp) +snes_faust/dis65816.$(OBJEXT): snes_faust/$(am__dirstamp) \ + snes_faust/$(DEPDIR)/$(am__dirstamp) vb/$(am__dirstamp): @$(MKDIR_P) vb @: > vb/$(am__dirstamp) @@ -2968,6 +2996,7 @@ mostlyclean-compile: -rm -f snes/src/smp/*.$(OBJEXT) -rm -f snes/src/system/*.$(OBJEXT) -rm -f snes_faust/*.$(OBJEXT) + -rm -f snes_faust/cart/*.$(OBJEXT) -rm -f sound/*.$(OBJEXT) -rm -f string/*.$(OBJEXT) -rm -f tremor/*.$(OBJEXT) @@ -3278,11 +3307,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@ngp/$(DEPDIR)/libngp_a-rom.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ngp/$(DEPDIR)/libngp_a-rtc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ngp/$(DEPDIR)/libngp_a-sound.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_dst.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_extra.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_reg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_src.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_interpret.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_interpret_dst.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_interpret_reg.Po@am__quote@ @@ -3392,9 +3416,18 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@snes_faust/$(DEPDIR)/apu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@snes_faust/$(DEPDIR)/cart.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@snes_faust/$(DEPDIR)/cpu.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@snes_faust/$(DEPDIR)/debug.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@snes_faust/$(DEPDIR)/dis65816.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@snes_faust/$(DEPDIR)/input.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@snes_faust/$(DEPDIR)/ppu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@snes_faust/$(DEPDIR)/snes.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@snes_faust/cart/$(DEPDIR)/cx4.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@snes_faust/cart/$(DEPDIR)/dsp1.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@snes_faust/cart/$(DEPDIR)/dsp2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@snes_faust/cart/$(DEPDIR)/sa1.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@snes_faust/cart/$(DEPDIR)/sa1cpu.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@snes_faust/cart/$(DEPDIR)/sdd1.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@snes_faust/cart/$(DEPDIR)/superfx.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sound/$(DEPDIR)/Blip_Buffer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sound/$(DEPDIR)/DSPUtility.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sound/$(DEPDIR)/Fir_Resampler.Po@am__quote@ @@ -4120,34 +4153,6 @@ ngp/libngp_a-Z80_interface.obj: ngp/Z80_interface.cpp @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/libngp_a-Z80_interface.obj `if test -f 'ngp/Z80_interface.cpp'; then $(CYGPATH_W) 'ngp/Z80_interface.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/Z80_interface.cpp'; fi` -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_extra.o: ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_extra.o -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_extra.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_extra.o `test -f 'ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_extra.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_extra.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp' object='ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_extra.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_extra.o `test -f 'ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp - -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_extra.obj: ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_extra.obj -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_extra.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_extra.obj `if test -f 'ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_extra.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_extra.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp' object='ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_extra.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_extra.obj `if test -f 'ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp'; fi` - -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_reg.o: ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_reg.o -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_reg.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_reg.o `test -f 'ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_reg.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_reg.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp' object='ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_reg.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_reg.o `test -f 'ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp - -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_reg.obj: ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_reg.obj -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_reg.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_reg.obj `if test -f 'ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_reg.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_reg.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp' object='ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_reg.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_reg.obj `if test -f 'ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp'; fi` - ngp/TLCS-900h/libngp_a-TLCS900h_interpret_single.o: ngp/TLCS-900h/TLCS900h_interpret_single.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_interpret_single.o -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_interpret_single.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_interpret_single.o `test -f 'ngp/TLCS-900h/TLCS900h_interpret_single.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_interpret_single.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_interpret_single.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_interpret_single.Po @@ -4162,20 +4167,6 @@ ngp/TLCS-900h/libngp_a-TLCS900h_interpret_single.obj: ngp/TLCS-900h/TLCS900h_int @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_interpret_single.obj `if test -f 'ngp/TLCS-900h/TLCS900h_interpret_single.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_interpret_single.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_interpret_single.cpp'; fi` -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_src.o: ngp/TLCS-900h/TLCS900h_disassemble_src.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_src.o -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_src.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_src.o `test -f 'ngp/TLCS-900h/TLCS900h_disassemble_src.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_disassemble_src.cpp -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_src.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_src.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ngp/TLCS-900h/TLCS900h_disassemble_src.cpp' object='ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_src.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_src.o `test -f 'ngp/TLCS-900h/TLCS900h_disassemble_src.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_disassemble_src.cpp - -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_src.obj: ngp/TLCS-900h/TLCS900h_disassemble_src.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_src.obj -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_src.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_src.obj `if test -f 'ngp/TLCS-900h/TLCS900h_disassemble_src.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_disassemble_src.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_disassemble_src.cpp'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_src.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_src.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ngp/TLCS-900h/TLCS900h_disassemble_src.cpp' object='ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_src.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_src.obj `if test -f 'ngp/TLCS-900h/TLCS900h_disassemble_src.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_disassemble_src.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_disassemble_src.cpp'; fi` - ngp/TLCS-900h/libngp_a-TLCS900h_interpret.o: ngp/TLCS-900h/TLCS900h_interpret.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_interpret.o -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_interpret.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_interpret.o `test -f 'ngp/TLCS-900h/TLCS900h_interpret.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_interpret.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_interpret.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_interpret.Po @@ -4218,20 +4209,6 @@ ngp/TLCS-900h/libngp_a-TLCS900h_interpret_reg.obj: ngp/TLCS-900h/TLCS900h_interp @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_interpret_reg.obj `if test -f 'ngp/TLCS-900h/TLCS900h_interpret_reg.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_interpret_reg.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_interpret_reg.cpp'; fi` -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble.o: ngp/TLCS-900h/TLCS900h_disassemble.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_disassemble.o -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble.o `test -f 'ngp/TLCS-900h/TLCS900h_disassemble.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_disassemble.cpp -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ngp/TLCS-900h/TLCS900h_disassemble.cpp' object='ngp/TLCS-900h/libngp_a-TLCS900h_disassemble.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble.o `test -f 'ngp/TLCS-900h/TLCS900h_disassemble.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_disassemble.cpp - -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble.obj: ngp/TLCS-900h/TLCS900h_disassemble.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_disassemble.obj -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble.obj `if test -f 'ngp/TLCS-900h/TLCS900h_disassemble.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_disassemble.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_disassemble.cpp'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ngp/TLCS-900h/TLCS900h_disassemble.cpp' object='ngp/TLCS-900h/libngp_a-TLCS900h_disassemble.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble.obj `if test -f 'ngp/TLCS-900h/TLCS900h_disassemble.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_disassemble.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_disassemble.cpp'; fi` - ngp/TLCS-900h/libngp_a-TLCS900h_interpret_src.o: ngp/TLCS-900h/TLCS900h_interpret_src.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_interpret_src.o -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_interpret_src.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_interpret_src.o `test -f 'ngp/TLCS-900h/TLCS900h_interpret_src.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_interpret_src.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_interpret_src.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_interpret_src.Po @@ -4260,20 +4237,6 @@ ngp/TLCS-900h/libngp_a-TLCS900h_interpret_dst.obj: ngp/TLCS-900h/TLCS900h_interp @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_interpret_dst.obj `if test -f 'ngp/TLCS-900h/TLCS900h_interpret_dst.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_interpret_dst.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_interpret_dst.cpp'; fi` -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_dst.o: ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_dst.o -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_dst.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_dst.o `test -f 'ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_dst.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_dst.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp' object='ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_dst.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_dst.o `test -f 'ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp' || echo '$(srcdir)/'`ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp - -ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_dst.obj: ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -MT ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_dst.obj -MD -MP -MF ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_dst.Tpo -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_dst.obj `if test -f 'ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_dst.Tpo ngp/TLCS-900h/$(DEPDIR)/libngp_a-TLCS900h_disassemble_dst.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp' object='ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_dst.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libngp_a_CXXFLAGS) $(CXXFLAGS) -c -o ngp/TLCS-900h/libngp_a-TLCS900h_disassemble_dst.obj `if test -f 'ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp'; then $(CYGPATH_W) 'ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp'; else $(CYGPATH_W) '$(srcdir)/ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp'; fi` - snes/libsnes_a-interface.o: snes/interface.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsnes_a_CPPFLAGS) $(CPPFLAGS) $(libsnes_a_CXXFLAGS) $(CXXFLAGS) -MT snes/libsnes_a-interface.o -MD -MP -MF snes/$(DEPDIR)/libsnes_a-interface.Tpo -c -o snes/libsnes_a-interface.o `test -f 'snes/interface.cpp' || echo '$(srcdir)/'`snes/interface.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) snes/$(DEPDIR)/libsnes_a-interface.Tpo snes/$(DEPDIR)/libsnes_a-interface.Po @@ -4962,6 +4925,8 @@ distclean-generic: -rm -f snes/src/system/$(am__dirstamp) -rm -f snes_faust/$(DEPDIR)/$(am__dirstamp) -rm -f snes_faust/$(am__dirstamp) + -rm -f snes_faust/cart/$(DEPDIR)/$(am__dirstamp) + -rm -f snes_faust/cart/$(am__dirstamp) -rm -f sound/$(DEPDIR)/$(am__dirstamp) -rm -f sound/$(am__dirstamp) -rm -f string/$(DEPDIR)/$(am__dirstamp) @@ -4988,7 +4953,7 @@ clean-am: clean-binPROGRAMS clean-generic clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-recursive - -rm -rf ./$(DEPDIR) apple2/$(DEPDIR) cdplay/$(DEPDIR) cdrom/$(DEPDIR) cheat_formats/$(DEPDIR) compress/$(DEPDIR) cputest/$(DEPDIR) demo/$(DEPDIR) desa68/$(DEPDIR) gb/$(DEPDIR) gba/$(DEPDIR) hash/$(DEPDIR) hw_cpu/m68k/$(DEPDIR) hw_cpu/v810/$(DEPDIR) hw_cpu/z80-fuse/$(DEPDIR) hw_misc/arcade_card/$(DEPDIR) hw_sound/gb_apu/$(DEPDIR) hw_sound/pce_psg/$(DEPDIR) hw_sound/sms_apu/$(DEPDIR) hw_sound/ym2413/$(DEPDIR) hw_sound/ym2612/$(DEPDIR) hw_video/huc6270/$(DEPDIR) lynx/$(DEPDIR) md/$(DEPDIR) md/cart/$(DEPDIR) md/cd/$(DEPDIR) md/input/$(DEPDIR) minilzo/$(DEPDIR) mpcdec/$(DEPDIR) mthreading/$(DEPDIR) nes/$(DEPDIR) nes/boards/$(DEPDIR) nes/input/$(DEPDIR) nes/ntsc/$(DEPDIR) nes/ppu/$(DEPDIR) net/$(DEPDIR) ngp/$(DEPDIR) ngp/TLCS-900h/$(DEPDIR) pce/$(DEPDIR) pce/input/$(DEPDIR) pce_fast/$(DEPDIR) pcfx/$(DEPDIR) pcfx/input/$(DEPDIR) psx/$(DEPDIR) psx/input/$(DEPDIR) quicklz/$(DEPDIR) resampler/$(DEPDIR) sms/$(DEPDIR) snes/$(DEPDIR) snes/src/cartridge/$(DEPDIR) snes/src/cheat/$(DEPDIR) snes/src/chip/bsx/$(DEPDIR) snes/src/chip/cx4/$(DEPDIR) snes/src/chip/dsp1/$(DEPDIR) snes/src/chip/dsp2/$(DEPDIR) snes/src/chip/dsp3/$(DEPDIR) snes/src/chip/dsp4/$(DEPDIR) snes/src/chip/obc1/$(DEPDIR) snes/src/chip/sa1/$(DEPDIR) snes/src/chip/sdd1/$(DEPDIR) snes/src/chip/spc7110/$(DEPDIR) snes/src/chip/srtc/$(DEPDIR) snes/src/chip/st010/$(DEPDIR) snes/src/chip/superfx/$(DEPDIR) snes/src/cpu/$(DEPDIR) snes/src/cpu/core/$(DEPDIR) snes/src/cpu/scpu/$(DEPDIR) snes/src/lib/libco/$(DEPDIR) snes/src/memory/$(DEPDIR) snes/src/memory/smemory/$(DEPDIR) snes/src/ppu/$(DEPDIR) snes/src/sdsp/$(DEPDIR) snes/src/smp/$(DEPDIR) snes/src/system/$(DEPDIR) snes_faust/$(DEPDIR) sound/$(DEPDIR) string/$(DEPDIR) tremor/$(DEPDIR) trio/$(DEPDIR) vb/$(DEPDIR) video/$(DEPDIR) wswan/$(DEPDIR) wswan/dis/$(DEPDIR) + -rm -rf ./$(DEPDIR) apple2/$(DEPDIR) cdplay/$(DEPDIR) cdrom/$(DEPDIR) cheat_formats/$(DEPDIR) compress/$(DEPDIR) cputest/$(DEPDIR) demo/$(DEPDIR) desa68/$(DEPDIR) gb/$(DEPDIR) gba/$(DEPDIR) hash/$(DEPDIR) hw_cpu/m68k/$(DEPDIR) hw_cpu/v810/$(DEPDIR) hw_cpu/z80-fuse/$(DEPDIR) hw_misc/arcade_card/$(DEPDIR) hw_sound/gb_apu/$(DEPDIR) hw_sound/pce_psg/$(DEPDIR) hw_sound/sms_apu/$(DEPDIR) hw_sound/ym2413/$(DEPDIR) hw_sound/ym2612/$(DEPDIR) hw_video/huc6270/$(DEPDIR) lynx/$(DEPDIR) md/$(DEPDIR) md/cart/$(DEPDIR) md/cd/$(DEPDIR) md/input/$(DEPDIR) minilzo/$(DEPDIR) mpcdec/$(DEPDIR) mthreading/$(DEPDIR) nes/$(DEPDIR) nes/boards/$(DEPDIR) nes/input/$(DEPDIR) nes/ntsc/$(DEPDIR) nes/ppu/$(DEPDIR) net/$(DEPDIR) ngp/$(DEPDIR) ngp/TLCS-900h/$(DEPDIR) pce/$(DEPDIR) pce/input/$(DEPDIR) pce_fast/$(DEPDIR) pcfx/$(DEPDIR) pcfx/input/$(DEPDIR) psx/$(DEPDIR) psx/input/$(DEPDIR) quicklz/$(DEPDIR) resampler/$(DEPDIR) sms/$(DEPDIR) snes/$(DEPDIR) snes/src/cartridge/$(DEPDIR) snes/src/cheat/$(DEPDIR) snes/src/chip/bsx/$(DEPDIR) snes/src/chip/cx4/$(DEPDIR) snes/src/chip/dsp1/$(DEPDIR) snes/src/chip/dsp2/$(DEPDIR) snes/src/chip/dsp3/$(DEPDIR) snes/src/chip/dsp4/$(DEPDIR) snes/src/chip/obc1/$(DEPDIR) snes/src/chip/sa1/$(DEPDIR) snes/src/chip/sdd1/$(DEPDIR) snes/src/chip/spc7110/$(DEPDIR) snes/src/chip/srtc/$(DEPDIR) snes/src/chip/st010/$(DEPDIR) snes/src/chip/superfx/$(DEPDIR) snes/src/cpu/$(DEPDIR) snes/src/cpu/core/$(DEPDIR) snes/src/cpu/scpu/$(DEPDIR) snes/src/lib/libco/$(DEPDIR) snes/src/memory/$(DEPDIR) snes/src/memory/smemory/$(DEPDIR) snes/src/ppu/$(DEPDIR) snes/src/sdsp/$(DEPDIR) snes/src/smp/$(DEPDIR) snes/src/system/$(DEPDIR) snes_faust/$(DEPDIR) snes_faust/cart/$(DEPDIR) sound/$(DEPDIR) string/$(DEPDIR) tremor/$(DEPDIR) trio/$(DEPDIR) vb/$(DEPDIR) video/$(DEPDIR) wswan/$(DEPDIR) wswan/dis/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -5034,7 +4999,7 @@ install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive - -rm -rf ./$(DEPDIR) apple2/$(DEPDIR) cdplay/$(DEPDIR) cdrom/$(DEPDIR) cheat_formats/$(DEPDIR) compress/$(DEPDIR) cputest/$(DEPDIR) demo/$(DEPDIR) desa68/$(DEPDIR) gb/$(DEPDIR) gba/$(DEPDIR) hash/$(DEPDIR) hw_cpu/m68k/$(DEPDIR) hw_cpu/v810/$(DEPDIR) hw_cpu/z80-fuse/$(DEPDIR) hw_misc/arcade_card/$(DEPDIR) hw_sound/gb_apu/$(DEPDIR) hw_sound/pce_psg/$(DEPDIR) hw_sound/sms_apu/$(DEPDIR) hw_sound/ym2413/$(DEPDIR) hw_sound/ym2612/$(DEPDIR) hw_video/huc6270/$(DEPDIR) lynx/$(DEPDIR) md/$(DEPDIR) md/cart/$(DEPDIR) md/cd/$(DEPDIR) md/input/$(DEPDIR) minilzo/$(DEPDIR) mpcdec/$(DEPDIR) mthreading/$(DEPDIR) nes/$(DEPDIR) nes/boards/$(DEPDIR) nes/input/$(DEPDIR) nes/ntsc/$(DEPDIR) nes/ppu/$(DEPDIR) net/$(DEPDIR) ngp/$(DEPDIR) ngp/TLCS-900h/$(DEPDIR) pce/$(DEPDIR) pce/input/$(DEPDIR) pce_fast/$(DEPDIR) pcfx/$(DEPDIR) pcfx/input/$(DEPDIR) psx/$(DEPDIR) psx/input/$(DEPDIR) quicklz/$(DEPDIR) resampler/$(DEPDIR) sms/$(DEPDIR) snes/$(DEPDIR) snes/src/cartridge/$(DEPDIR) snes/src/cheat/$(DEPDIR) snes/src/chip/bsx/$(DEPDIR) snes/src/chip/cx4/$(DEPDIR) snes/src/chip/dsp1/$(DEPDIR) snes/src/chip/dsp2/$(DEPDIR) snes/src/chip/dsp3/$(DEPDIR) snes/src/chip/dsp4/$(DEPDIR) snes/src/chip/obc1/$(DEPDIR) snes/src/chip/sa1/$(DEPDIR) snes/src/chip/sdd1/$(DEPDIR) snes/src/chip/spc7110/$(DEPDIR) snes/src/chip/srtc/$(DEPDIR) snes/src/chip/st010/$(DEPDIR) snes/src/chip/superfx/$(DEPDIR) snes/src/cpu/$(DEPDIR) snes/src/cpu/core/$(DEPDIR) snes/src/cpu/scpu/$(DEPDIR) snes/src/lib/libco/$(DEPDIR) snes/src/memory/$(DEPDIR) snes/src/memory/smemory/$(DEPDIR) snes/src/ppu/$(DEPDIR) snes/src/sdsp/$(DEPDIR) snes/src/smp/$(DEPDIR) snes/src/system/$(DEPDIR) snes_faust/$(DEPDIR) sound/$(DEPDIR) string/$(DEPDIR) tremor/$(DEPDIR) trio/$(DEPDIR) vb/$(DEPDIR) video/$(DEPDIR) wswan/$(DEPDIR) wswan/dis/$(DEPDIR) + -rm -rf ./$(DEPDIR) apple2/$(DEPDIR) cdplay/$(DEPDIR) cdrom/$(DEPDIR) cheat_formats/$(DEPDIR) compress/$(DEPDIR) cputest/$(DEPDIR) demo/$(DEPDIR) desa68/$(DEPDIR) gb/$(DEPDIR) gba/$(DEPDIR) hash/$(DEPDIR) hw_cpu/m68k/$(DEPDIR) hw_cpu/v810/$(DEPDIR) hw_cpu/z80-fuse/$(DEPDIR) hw_misc/arcade_card/$(DEPDIR) hw_sound/gb_apu/$(DEPDIR) hw_sound/pce_psg/$(DEPDIR) hw_sound/sms_apu/$(DEPDIR) hw_sound/ym2413/$(DEPDIR) hw_sound/ym2612/$(DEPDIR) hw_video/huc6270/$(DEPDIR) lynx/$(DEPDIR) md/$(DEPDIR) md/cart/$(DEPDIR) md/cd/$(DEPDIR) md/input/$(DEPDIR) minilzo/$(DEPDIR) mpcdec/$(DEPDIR) mthreading/$(DEPDIR) nes/$(DEPDIR) nes/boards/$(DEPDIR) nes/input/$(DEPDIR) nes/ntsc/$(DEPDIR) nes/ppu/$(DEPDIR) net/$(DEPDIR) ngp/$(DEPDIR) ngp/TLCS-900h/$(DEPDIR) pce/$(DEPDIR) pce/input/$(DEPDIR) pce_fast/$(DEPDIR) pcfx/$(DEPDIR) pcfx/input/$(DEPDIR) psx/$(DEPDIR) psx/input/$(DEPDIR) quicklz/$(DEPDIR) resampler/$(DEPDIR) sms/$(DEPDIR) snes/$(DEPDIR) snes/src/cartridge/$(DEPDIR) snes/src/cheat/$(DEPDIR) snes/src/chip/bsx/$(DEPDIR) snes/src/chip/cx4/$(DEPDIR) snes/src/chip/dsp1/$(DEPDIR) snes/src/chip/dsp2/$(DEPDIR) snes/src/chip/dsp3/$(DEPDIR) snes/src/chip/dsp4/$(DEPDIR) snes/src/chip/obc1/$(DEPDIR) snes/src/chip/sa1/$(DEPDIR) snes/src/chip/sdd1/$(DEPDIR) snes/src/chip/spc7110/$(DEPDIR) snes/src/chip/srtc/$(DEPDIR) snes/src/chip/st010/$(DEPDIR) snes/src/chip/superfx/$(DEPDIR) snes/src/cpu/$(DEPDIR) snes/src/cpu/core/$(DEPDIR) snes/src/cpu/scpu/$(DEPDIR) snes/src/lib/libco/$(DEPDIR) snes/src/memory/$(DEPDIR) snes/src/memory/smemory/$(DEPDIR) snes/src/ppu/$(DEPDIR) snes/src/sdsp/$(DEPDIR) snes/src/smp/$(DEPDIR) snes/src/system/$(DEPDIR) snes_faust/$(DEPDIR) snes_faust/cart/$(DEPDIR) sound/$(DEPDIR) string/$(DEPDIR) tremor/$(DEPDIR) trio/$(DEPDIR) vb/$(DEPDIR) video/$(DEPDIR) wswan/$(DEPDIR) wswan/dis/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/mednafen/apple2/apple2.cpp b/mednafen/apple2/apple2.cpp index 4835251..8f6eb0f 100644 --- a/mednafen/apple2/apple2.cpp +++ b/mednafen/apple2/apple2.cpp @@ -2,7 +2,7 @@ /* Mednafen Apple II Emulation Module */ /******************************************************************************/ /* apple2.cpp: -** Copyright (C) 2018 Mednafen Team +** Copyright (C) 2018-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -493,6 +493,8 @@ static void Emulate(EmulateSpecStruct* espec) s.mono_lumafilter = MDFN_GetSettingI("apple2.video.mono_lumafilter"); s.color_lumafilter = MDFN_GetSettingI("apple2.video.color_lumafilter"); + s.mode = MDFN_GetSettingUI("apple2.video.mode"); + s.matrix = MDFN_GetSettingUI("apple2.video.matrix"); for(unsigned cc_i = 0; cc_i < 3; cc_i++) @@ -512,7 +514,7 @@ static void Emulate(EmulateSpecStruct* espec) // // // - Video::SetFormat(surface->format, s); + Video::SetFormat(surface->format, s, espec->CustomPalette, espec->CustomPaletteNumEntries); // VideoSettingChanged = false; } @@ -521,11 +523,7 @@ static void Emulate(EmulateSpecStruct* espec) Sound::SetParams(espec->SoundRate, 0.00004, 3); // Video::surface = espec->surface; - - espec->DisplayRect.x = 0; - espec->DisplayRect.y = 0; - espec->DisplayRect.w = 560 + 12*2; - espec->DisplayRect.h = 192; + espec->DisplayRect = Video::surface_dr; MDFNMP_ApplyPeriodicCheats(); @@ -1678,6 +1676,16 @@ static const MDFNSetting_EnumList Matrix_List[] = { nullptr, 0 }, }; +static const MDFNSetting_EnumList Mode_List[] = +{ + { "composite", Video::Settings::MODE_COMPOSITE, "Composite", gettext_noop("Internal video dimensions of 584x192.") }, + { "rgb", Video::Settings::MODE_RGB, "RGB", gettext_noop("Internal video dimensions of 292x192; suitable for use with scalers like hq2x.") }, + { "rgb_alt1", Video::Settings::MODE_RGB_ALT1, "RGB (alternate algorithm 1)", gettext_noop("Internal video dimensions of 584x192.") }, + { "rgb_alt2", Video::Settings::MODE_RGB_ALT2, "RGB (alternate algorithm 2)", gettext_noop("Internal video dimensions of 584x192.") }, + + { nullptr, 0 } +}; + static const MDFNSetting Settings[] = { { "apple2.video.hue", MDFNSF_CAT_VIDEO, gettext_noop("Color video hue/tint."), nullptr, MDFNST_FLOAT, "0.0", "-1.0", "1.0", nullptr, VideoChangeNotif }, @@ -1701,6 +1709,8 @@ static const MDFNSetting Settings[] = { "apple2.video.matrix.blue.i", MDFNSF_CAT_VIDEO, gettext_noop("Custom color decoder matrix; blue, I."), gettext_noop("Only used if \"apple2.video.matrix\" is set to \"custom\"."), MDFNST_FLOAT, "-1.11", "-4.00", "4.00", nullptr, VideoChangeNotif }, { "apple2.video.matrix.blue.q", MDFNSF_CAT_VIDEO, gettext_noop("Custom color decoder matrix; blue, Q."), gettext_noop("Only used if \"apple2.video.matrix\" is set to \"custom\"."), MDFNST_FLOAT, "1.70", "-4.00", "4.00", nullptr, VideoChangeNotif }, + { "apple2.video.mode", MDFNSF_CAT_VIDEO, gettext_noop("Video rendering mode."), gettext_noop("When an RGB mode is enabled, settings \"apple2.video.force_mono\", \"apple2.video.mixed_text_mono\", \"apple2.video.mono_lumafilter\", \"apple2.video.color_lumafilter\", and \"apple2.video.color_smooth\" are effectively ignored."), MDFNST_ENUM, "composite", nullptr, nullptr, nullptr, VideoChangeNotif, Mode_List }, + { NULL }, }; @@ -1731,6 +1741,13 @@ static const CheatInfoStruct CheatInfo = false }; +static const CustomPalette_Spec CPInfo[] = +{ + { gettext_noop("RGB mode 16-color palette. The presence of a custom palette will automatically enable RGB video mode."), NULL, { 16, 0 } }, + + { NULL, NULL } +}; + } using namespace MDFN_IEN_APPLE2; @@ -1747,6 +1764,7 @@ MDFNGI EmulatedApple2 = NULL, //#endif A2PortInfo, + NULL, Load, TestMagic, nullptr, @@ -1759,8 +1777,8 @@ MDFNGI EmulatedApple2 = nullptr, nullptr, - nullptr, - 0, + CPInfo, + 1, CheatInfo, diff --git a/mednafen/apple2/video.inc b/mednafen/apple2/video.inc index cf9afa4..e839e90 100644 --- a/mednafen/apple2/video.inc +++ b/mednafen/apple2/video.inc @@ -2,7 +2,7 @@ /* Mednafen Apple II Emulation Module */ /******************************************************************************/ /* video.inc: -** Copyright (C) 2018 Mednafen Team +** Copyright (C) 2018-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -58,9 +58,15 @@ namespace Video enum { ColorLUT_NumPixels = 13 }; static uint32 ColorLUT[2][4][1U << ColorLUT_NumPixels]; +static uint32 RGBLUT[16 * 2]; static MDFN_PixelFormat format; static bool EnableMixedTextMonoHack; +static void (*BlitLineBitBuffer)(uint32* target); +template static void BlitLineBitBuffer_RGB_Alt(uint32* target); +static void BlitLineBitBuffer_RGB(uint32* target); +static void BlitLineBitBuffer_Composite(uint32* target); + struct Settings { float hue = 0.0; @@ -74,6 +80,16 @@ struct Settings int mono_lumafilter = 5; int color_lumafilter = -3; + enum + { + MODE_COMPOSITE = 0, + MODE_RGB, + MODE_RGB_ALT1, + MODE_RGB_ALT2 + }; + + unsigned mode = MODE_COMPOSITE; + enum { MATRIX_MEDNAFEN = 0, @@ -97,286 +113,241 @@ struct Settings float custom_matrix[3][2]; }; -static const float matrixes[Settings::MATRIX_CUSTOM][3][2] = -{ - // - // Mednafen - // - { - { 1.348808, 0.504299 }, // (102.5° * 1.440) + (237.7° * 0.000) + (0.0° * 0.000), - { -0.242363, -0.526935 }, // (102.5° * 0.000) + (237.7° * 0.580) + (0.0° * 0.000), - { -1.089278, 1.677341 }, // (102.5° * 0.000) + (237.7° * 0.000) + (0.0° * 2.000), - }, - - // - // LA7620 - // - { - { 1.701933, 0.586023 }, // (104.0° * 1.800) + (238.0° * 0.000) + (0.0° * 0.000), - { -0.253571, -0.543785 }, // (104.0° * 0.000) + (238.0° * 0.600) + (0.0° * 0.000), - { -1.089278, 1.677341 }, // (104.0° * 0.000) + (238.0° * 0.000) + (0.0° * 2.000), - }, +/* + text/lores + page1: 0x0400-0x07FF + page2: 0x0800-0x0BFF - // - // CXA2025 Japan - // - { - { 1.377398, 0.732376 }, // (95.0° * 1.560) + (240.0° * 0.000) + (0.0° * 0.000), - { -0.272394, -0.534604 }, // (95.0° * 0.000) + (240.0° * 0.600) + (0.0° * 0.000), - { -1.089278, 1.677341 }, // (95.0° * 0.000) + (240.0° * 0.000) + (0.0° * 2.000), - }, + hires + page1: 0x2000-0x3FFF + page2: 0x4000-0x5FFF - // - // CXA2025 USA - // - { - { 1.629501, 0.316743 }, // (112.0° * 1.660) + (252.0° * 0.000) + (0.0° * 0.000), - { -0.377592, -0.466288 }, // (112.0° * 0.000) + (252.0° * 0.600) + (0.0° * 0.000), - { -1.089278, 1.677341 }, // (112.0° * 0.000) + (252.0° * 0.000) + (0.0° * 2.000), - }, - // - // CXA2060 Japan - // - { - { 1.377398, 0.732376 }, // (95.0° * 1.560) + (236.0° * 0.000) + (0.0° * 0.000), - { -0.257883, -0.607533 }, // (95.0° * 0.000) + (236.0° * 0.660) + (0.0° * 0.000), - { -1.089278, 1.677341 }, // (95.0° * 0.000) + (236.0° * 0.000) + (0.0° * 2.000), - }, + lores: 1 byte for 7x8 7MHz pixels, lower nybble for upper 4 pixels, upper nybble for lower 4 pixels - // - // CXA2060 USA - // - { - { 1.456385, 0.559054 }, // (102.0° * 1.560) + (236.0° * 0.000) + (0.0° * 0.000), - { -0.234439, -0.552303 }, // (102.0° * 0.000) + (236.0° * 0.600) + (0.0° * 0.000), - { -1.089278, 1.677341 }, // (102.0° * 0.000) + (236.0° * 0.000) + (0.0° * 2.000), - }, + hires: 1 byte for 7x1 7MHz pixels, upper bit for phase/delay thing, bit0 leftmost pixel, bit6 rightmost pixel +*/ - // - // CXA2095 Japan - // - { - { 1.059537, 0.563366 }, // (95.0° * 1.200) + (236.0° * 0.000) + (0.0° * 0.000), - { -0.257883, -0.607533 }, // (95.0° * 0.000) + (236.0° * 0.660) + (0.0° * 0.000), - { -1.089278, 1.677341 }, // (95.0° * 0.000) + (236.0° * 0.000) + (0.0° * 2.000), - }, +static uint8 linebuffer[(560 + 24) / 8 + 4] = { 0 }; +static MDFN_Surface* surface; +static MDFN_Rect surface_dr; +static bool colorburst_present; +static bool rgb_hires_latch; +static uint32 HCounter, VCounter; +static bool flashything; +static int32 flashycounter; +static bool HiresDelayBit = false; +static uint64 NoiseLCG; - // - // CXA2095 USA - // - { - { 1.483648, 0.482066 }, // (105.0° * 1.560) + (236.0° * 0.000) + (0.0° * 0.000), - { -0.257883, -0.607533 }, // (105.0° * 0.000) + (236.0° * 0.660) + (0.0° * 0.000), - { -1.089278, 1.677341 }, // (105.0° * 0.000) + (236.0° * 0.000) + (0.0° * 2.000), - }, -}; +static void Power(void) +{ + HCounter = 0; + VCounter = 0xFA; + flashything = false; + flashycounter = 0; + HiresDelayBit = false; + NoiseLCG = 0; +} -// tint, saturation, -1.0 to 1.0 -static INLINE void SetFormat(const MDFN_PixelFormat& f, const Settings& s) +template +static void BlitLineBitBuffer_RGB_Alt(uint32* target) { - format = f; - EnableMixedTextMonoHack = s.mixed_text_mono; - // - // - const float (&d)[3][2] = (s.matrix == Settings::MATRIX_CUSTOM) ? s.custom_matrix : matrixes[s.matrix]; - float demod_tab[2][4]; + uint32 pdata = 0; - for(unsigned cd_i = 0; cd_i < 2; cd_i++) + if(!colorburst_present) { - static const float angles[2] = { 123.0, 33.0 }; - - for(int x = 0; x < 4; x++) + for(int x = 0; x < 584; x++) { - demod_tab[cd_i][x] = sin(((x / 4.0) - s.hue / 8.0 + angles[cd_i] / 360.0) * (M_PI * 2.0)); - //printf("%d, %d, %f\n", cd_i, x, demod_tab[cd_i][x]); + pdata |= ((linebuffer[x >> 3] >> (x & 0x7)) & 1) << 12; + // + const bool C = (pdata & 1); + target[x] = RGBLUT[C ? 15 : 0]; + // + pdata >>= 1; } } - - - for(unsigned cbp = 0; cbp < 2; cbp++) + else if(!rgb_hires_latch) { - static const float coeffs[11][ColorLUT_NumPixels] = - { - /* -3 */ { 0.00172554, -0.00760881, -0.03068241, -0.01602947, 0.09901781, 0.27344111, 0.36027244, 0.27344111, 0.09901781, -0.01602947, -0.03068241, -0.00760881, 0.00172554, }, /* 1.000000 */ - /* -2 */ { -0.00085195, -0.00688802, -0.00964609, 0.02346799, 0.11669260, 0.23333631, 0.28777829, 0.23333631, 0.11669260, 0.02346799, -0.00964609, -0.00688802, -0.00085195, }, /* 1.000000 */ - /* -1 */ { -0.00666994, -0.01931400, -0.01700092, 0.03131011, 0.13104562, 0.23818615, 0.28488591, 0.23818615, 0.13104562, 0.03131011, -0.01700092, -0.01931400, -0.00666994, }, /* 1.000000 */ - /* 0 */ { 0.00000000, 0.00535462, 0.02579365, 0.06746032, 0.12500000, 0.17718506, 0.19841270, 0.17718506, 0.12500000, 0.06746032, 0.02579365, 0.00535462, 0.00000000, }, /* 1.000000 */ - /* 1 */ { 0.00000000, 0.00000000, 0.00957449, 0.04780242, 0.12137789, 0.20219758, 0.23809524, 0.20219758, 0.12137789, 0.04780242, 0.00957449, 0.00000000, 0.00000000, }, /* 1.000000 */ - /* 2 */ { 0.00000000, 0.00000000, 0.00000000, 0.01977578, 0.10119048, 0.23022422, 0.29761904, 0.23022422, 0.10119048, 0.01977578, 0.00000000, 0.00000000, 0.00000000, }, /* 1.000000 */ - /* 3 */ { 0.00000000, 0.00000000, 0.00000000, 0.01464626, 0.08312087, 0.23555925, 0.33334723, 0.23555925, 0.08312087, 0.01464626, 0.00000000, 0.00000000, 0.00000000, }, /* 1.000000 */ - /* 4 */ { 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.05158730, 0.25000000, 0.39682540, 0.25000000, 0.05158730, 0.00000000, 0.00000000, 0.00000000, 0.00000000, }, /* 1.000000 */ - /* 5 */ { 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.25000000, 0.50000000, 0.25000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, }, /* 1.000000 */ - /* 6 */ { 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.16666667, 0.66666669, 0.16666667, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, }, /* 1.000000 */ - /* 7 */ { 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 1.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, }, /* 1.000000 */ - }; - const bool mono_mode = !cbp || s.force_mono; - static const float colordiff_coeffs[ColorLUT_NumPixels] = { 0.00329843, 0.01538324, 0.04024864, 0.07809234, 0.12141892, 0.15652442, 0.17006803, 0.15652442, 0.12141892, 0.07809234, 0.04024864, 0.01538324, 0.00329843 }; - const float (&luma_coeffs)[ColorLUT_NumPixels] = coeffs[3 + (mono_mode ? s.mono_lumafilter : s.color_lumafilter)]; + unsigned pat = 0; + unsigned dc = 1; -#if 0 - for(unsigned ci = 0; ci < 11; ci++) + for(int x = 0; x < 584; x++) { - float sum = 0; - - printf(" /* % d */ { ", (int)ci - 3); + unsigned phase = x & 3; + bool nb = ((linebuffer[x >> 3] >> (x & 0x7)) & 1); - for(unsigned i = 0; i < ColorLUT_NumPixels; i++) + pdata |= nb << 12; + // + dc++; + if(dc == 14) { - assert(coeffs[ci][i] == coeffs[ci][ColorLUT_NumPixels - 1 - i]); - sum += coeffs[ci][i]; - printf("% .8f, ", coeffs[ci][i]); + pat = (pdata >> 0) & 0xF; + pat = ((pat << phase) | (pat >> (4 - phase))) & 0xF; + dc = 0; } - printf("}, /* %f */\n", sum); + target[x] = RGBLUT[pat]; + // + pdata >>= 1; } -#endif + } + else + { + unsigned pat = 0; + unsigned bw = 0; + unsigned cpd = 0; + unsigned dc = 0; + unsigned halve = 0; - for(unsigned phase = 0; phase < 4; phase++) + for(int x = 0; x < 584; x++) { - for(unsigned color = 0; color < (1U << ColorLUT_NumPixels); color++) - { - float y = 0; - float color_diff[2] = { 0, 0 }; - - for(unsigned i = 0; i < ColorLUT_NumPixels; i++) - y += luma_coeffs[i] * ((color >> i) & 1); - - y = y * ((s.contrast * 0.50) + 1.0) + (s.brightness * 0.50); - - for(unsigned cd_i = 0; cd_i < 2; cd_i++) - { - for(unsigned i = 0; i < ColorLUT_NumPixels; i++) - { - float chroma = ((color >> i) & 1); - - color_diff[cd_i] += colordiff_coeffs[i] * demod_tab[cd_i][(i + phase) & 3] * chroma; - } - color_diff[cd_i] *= 1.0 + s.saturation; + unsigned phase = x & 3; + bool nb = ((linebuffer[x >> 3] >> (x & 0x7)) & 1); - if(mono_mode) - color_diff[cd_i] = 0; - } + pdata |= nb << 12; + // + if((pdata & 0x1FC) == 0x070) + bw |= 0x070; - unsigned rgb_cc[3]; + if((pdata & 0xF00) == 0xF00) + bw |= 0xF00; - for(unsigned cc_i = 0; cc_i < 3; cc_i++) - { - float eff_y = y * (s.force_mono ? (((s.force_mono >> ((2 - cc_i) << 3)) & 0xFF) / 255.0) : 1.0); - float t = std::max(0.0, eff_y + d[cc_i][0] * color_diff[0] + d[cc_i][1] * color_diff[1]); + if((pdata & 0xF00) == 0x000) + bw |= 0xF00; - //t = pow(t, d.power); + if(which == 2) + { + if((pdata & 0xF3C) == 0xF3C) + halve |= 0xC0; //bw |= 0xFFC; - //if(t > 1.10) - // printf("phase=%d color=0x%08x cc_i=%u t=%f\n", phase, color, cc_i, t); + if((pdata & 0xF1E) == 0xF1E) + halve |= 0xE0; //bw |= 0xFFE; + } - rgb_cc[cc_i] = std::min(1016, std::max(0, floor(0.5 + 1016 * t))); - } + if((pdata & 0xF00) == 0x300) // && !(pdata & 0x400)) + dc = 0; + else + dc = (dc + 1) & 1; - //printf("color 0x%01x: y=%f pb=%.13f pr=%.13f --- %3u %3u %3u\n", color, ySL2 / 4.0, pbSL6 / 64.0, prSL6 / 64.0, r, g, b); + if(!dc) + { + cpd = (pdata >> 0) & 0xF; + cpd = ((cpd << phase) | (cpd >> (4 - phase))) & 0xF; + } - ColorLUT[cbp][phase][color] = (rgb_cc[0] << 0) + (rgb_cc[1] << 10) + (rgb_cc[2] << 20); + if(bw & 0x01) + pat = (pdata & 0x01) ? 15 : 0; + else if(which == 2 && (halve & 0x01)) + pat = 0x10 + cpd; + else if(1) + { + //pat = (pdata >> (ps & 1)) & 0xF; + //pat = ((pat << phase) | (pat >> (4 - phase))) & 0xF; + pat = cpd; } + + target[x] = RGBLUT[pat]; + // + pdata >>= 1; + bw >>= 1; + if(which == 2) + halve >>= 1; } } +} - if(s.color_smooth && !s.force_mono) - { - uint32 SmoothLUT[4][16]; +static void BlitLineBitBuffer_RGB(uint32* target) +{ + for(int i = 0; i < 6; i++) + *(target++) = RGBLUT[0]; - for(unsigned phase = 0; phase < 4; phase++) + if(!colorburst_present) + { + for(int x = 0; x < 560; x += 2) { - for(unsigned color = 0; color < 16; color++) - { - float r = 0; - float g = 0; - float b = 0; - int r_p, g_p, b_p; + const bool C = (linebuffer[x >> 3] >> (x & 0x7)) & 1; + target[x >> 1] = RGBLUT[C ? 15 : 0]; + } + target += 560; + } + else if(!rgb_hires_latch) + { + for(int x = 0; x < 560; x += 14) + { + unsigned pat = (MDFN_de32lsb(&linebuffer[x >> 3]) >> (x & 0x7)) & 0xF; + unsigned phase = x & 3; + uint32 pix; - for(unsigned i = 0; i < 4; i++) - { - unsigned pattern = (color | (color << 4) | (color << 8) | (color << 12) | (color << 16)) >> (4 + i - phase); - uint32 cle = ColorLUT[1][(i) & 3][pattern & 0x1FFF]; + pat = ((pat << phase) | (pat >> (4 - phase))) & 0xF; + pix = RGBLUT[pat]; - r_p = (cle >> 0) & 0x3FF; - g_p = (cle >> 10) & 0x3FF; - b_p = (cle >> 20) & 0x3FF; + for(int sx = 0; sx < 7; sx++) + target[(x >> 1) + sx] = pix; + } + target += 560; + } + else + { + uint32 pdata = 0; + uint32 pshift = 0; + uint32 bw = 0; + uint32 cpd = 0; - r += pow(r_p / 1016.0, 2.2); - g += pow(g_p / 1016.0, 2.2); - b += pow(b_p / 1016.0, 2.2); - } + for(int x = 0; x < 560 + 14; x += 14) + { + uint32 tmp = MDFN_de32lsb(&linebuffer[x >> 3]) >> (x & 0x7); - r /= 4; - g /= 4; - b /= 4; + if((tmp ^ (tmp >> 1)) & 0x1555) + { + tmp = ((tmp >> 1) & 0x1FFF) | (tmp & 0x2000); + pshift |= 0x3FFF << 14; + } + pdata |= (tmp & 0x3FFF) << 14; - r_p = std::min(1016, floor(0.5 + 1016 * pow(r, 1.0 / 2.2))); - g_p = std::min(1016, floor(0.5 + 1016 * pow(g, 1.0 / 2.2))); - b_p = std::min(1016, floor(0.5 + 1016 * pow(b, 1.0 / 2.2))); + for(int sx = 0; sx < 14; sx += 2) + { + uint32 pat; - //printf("Phase: %d, Color: %d - 0x%02x 0x%02x 0x%02x\n", phase, color, r_p, g_p, b_p); + if((pdata & 0xF00) == 0xF00) + bw |= 0xF00; - SmoothLUT[phase][color] = (r_p << 0) + (g_p << 10) + (b_p << 20); - } - } + if((pdata & 0xF00) == 0x000) + bw |= 0xF00; - for(unsigned phase = 0; phase < 4; phase++) - { - for(unsigned color = 0; color < (1U << ColorLUT_NumPixels); color++) - { - const unsigned c0 = (color >> 0) & 0x1F; - const unsigned c1 = (color >> 4) & 0x1F; - const unsigned c2 = (color >> 8) & 0x1F; + if(!(sx & 0x3)) + { + unsigned shift = ((x & 2) ^ 2) + (pshift & 1); + cpd = pdata & 0xF; + cpd = ((cpd << shift) | (cpd >> (4 - shift))) & 0xF; + } - if(c1 == c0 || c1 == c2 || (((color >> 2) & 0x7) == ((color >> 6) & 0x7) && ((color >> 3) & 0x7) == ((color >> 7) & 0x7))) - ColorLUT[1][phase][color] = SmoothLUT[phase][c1 & 0xF]; + if(bw & 1) + pat = (pdata & 0x1) ? 0xF : 0x0; + else + pat = cpd; + + *target = RGBLUT[pat]; + // + if(x >= 14) + target++; + bw >>= 2; + pdata >>= 2; + pshift >>= 2; } } } + + for(int i = 0; i < 6; i++) + *(target++) = RGBLUT[0]; } -/* - text/lores - page1: 0x0400-0x07FF - page2: 0x0800-0x0BFF - - hires - page1: 0x2000-0x3FFF - page2: 0x4000-0x5FFF - - - lores: 1 byte for 7x8 7MHz pixels, lower nybble for upper 4 pixels, upper nybble for lower 4 pixels - - hires: 1 byte for 7x1 7MHz pixels, upper bit for phase/delay thing, bit0 leftmost pixel, bit6 rightmost pixel -*/ - -static uint8 linebuffer[(560 + 24) / 8 + 4] = { 0 }; -static MDFN_Surface* surface; -static bool colorburst_present; -static uint32 HCounter, VCounter; -static bool flashything; -static int32 flashycounter; -static bool HiresDelayBit = false; -static uint64 NoiseLCG; - -static void Power(void) -{ - HCounter = 0; - VCounter = 0xFA; - flashything = false; - flashycounter = 0; - HiresDelayBit = false; - NoiseLCG = 0; -} - -static NO_INLINE void BlitLineBitBuffer_Composite(uint32* target) -{ - uint32 pdata = 0; - const unsigned nb_pos = (ColorLUT_NumPixels - 1) + (12 - (ColorLUT_NumPixels / 2)); - const uint8 rs = format.Rshift; - const uint8 gs = format.Gshift; - const uint8 bs = format.Bshift; +static void BlitLineBitBuffer_Composite(uint32* target) +{ + uint32 pdata = 0; + const unsigned nb_pos = (ColorLUT_NumPixels - 1) + (12 - (ColorLUT_NumPixels / 2)); + const uint8 rs = format.Rshift; + const uint8 gs = format.Gshift; + const uint8 bs = format.Bshift; for(size_t x = 0; x < 584; x++) { @@ -561,7 +532,7 @@ static NO_INLINE void Tick(void) } #endif - BlitLineBitBuffer_Composite(surface->pixels + vis_vc * surface->pitchinpix); + BlitLineBitBuffer(surface->pixels + vis_vc * surface->pitchinpix); } // VCounter = (VCounter + 1) & 0x1FF; @@ -585,6 +556,8 @@ static NO_INLINE void Tick(void) if(text && EnableMixedTextMonoHack) colorburst_present = false; + + rgb_hires_latch = hires && !text; } if(flashycounter <= 0) @@ -672,4 +645,320 @@ static INLINE void Kill(void) } +static const float matrixes[Settings::MATRIX_CUSTOM][3][2] = +{ + // + // Mednafen + // + { + { 1.348808, 0.504299 }, // (102.5° * 1.440) + (237.7° * 0.000) + (0.0° * 0.000), + { -0.242363, -0.526935 }, // (102.5° * 0.000) + (237.7° * 0.580) + (0.0° * 0.000), + { -1.089278, 1.677341 }, // (102.5° * 0.000) + (237.7° * 0.000) + (0.0° * 2.000), + }, + + // + // LA7620 + // + { + { 1.701933, 0.586023 }, // (104.0° * 1.800) + (238.0° * 0.000) + (0.0° * 0.000), + { -0.253571, -0.543785 }, // (104.0° * 0.000) + (238.0° * 0.600) + (0.0° * 0.000), + { -1.089278, 1.677341 }, // (104.0° * 0.000) + (238.0° * 0.000) + (0.0° * 2.000), + }, + + // + // CXA2025 Japan + // + { + { 1.377398, 0.732376 }, // (95.0° * 1.560) + (240.0° * 0.000) + (0.0° * 0.000), + { -0.272394, -0.534604 }, // (95.0° * 0.000) + (240.0° * 0.600) + (0.0° * 0.000), + { -1.089278, 1.677341 }, // (95.0° * 0.000) + (240.0° * 0.000) + (0.0° * 2.000), + }, + + // + // CXA2025 USA + // + { + { 1.629501, 0.316743 }, // (112.0° * 1.660) + (252.0° * 0.000) + (0.0° * 0.000), + { -0.377592, -0.466288 }, // (112.0° * 0.000) + (252.0° * 0.600) + (0.0° * 0.000), + { -1.089278, 1.677341 }, // (112.0° * 0.000) + (252.0° * 0.000) + (0.0° * 2.000), + }, + + // + // CXA2060 Japan + // + { + { 1.377398, 0.732376 }, // (95.0° * 1.560) + (236.0° * 0.000) + (0.0° * 0.000), + { -0.257883, -0.607533 }, // (95.0° * 0.000) + (236.0° * 0.660) + (0.0° * 0.000), + { -1.089278, 1.677341 }, // (95.0° * 0.000) + (236.0° * 0.000) + (0.0° * 2.000), + }, + + // + // CXA2060 USA + // + { + { 1.456385, 0.559054 }, // (102.0° * 1.560) + (236.0° * 0.000) + (0.0° * 0.000), + { -0.234439, -0.552303 }, // (102.0° * 0.000) + (236.0° * 0.600) + (0.0° * 0.000), + { -1.089278, 1.677341 }, // (102.0° * 0.000) + (236.0° * 0.000) + (0.0° * 2.000), + }, + + // + // CXA2095 Japan + // + { + { 1.059537, 0.563366 }, // (95.0° * 1.200) + (236.0° * 0.000) + (0.0° * 0.000), + { -0.257883, -0.607533 }, // (95.0° * 0.000) + (236.0° * 0.660) + (0.0° * 0.000), + { -1.089278, 1.677341 }, // (95.0° * 0.000) + (236.0° * 0.000) + (0.0° * 2.000), + }, + + // + // CXA2095 USA + // + { + { 1.483648, 0.482066 }, // (105.0° * 1.560) + (236.0° * 0.000) + (0.0° * 0.000), + { -0.257883, -0.607533 }, // (105.0° * 0.000) + (236.0° * 0.660) + (0.0° * 0.000), + { -1.089278, 1.677341 }, // (105.0° * 0.000) + (236.0° * 0.000) + (0.0° * 2.000), + }, +}; + +// tint, saturation, -1.0 to 1.0 +static INLINE void SetFormat(const MDFN_PixelFormat& f, const Settings& s, uint8* CustomPalette, uint32 CustomPaletteNumEntries) +{ + int mode = s.mode; + + if(CustomPalette && CustomPaletteNumEntries && mode == Settings::MODE_COMPOSITE) + mode = Settings::MODE_RGB; + // + // + format = f; + EnableMixedTextMonoHack = (mode != Settings::MODE_COMPOSITE) ? true : s.mixed_text_mono; + // + // + surface_dr.x = 0; + surface_dr.y = 0; + surface_dr.w = (560 + 12*2) >> (mode == Settings::MODE_RGB); + surface_dr.h = 192; + // + // + // + if(mode == Settings::MODE_COMPOSITE) + BlitLineBitBuffer = BlitLineBitBuffer_Composite; + else + { + if(mode == Settings::MODE_RGB_ALT1) + BlitLineBitBuffer = BlitLineBitBuffer_RGB_Alt<1>; + else if(mode == Settings::MODE_RGB_ALT2) + BlitLineBitBuffer = BlitLineBitBuffer_RGB_Alt<2>; + else + BlitLineBitBuffer = BlitLineBitBuffer_RGB; + + if(CustomPalette && CustomPaletteNumEntries == 16) + { + for(unsigned i = 0; i < 16; i++) + { + RGBLUT[i] = format.MakeColor(CustomPalette[i * 3 + 0], CustomPalette[i * 3 + 1], CustomPalette[i * 3 + 2]); + RGBLUT[16 + i] = format.MakeColor(CustomPalette[i * 3 + 0] * 3 / 4, CustomPalette[i * 3 + 1] * 3 / 4, CustomPalette[i * 3 + 2] * 3 / 4); + } + + return; + } + } + // + // + // + const uint32 force_mono = (mode != Settings::MODE_COMPOSITE) ? 0 : s.force_mono; + const float (&d)[3][2] = *((s.matrix == Settings::MATRIX_CUSTOM) ? &s.custom_matrix : &matrixes[s.matrix]); + float demod_tab[2][4]; + + for(unsigned cd_i = 0; cd_i < 2; cd_i++) + { + static const float angles[2] = { 123.0, 33.0 }; + + for(int x = 0; x < 4; x++) + { + demod_tab[cd_i][x] = sin(((x / 4.0) - s.hue / 8.0 + angles[cd_i] / 360.0) * (M_PI * 2.0)); + //printf("%d, %d, %f\n", cd_i, x, demod_tab[cd_i][x]); + } + } + + + for(unsigned cbp = 0; cbp < 2; cbp++) + { + static const float coeffs[11][ColorLUT_NumPixels] = + { + /* -3 */ { 0.00172554, -0.00760881, -0.03068241, -0.01602947, 0.09901781, 0.27344111, 0.36027244, 0.27344111, 0.09901781, -0.01602947, -0.03068241, -0.00760881, 0.00172554, }, /* 1.000000 */ + /* -2 */ { -0.00085195, -0.00688802, -0.00964609, 0.02346799, 0.11669260, 0.23333631, 0.28777829, 0.23333631, 0.11669260, 0.02346799, -0.00964609, -0.00688802, -0.00085195, }, /* 1.000000 */ + /* -1 */ { -0.00666994, -0.01931400, -0.01700092, 0.03131011, 0.13104562, 0.23818615, 0.28488591, 0.23818615, 0.13104562, 0.03131011, -0.01700092, -0.01931400, -0.00666994, }, /* 1.000000 */ + /* 0 */ { 0.00000000, 0.00535462, 0.02579365, 0.06746032, 0.12500000, 0.17718506, 0.19841270, 0.17718506, 0.12500000, 0.06746032, 0.02579365, 0.00535462, 0.00000000, }, /* 1.000000 */ + /* 1 */ { 0.00000000, 0.00000000, 0.00957449, 0.04780242, 0.12137789, 0.20219758, 0.23809524, 0.20219758, 0.12137789, 0.04780242, 0.00957449, 0.00000000, 0.00000000, }, /* 1.000000 */ + /* 2 */ { 0.00000000, 0.00000000, 0.00000000, 0.01977578, 0.10119048, 0.23022422, 0.29761904, 0.23022422, 0.10119048, 0.01977578, 0.00000000, 0.00000000, 0.00000000, }, /* 1.000000 */ + /* 3 */ { 0.00000000, 0.00000000, 0.00000000, 0.01464626, 0.08312087, 0.23555925, 0.33334723, 0.23555925, 0.08312087, 0.01464626, 0.00000000, 0.00000000, 0.00000000, }, /* 1.000000 */ + /* 4 */ { 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.05158730, 0.25000000, 0.39682540, 0.25000000, 0.05158730, 0.00000000, 0.00000000, 0.00000000, 0.00000000, }, /* 1.000000 */ + /* 5 */ { 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.25000000, 0.50000000, 0.25000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, }, /* 1.000000 */ + /* 6 */ { 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.16666667, 0.66666669, 0.16666667, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, }, /* 1.000000 */ + /* 7 */ { 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 1.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.00000000, }, /* 1.000000 */ + }; + const bool mono_mode = !cbp || force_mono; + static const float colordiff_coeffs[ColorLUT_NumPixels] = { 0.00329843, 0.01538324, 0.04024864, 0.07809234, 0.12141892, 0.15652442, 0.17006803, 0.15652442, 0.12141892, 0.07809234, 0.04024864, 0.01538324, 0.00329843 }; + const float (&luma_coeffs)[ColorLUT_NumPixels] = coeffs[3 + (mono_mode ? s.mono_lumafilter : s.color_lumafilter)]; + +#if 0 + for(unsigned ci = 0; ci < 11; ci++) + { + float sum = 0; + + printf(" /* % d */ { ", (int)ci - 3); + + for(unsigned i = 0; i < ColorLUT_NumPixels; i++) + { + assert(coeffs[ci][i] == coeffs[ci][ColorLUT_NumPixels - 1 - i]); + sum += coeffs[ci][i]; + printf("% .8f, ", coeffs[ci][i]); + } + + printf("}, /* %f */\n", sum); + } +#endif + + for(unsigned phase = 0; phase < 4; phase++) + { + for(unsigned color = 0; color < (1U << ColorLUT_NumPixels); color++) + { + float y = 0; + float color_diff[2] = { 0, 0 }; + + for(unsigned i = 0; i < ColorLUT_NumPixels; i++) + y += luma_coeffs[i] * ((color >> i) & 1); + + y = y * ((s.contrast * 0.50) + 1.0) + (s.brightness * 0.50); + + for(unsigned cd_i = 0; cd_i < 2; cd_i++) + { + for(unsigned i = 0; i < ColorLUT_NumPixels; i++) + { + float chroma = ((color >> i) & 1); + + color_diff[cd_i] += colordiff_coeffs[i] * demod_tab[cd_i][(i + phase) & 3] * chroma; + } + color_diff[cd_i] *= 1.0 + s.saturation; + + if(mono_mode) + color_diff[cd_i] = 0; + } + + unsigned rgb_cc[3]; + + for(unsigned cc_i = 0; cc_i < 3; cc_i++) + { + float eff_y = y * (force_mono ? (((force_mono >> ((2 - cc_i) << 3)) & 0xFF) / 255.0) : 1.0); + float t = std::max(0.0, eff_y + d[cc_i][0] * color_diff[0] + d[cc_i][1] * color_diff[1]); + + //t = pow(t, d.power); + + //if(t > 1.10) + // printf("phase=%d color=0x%08x cc_i=%u t=%f\n", phase, color, cc_i, t); + + rgb_cc[cc_i] = std::min(1016, std::max(0, floor(0.5 + 1016 * t))); + } + + //printf("color 0x%01x: y=%f pb=%.13f pr=%.13f --- %3u %3u %3u\n", color, ySL2 / 4.0, pbSL6 / 64.0, prSL6 / 64.0, r, g, b); + + ColorLUT[cbp][phase][color] = (rgb_cc[0] << 0) + (rgb_cc[1] << 10) + (rgb_cc[2] << 20); + } + } + } + + if(s.color_smooth && !force_mono) + { + uint32 SmoothLUT[4][16]; + + for(unsigned phase = 0; phase < 4; phase++) + { + for(unsigned color = 0; color < 16; color++) + { + float r = 0; + float g = 0; + float b = 0; + int r_p, g_p, b_p; + + for(unsigned i = 0; i < 4; i++) + { + unsigned pattern = (color | (color << 4) | (color << 8) | (color << 12) | (color << 16)) >> (4 + i - phase); + uint32 cle = ColorLUT[1][(i) & 3][pattern & 0x1FFF]; + + r_p = (cle >> 0) & 0x3FF; + g_p = (cle >> 10) & 0x3FF; + b_p = (cle >> 20) & 0x3FF; + + r += pow(r_p / 1016.0, 2.2); + g += pow(g_p / 1016.0, 2.2); + b += pow(b_p / 1016.0, 2.2); + } + + r /= 4; + g /= 4; + b /= 4; + + r_p = std::min(1016, floor(0.5 + 1016 * pow(r, 1.0 / 2.2))); + g_p = std::min(1016, floor(0.5 + 1016 * pow(g, 1.0 / 2.2))); + b_p = std::min(1016, floor(0.5 + 1016 * pow(b, 1.0 / 2.2))); + + //printf("Phase: %d, Color: %d - 0x%02x 0x%02x 0x%02x\n", phase, color, r_p, g_p, b_p); + + SmoothLUT[phase][color] = (r_p << 0) + (g_p << 10) + (b_p << 20); + } + } + + for(unsigned phase = 0; phase < 4; phase++) + { + for(unsigned color = 0; color < (1U << ColorLUT_NumPixels); color++) + { + const unsigned c0 = (color >> 0) & 0x1F; + const unsigned c1 = (color >> 4) & 0x1F; + const unsigned c2 = (color >> 8) & 0x1F; + + if(c1 == c0 || c1 == c2 || (((color >> 2) & 0x7) == ((color >> 6) & 0x7) && ((color >> 3) & 0x7) == ((color >> 7) & 0x7))) + ColorLUT[1][phase][color] = SmoothLUT[phase][c1 & 0xF]; + } + } + } + + if(mode != Settings::MODE_COMPOSITE) + { + for(unsigned color = 0; color < 16; color++) + { + float r = 0; + float g = 0; + float b = 0; + int r_p, g_p, b_p; + + for(unsigned i = 0; i < 4; i++) + { + unsigned pattern = (color | (color << 4) | (color << 8) | (color << 12) | (color << 16)) >> (4 + i); + uint32 cle = ColorLUT[1][i & 3][pattern & 0x1FFF]; + + r_p = (cle >> 0) & 0x3FF; + g_p = (cle >> 10) & 0x3FF; + b_p = (cle >> 20) & 0x3FF; + + r += pow(r_p / 1016.0, 2.2); + g += pow(g_p / 1016.0, 2.2); + b += pow(b_p / 1016.0, 2.2); + } + + r /= 4; + g /= 4; + b /= 4; + + r_p = std::min(255, floor(0.5 + 255 * pow(r, 1.0 / 2.2))); + g_p = std::min(255, floor(0.5 + 255 * pow(g, 1.0 / 2.2))); + b_p = std::min(255, floor(0.5 + 255 * pow(b, 1.0 / 2.2))); + + //printf("Phase: %d, Color: %d - 0x%02x 0x%02x 0x%02x\n", phase, color, r_p, g_p, b_p); + + RGBLUT[color] = format.MakeColor(r_p, g_p, b_p); + RGBLUT[16 + color] = format.MakeColor(r_p * 3 / 4, g_p * 3 / 4, b_p * 3 / 4); + } + } +} + } diff --git a/mednafen/cdplay/cdplay.cpp b/mednafen/cdplay/cdplay.cpp index f4bb013..2d1eda7 100644 --- a/mednafen/cdplay/cdplay.cpp +++ b/mednafen/cdplay/cdplay.cpp @@ -555,6 +555,7 @@ MDFNGI EmulatedCDPlay = PortInfo, // NULL, NULL, + NULL, LoadCD, TestMagicCD, CloseGame, diff --git a/mednafen/cdrom/recover-raw.cpp b/mednafen/cdrom/recover-raw.cpp index e7dee73..8300dea 100644 --- a/mednafen/cdrom/recover-raw.cpp +++ b/mednafen/cdrom/recover-raw.cpp @@ -178,7 +178,7 @@ static int simple_lec(unsigned char *frame) int ValidateRawSector(unsigned char *frame, bool xaMode) { - int lec_did_sth = FALSE; + //int lec_did_sth = FALSE; /* Do simple L-EC. It seems that drives stop their internal L-EC as soon as the @@ -196,17 +196,17 @@ int ValidateRawSector(unsigned char *frame, bool xaMode) memset(frame + 12, 0, 4); } - lec_did_sth = simple_lec(frame); + /*lec_did_sth =*/ simple_lec(frame); if(xaMode) memcpy(frame + 12, header, 4); - } - /* Test internal sector checksum again */ - if(!CheckEDC(frame, xaMode)) - { - /* EDC failure in RAW sector */ - return FALSE; + /* Test internal sector checksum again */ + if(!CheckEDC(frame, xaMode)) + { + /* EDC failure in RAW sector */ + return FALSE; + } } return TRUE; diff --git a/mednafen/demo/demo.cpp b/mednafen/demo/demo.cpp index f924d6a..4cd5549 100644 --- a/mednafen/demo/demo.cpp +++ b/mednafen/demo/demo.cpp @@ -755,6 +755,7 @@ MDFNGI EmulatedDEMO = MODPRIO_INTERNAL_LOW, NULL, PortInfo, + NULL, Load, TestMagic, NULL, diff --git a/mednafen/desa68/desa68.c b/mednafen/desa68/desa68.c index 1cbe22f..6437aa3 100644 --- a/mednafen/desa68/desa68.c +++ b/mednafen/desa68/desa68.c @@ -124,7 +124,7 @@ static void desa_char(const unsigned char c) #endif /* Add a string to disassembly string */ -static void desa_str(char *str) +static void desa_str(const char *str) { char c; while(c=*str++, c) @@ -1017,7 +1017,7 @@ static void desa_line4(void) return; case 6: /* FUNKY LINE 4 MODE 6 (4E */ { - static char *str[8] = /* $4E70 - $4E77 */ + static const char *str[8] = /* $4E70 - $4E77 */ { /* 0 1 2 3 4 5 6 7 */ "RESET","NOP","STOP ","RTE", "?","RTS","TRAPV","RTR" diff --git a/mednafen/drivers/main.cpp b/mednafen/drivers/main.cpp index ff7d59a..3e73116 100644 --- a/mednafen/drivers/main.cpp +++ b/mednafen/drivers/main.cpp @@ -66,7 +66,9 @@ static bool SuppressErrorPopups; // Set from env variable "MEDNAFEN_NOPOPUPS" static int StateSLSTest = false; static int StateRCTest = false; // Rewind consistency - +#if 0 +static int StatePCTest = false; // Power(toggle) consistency +#endif static WMInputBehavior NeededWMInputBehavior = { false, false, false, false }; static bool NeededWMInputBehavior_Dirty = false; @@ -152,11 +154,11 @@ static const MDFNSetting DriverSettings[] = gettext_noop("Disable to reduce latency, at the cost of potentially increased video \"juddering\", with the maximum reduction in latency being about 1 video frame's time.\nWill work best with emulated systems that are not very computationally expensive to emulate, combined with running on a relatively fast CPU."), MDFNST_BOOL, "1" }, - { "ffspeed", MDFNSF_NOFLAGS, gettext_noop("Fast-forwarding speed multiplier."), NULL, MDFNST_FLOAT, "4", "1", "15" }, + { "ffspeed", MDFNSF_NOFLAGS, gettext_noop("Fast-forwarding speed multiplier."), NULL, MDFNST_FLOAT, "4", "0.25", "15" }, { "fftoggle", MDFNSF_NOFLAGS, gettext_noop("Treat the fast-forward button as a toggle."), NULL, MDFNST_BOOL, "0" }, { "ffnosound", MDFNSF_NOFLAGS, gettext_noop("Silence sound output when fast-forwarding."), NULL, MDFNST_BOOL, "0" }, - { "sfspeed", MDFNSF_NOFLAGS, gettext_noop("SLOW-forwarding speed multiplier."), NULL, MDFNST_FLOAT, "0.75", "0.25", "1" }, + { "sfspeed", MDFNSF_NOFLAGS, gettext_noop("SLOW-forwarding speed multiplier."), NULL, MDFNST_FLOAT, "0.75", "0.25", "15" }, { "sftoggle", MDFNSF_NOFLAGS, gettext_noop("Treat the SLOW-forward button as a toggle."), NULL, MDFNST_BOOL, "0" }, { "nothrottle", MDFNSF_NOFLAGS, gettext_noop("Disable speed throttling when sound is disabled."), NULL, MDFNST_BOOL, "0"}, @@ -865,6 +867,11 @@ static bool DoArgs(int argc, char *argv[], char **filename) // Save state rewind consistency test. { "staterctest", NULL, &StateRCTest, 0, 0 }, +#if 0 + // Save state power consistency test. + { "statepctest", NULL, &StatePCTest, 0, 0 }, +#endif + // SwiftResampler test. { "swiftresamptest", NULL, &swiftresamptest, 0, 0 }, @@ -982,7 +989,45 @@ static int LoadGame(const char *force_module, const char *path) if(!(tmp=MDFNI_LoadGame(force_module, &::Mednafen::NVFS, path))) return 0; } + // + // + // +#if 0 + if(StatePCTest) + { + MemoryStream state0(524288); + MemoryStream state1(524288); + MDFNI_Power(); + MDFNSS_SaveSM(&state0); + state0.rewind(); + MDFNSS_LoadSM(&state0, false, true); + MDFNI_CloseGame(); + if(!(tmp=MDFNI_LoadGame(force_module, &::Mednafen::NVFS, path))) + abort(); + MDFNI_Power(); + MDFNSS_SaveSM(&state1); + state0.rewind(); + MDFNSS_LoadSM(&state0); + MDFNI_CloseGame(); + if(!(tmp=MDFNI_LoadGame(force_module, &::Mednafen::NVFS, path))) + abort(); + if(!(state0.map_size() == state1.map_size() && !memcmp(state0.map() + 32, state1.map() + 32, state1.map_size() - 32))) + { + FileStream sd0("/tmp/sdump0", FileStream::MODE_WRITE); + FileStream sd1("/tmp/sdump1", FileStream::MODE_WRITE); + + sd0.write(state0.map(), state0.map_size()); + sd1.write(state1.map(), state1.map_size()); + sd0.close(); + sd1.close(); + abort(); + } + } +#endif + // + // + // CurGame = tmp; Input_GameLoaded(tmp); RMDUI_Init(tmp, which_medium); diff --git a/mednafen/drivers/sound.cpp b/mednafen/drivers/sound.cpp index d454a61..6b735bc 100644 --- a/mednafen/drivers/sound.cpp +++ b/mednafen/drivers/sound.cpp @@ -74,6 +74,7 @@ void Sound_WriteSilence(int ms) Output->Write(Output, SBuffer, frames); } +#if 0 static std::string sampformat_to_string(const uint32 sampformat) { char buf[256]; @@ -95,7 +96,6 @@ static std::string sampformat_to_string(const uint32 sampformat) return buf; } -#if 0 static bool RunSexyALTest(SexyAL_buffering* buffering, const char* device, int driver_type) { static const uint32 sampformats[] = diff --git a/mednafen/gb/gb.cpp b/mednafen/gb/gb.cpp index ec26903..6a52560 100644 --- a/mednafen/gb/gb.cpp +++ b/mednafen/gb/gb.cpp @@ -2864,6 +2864,7 @@ MDFNGI EmulatedGB = MODPRIO_INTERNAL_HIGH, NULL, PortInfo, + NULL, Load, TestMagic, NULL, diff --git a/mednafen/gba/GBA.cpp b/mednafen/gba/GBA.cpp index 95b0155..68d1afe 100644 --- a/mednafen/gba/GBA.cpp +++ b/mednafen/gba/GBA.cpp @@ -3339,6 +3339,7 @@ MDFNGI EmulatedGBA = MODPRIO_INTERNAL_HIGH, NULL, PortInfo, + NULL, Load, TestMagic, NULL, diff --git a/mednafen/git.h b/mednafen/git.h index f03b725..ff742ac 100644 --- a/mednafen/git.h +++ b/mednafen/git.h @@ -528,6 +528,24 @@ struct DesiredInputType std::map switches; }; +struct GameDB_Entry +{ + std::string GameID; + bool GameIDIsHash = false; + std::string Name; + std::string Setting; + std::string Purpose; +}; + +struct GameDB_Database +{ + std::string ShortName; + std::string FullName; + std::string Description; + + std::vector Entries; +}; + typedef struct { /* Private functions to Mednafen. Do not call directly @@ -554,6 +572,8 @@ typedef struct #endif const std::vector &PortInfo; + void (*GetInternalDB)(std::vector* databases); + // // throws exception on fatal error. // diff --git a/mednafen/hw_cpu/m68k/m68k.cpp b/mednafen/hw_cpu/m68k/m68k.cpp index 16159ce..a36b135 100644 --- a/mednafen/hw_cpu/m68k/m68k.cpp +++ b/mednafen/hw_cpu/m68k/m68k.cpp @@ -107,6 +107,9 @@ void M68K::StateAction(StateMem* sm, const unsigned load, const bool data_only, }; MDFNSS_StateAction(sm, load, data_only, StateRegs, sname); + + if(load) + XPending &= XPENDING_MASK__VALID; } void M68K::LoadOldState(const uint8* osm) @@ -2274,6 +2277,8 @@ void M68K::Reset(bool powering_up) { if(powering_up) { + PC = 0; + for(unsigned i = 0; i < 8; i++) D[i] = 0; @@ -2284,7 +2289,7 @@ void M68K::Reset(bool powering_up) SetSR(0); } - XPending = (XPending & ~XPENDING_MASK_STOPPED) | XPENDING_MASK_RESET; + XPending = (XPending & ~(XPENDING_MASK_STOPPED | XPENDING_MASK_NMI)) | XPENDING_MASK_RESET; } diff --git a/mednafen/hw_cpu/m68k/m68k.h b/mednafen/hw_cpu/m68k/m68k.h index 8d64630..9cfbfc5 100644 --- a/mednafen/hw_cpu/m68k/m68k.h +++ b/mednafen/hw_cpu/m68k/m68k.h @@ -80,7 +80,10 @@ class M68K XPENDING_MASK_NMI = 0x0002, XPENDING_MASK_RESET = 0x0010, XPENDING_MASK_STOPPED = 0x0100, // via STOP instruction - XPENDING_MASK_EXTHALTED= 0x1000 + XPENDING_MASK_EXTHALTED= 0x1000, + + // For save state sanitizing: + XPENDING_MASK__VALID = XPENDING_MASK_INT | XPENDING_MASK_NMI | XPENDING_MASK_RESET | XPENDING_MASK_STOPPED | XPENDING_MASK_EXTHALTED }; const bool Revision_E; diff --git a/mednafen/lynx/system.cpp b/mednafen/lynx/system.cpp index 844d923..95d17c1 100644 --- a/mednafen/lynx/system.cpp +++ b/mednafen/lynx/system.cpp @@ -447,6 +447,7 @@ MDFNGI EmulatedLynx = MODPRIO_INTERNAL_HIGH, NULL, PortInfo, + NULL, Load, TestMagic, NULL, diff --git a/mednafen/md/system.cpp b/mednafen/md/system.cpp index 7aa3759..77675c6 100644 --- a/mednafen/md/system.cpp +++ b/mednafen/md/system.cpp @@ -795,6 +795,7 @@ MDFNGI EmulatedMD = NULL, #endif MDPortInfo, + NULL, Load, MDCart_TestMagic, LoadCD, diff --git a/mednafen/mednafen.cpp b/mednafen/mednafen.cpp index d3b18a3..d24c51e 100644 --- a/mednafen/mednafen.cpp +++ b/mednafen/mednafen.cpp @@ -530,6 +530,30 @@ void MDFNI_DumpModulesDef(const char *fn) fp.print_format("\n"); } } + + std::vector gamedb; + + if(MDFNSystems[i]->GetInternalDB) + MDFNSystems[i]->GetInternalDB(&gamedb); + + fp.print_format("%zu\n", gamedb.size()); + + for(const GameDB_Database& db : gamedb) + { + fp.print_format("%s\n", MDFN_strescape(db.ShortName).c_str()); + fp.print_format("%s\n", MDFN_strescape(db.FullName).c_str()); + fp.print_format("%s\n", MDFN_strescape(db.Description).c_str()); + + fp.print_format("%zu\n", db.Entries.size()); + for(const GameDB_Entry& gdbe : db.Entries) + { + fp.print_format("%s\n", MDFN_strescape(gdbe.Name).c_str()); + fp.print_format("%s\n", MDFN_strescape(gdbe.GameID).c_str()); + fp.print_format("%u\n", gdbe.GameIDIsHash); + fp.print_format("%s\n", MDFN_strescape(gdbe.Setting).c_str()); + fp.print_format("%s\n", MDFN_strescape(gdbe.Purpose).c_str()); + } + } } fp.close(); diff --git a/mednafen/nes/nes.cpp b/mednafen/nes/nes.cpp index e5255aa..efd7cc4 100644 --- a/mednafen/nes/nes.cpp +++ b/mednafen/nes/nes.cpp @@ -775,6 +775,7 @@ MDFNGI EmulatedNES = NULL, #endif NESPortInfo, + NULL, Load, TestMagic, NULL, diff --git a/mednafen/ngp/Makefile.am.inc b/mednafen/ngp/Makefile.am.inc index ae26154..3ba7a2b 100644 --- a/mednafen/ngp/Makefile.am.inc +++ b/mednafen/ngp/Makefile.am.inc @@ -4,11 +4,12 @@ libngp_a_CXXFLAGS = @AM_CXXFLAGS@ @NO_STRICT_ALIASING_FLAGS@ libngp_a_SOURCES = ngp/bios.cpp ngp/biosHLE.cpp ngp/dma.cpp ngp/flash.cpp ngp/gfx.cpp ngp/T6W28_Apu.cpp \ ngp/gfx_scanline_mono.cpp ngp/gfx_scanline_colour.cpp ngp/interrupt.cpp ngp/mem.cpp ngp/neopop.cpp \ ngp/rom.cpp ngp/rtc.cpp ngp/sound.cpp ngp/Z80_interface.cpp \ - ngp/TLCS-900h/TLCS900h_disassemble_extra.cpp ngp/TLCS-900h/TLCS900h_disassemble_reg.cpp \ - ngp/TLCS-900h/TLCS900h_interpret_single.cpp ngp/TLCS-900h/TLCS900h_disassemble_src.cpp \ - ngp/TLCS-900h/TLCS900h_interpret.cpp ngp/TLCS-900h/TLCS900h_registers.cpp ngp/TLCS-900h/TLCS900h_interpret_reg.cpp \ - ngp/TLCS-900h/TLCS900h_disassemble.cpp ngp/TLCS-900h/TLCS900h_interpret_src.cpp \ - ngp/TLCS-900h/TLCS900h_interpret_dst.cpp ngp/TLCS-900h/TLCS900h_disassemble_dst.cpp + ngp/TLCS-900h/TLCS900h_interpret_single.cpp \ + ngp/TLCS-900h/TLCS900h_interpret.cpp \ + ngp/TLCS-900h/TLCS900h_registers.cpp \ + ngp/TLCS-900h/TLCS900h_interpret_reg.cpp \ + ngp/TLCS-900h/TLCS900h_interpret_src.cpp \ + ngp/TLCS-900h/TLCS900h_interpret_dst.cpp mednafen_LDADD += libngp.a mednafen_DEPENDENCIES += libngp.a diff --git a/mednafen/ngp/TLCS-900h/TLCS900h_interpret_reg.cpp b/mednafen/ngp/TLCS-900h/TLCS900h_interpret_reg.cpp index fc91219..9f4ede4 100644 --- a/mednafen/ngp/TLCS-900h/TLCS900h_interpret_reg.cpp +++ b/mednafen/ngp/TLCS-900h/TLCS900h_interpret_reg.cpp @@ -732,12 +732,61 @@ void regTSET() cycles = 6; } +#if 0 +// TODO, test on an actual TLCS-900H CPU: + +//===== MINC1 #,r +void regMINC1() +{ + const uint16 mask = fetch16() | 0; + const uint16 origval = rCodeW(rCode); + + if(size == 1) + rCodeW(rCode) = (origval & ~mask) + ((origval + 1) & mask); + + printf("MINC1: 0x%04x, 0x%04x->0x%04x%s\n", mask, origval, rCodeW(rCode), (rCodeW(rCode) < origval) ? " (wrap)" : ""); + + cycles = 8; +} + +//===== MINC2 #,r +// Densetsu no Ogre Battle Gaiden +void regMINC2() +{ + const uint16 mask = fetch16() | 1; + const uint16 origval = rCodeW(rCode); + + if(size == 1) + rCodeW(rCode) = (origval & ~mask) + ((origval + 2) & mask); + + printf("MINC2: 0x%04x, 0x%04x->0x%04x%s\n", mask, origval, rCodeW(rCode), (rCodeW(rCode) < origval) ? " (wrap)" : ""); + + cycles = 8; +} + +//===== MINC4 #,r +// Pocket Tennis Color +void regMINC4() +{ + const uint16 mask = fetch16() | 3; + const uint16 origval = rCodeW(rCode); + + if(size == 1) + rCodeW(rCode) = (origval & ~mask) + ((origval + 4) & mask); + + printf("MINC4: 0x%04x, 0x%04x->0x%04x%s\n", mask, origval, rCodeW(rCode), (rCodeW(rCode) < origval) ? " (wrap)" : ""); + + cycles = 8; +} + +#endif + //===== MINC1 #,r void regMINC1() { uint16 num = fetch16() + 1; - if (size == 1) + if (size == 1 && num) { if ((rCodeW(rCode) % num) == (num - 1)) rCodeW(rCode) -= (num - 1); @@ -753,7 +802,7 @@ void regMINC2() { uint16 num = fetch16() + 2; - if (size == 1) + if (size == 1 && num) { if ((rCodeW(rCode) % num) == (num - 2)) rCodeW(rCode) -= (num - 2); @@ -769,7 +818,7 @@ void regMINC4() { uint16 num = fetch16() + 4; - if (size == 1) + if (size == 1 && num) { if ((rCodeW(rCode) % num) == (num - 4)) rCodeW(rCode) -= (num - 4); @@ -785,7 +834,7 @@ void regMDEC1() { uint16 num = fetch16() + 1; - if (size == 1) + if (size == 1 && num) { if ((rCodeW(rCode) % num) == 0) rCodeW(rCode) += (num - 1); @@ -801,7 +850,7 @@ void regMDEC2() { uint16 num = fetch16() + 2; - if (size == 1) + if (size == 1 && num) { if ((rCodeW(rCode) % num) == 0) rCodeW(rCode) += (num - 2); @@ -817,7 +866,7 @@ void regMDEC4() { uint16 num = fetch16() + 4; - if (size == 1) + if (size == 1 && num) { if ((rCodeW(rCode) % num) == 0) rCodeW(rCode) += (num - 4); diff --git a/mednafen/ngp/TLCS-900h/TLCS900h_interpret_single.cpp b/mednafen/ngp/TLCS-900h/TLCS900h_interpret_single.cpp index 1561b06..a5660b9 100644 --- a/mednafen/ngp/TLCS-900h/TLCS900h_interpret_single.cpp +++ b/mednafen/ngp/TLCS-900h/TLCS900h_interpret_single.cpp @@ -408,16 +408,16 @@ void sngSWI() pc = loadL(0xFFFE00 + ((rCodeB(0x31) & 0x1F) << 2)); break; - case 3: interrupt(0); //SWI 3 + case 3: interrupt(0, -1); //SWI 3 break; - case 4: interrupt(1); //SWI 4 + case 4: interrupt(1, -1); //SWI 4 break; - case 5: interrupt(2); //SWI 5 + case 5: interrupt(2, -1); //SWI 5 break; - case 6: interrupt(3); //SWI 6 + case 6: interrupt(3, -1); //SWI 6 break; default: instruction_error("SWI %d is not valid.", first & 7); diff --git a/mednafen/ngp/TLCS-900h/TLCS900h_interpret_src.cpp b/mednafen/ngp/TLCS-900h/TLCS900h_interpret_src.cpp index a51ba6f..e0bbc74 100644 --- a/mednafen/ngp/TLCS-900h/TLCS900h_interpret_src.cpp +++ b/mednafen/ngp/TLCS-900h/TLCS900h_interpret_src.cpp @@ -263,15 +263,15 @@ void srcLDDR() //===== CPI void srcCPI() { - uint8 R = first & 7; + uint8 R_local = first & 7; switch(size) { - case 0: generic_SUB_B(REGA, loadB(regL(R))); - regL(R) ++; break; + case 0: generic_SUB_B(REGA, loadB(regL(R_local))); + regL(R_local) ++; break; - case 1: generic_SUB_W(REGWA, loadW(regL(R))); - regL(R) += 2; break; + case 1: generic_SUB_W(REGWA, loadW(regL(R_local))); + regL(R_local) += 2; break; } REGBC --; @@ -283,7 +283,7 @@ void srcCPI() //===== CPIR void srcCPIR() { - uint8 R = first & 7; + uint8 R_local = first & 7; cycles = 10; @@ -292,12 +292,12 @@ void srcCPIR() switch(size) { case 0: if (debug_abort_memory == false) - generic_SUB_B(REGA, loadB(regL(R))); - regL(R) ++; break; + generic_SUB_B(REGA, loadB(regL(R_local))); + regL(R_local) ++; break; case 1: if (debug_abort_memory == false) - generic_SUB_W(REGWA, loadW(regL(R))); - regL(R) += 2; break; + generic_SUB_W(REGWA, loadW(regL(R_local))); + regL(R_local) += 2; break; } REGBC --; @@ -311,15 +311,15 @@ void srcCPIR() //===== CPD void srcCPD() { - uint8 R = first & 7; + uint8 R_local = first & 7; switch(size) { - case 0: generic_SUB_B(REGA, loadB(regL(R))); - regL(R) --; break; + case 0: generic_SUB_B(REGA, loadB(regL(R_local))); + regL(R_local) --; break; - case 1: generic_SUB_W(REGWA, loadW(regL(R))); - regL(R) -= 2; break; + case 1: generic_SUB_W(REGWA, loadW(regL(R_local))); + regL(R_local) -= 2; break; } REGBC --; @@ -331,7 +331,7 @@ void srcCPD() //===== CPDR void srcCPDR() { - uint8 R = first & 7; + uint8 R_local = first & 7; cycles = 10; @@ -340,12 +340,12 @@ void srcCPDR() switch(size) { case 0: if (debug_abort_memory == false) - generic_SUB_B(REGA, loadB(regL(R))); - regL(R) -= 1; break; + generic_SUB_B(REGA, loadB(regL(R_local))); + regL(R_local) -= 1; break; case 1: if (debug_abort_memory == false) - generic_SUB_W(REGWA, loadW(regL(R))); - regL(R) -= 2; break; + generic_SUB_W(REGWA, loadW(regL(R_local))); + regL(R_local) -= 2; break; } REGBC --; diff --git a/mednafen/ngp/biosHLE.cpp b/mednafen/ngp/biosHLE.cpp index 6ae6c21..e549475 100644 --- a/mednafen/ngp/biosHLE.cpp +++ b/mednafen/ngp/biosHLE.cpp @@ -321,8 +321,36 @@ void iBIOSHLE(void) if (filter_bios) system_debug_message("VECT_FLASHERS: bank %d, block %d (?)", rCodeB(0x30), rCodeB(0x35)); #endif - //TODO - rCodeB(0x30) = 0; //RA3 = SYS_SUCCESS + // + // + // + { + const uint8 bank = rCodeB(0x30); + const uint8 flash_block = rCodeB(0x35); + + //printf("flash erase: %d 0x%02x\n", bank, flash_block); + + if((ngpc_rom.length & ~0x1FFF) == 0x200000 && bank == 0 && flash_block == 31) + { + const uint32 addr = 0x3F0000; + const uint32 size = 0x008000; + + flash_optimise_blocks(); + flash_write(addr, size); + flash_optimise_blocks(); + + memory_flash_error = false; + memory_unlock_flash_write = true; + for(uint32 i = 0; i < size; i += 4) + { + storeL(addr + i, 0xFFFFFFFF); + } + memory_unlock_flash_write = false; + } + + rCodeB(0x30) = 0; //RA3 = SYS_SUCCESS + //rCodeB(0x30) = 0xFF; //RA3 = SYS_FAILURE + } break; //VECT_ALARMSET diff --git a/mednafen/ngp/dma.cpp b/mednafen/ngp/dma.cpp index 277c280..9945c28 100644 --- a/mednafen/ngp/dma.cpp +++ b/mednafen/ngp/dma.cpp @@ -188,7 +188,8 @@ void DMA_update(int channel) dmaC[channel] --; if (dmaC[channel] == 0) { - interrupt(14 + channel); + //printf("dma end: %d\n", channel); + interrupt(14 + channel, 7); storeB(0x7C + channel, 0); } } diff --git a/mednafen/ngp/flash.cpp b/mednafen/ngp/flash.cpp index ceac6c1..3e892fc 100644 --- a/mednafen/ngp/flash.cpp +++ b/mednafen/ngp/flash.cpp @@ -69,7 +69,7 @@ static uint16 block_count; //----------------------------------------------------------------------------- // optimise_blocks() //----------------------------------------------------------------------------- -static void optimise_blocks(void) +void flash_optimise_blocks(void) { int i, j; @@ -105,9 +105,8 @@ static void optimise_blocks(void) (blocks[i].start_address + blocks[i].data_length)) { //Extend the first block - blocks[i].data_length = - (uint16)((blocks[i+1].start_address + blocks[i+1].data_length) - - blocks[i].start_address); + blocks[i].data_length = (uint16)(std::max(blocks[i + 0].start_address + blocks[i + 0].data_length, + blocks[i + 1].start_address + blocks[i + 1].data_length) - blocks[i].start_address); //Remove the next one. for (j = i+2; j < block_count; j++) @@ -122,6 +121,9 @@ static void optimise_blocks(void) i++; // Try the next block } } + + //for(i = 0; i < block_count; i++) + // printf("block: 0x%08x 0x%04x\n", blocks[i].start_address, blocks[i].data_length); } static void do_flash_read(const uint8 *flashdata) @@ -162,7 +164,7 @@ static void do_flash_read(const uint8 *flashdata) } memory_unlock_flash_write = PREV_memory_unlock_flash_write; - optimise_blocks(); //Optimise + flash_optimise_blocks(); //Optimise #if 0 //Output block list... @@ -211,6 +213,8 @@ void flash_write(uint32 start_address, uint16 length) { uint16 i; + //printf("flash_write 0x%08x 0x%04x\n", start_address, length); + //Now we need a new flash command before the next flash write will work! memory_flash_command = false; @@ -260,7 +264,7 @@ static void make_flash_commit(PODFastVector &flashdata) return; //Optimise before writing - optimise_blocks(); + flash_optimise_blocks(); //Build a header; header.valid_flash_id = FLASH_VALID_ID; diff --git a/mednafen/ngp/flash.h b/mednafen/ngp/flash.h index 662be2a..692f3dd 100644 --- a/mednafen/ngp/flash.h +++ b/mednafen/ngp/flash.h @@ -21,6 +21,7 @@ namespace MDFN_IEN_NGP //Marks flash blocks for saving. void flash_write(uint32 start_address, uint16 length); +void flash_optimise_blocks(void); void FLASH_LoadNV(void); void FLASH_SaveNV(void); diff --git a/mednafen/ngp/interrupt.cpp b/mednafen/ngp/interrupt.cpp index 0f69136..7fefba1 100644 --- a/mednafen/ngp/interrupt.cpp +++ b/mednafen/ngp/interrupt.cpp @@ -48,15 +48,15 @@ static bool h_int, timer0, timer2; // a device sets the virual interrupt latch register, signaling it wants an interrupt. // FIXME in the future if we ever add real bios support? -void interrupt(uint8 index) +void interrupt(const uint8 index, const int level) { //printf("INT: %d\n", index); push32(pc); push16(sr); - //Up the IFF - if (((sr & 0x7000) >> 12) < 7) - setStatusIFF(((sr & 0x7000) >> 12) + 1); + //Up the IFF + if(level >= 0) + setStatusIFF((level < 7) ? (level + 1) : 7); //Access the interrupt vector table to find the jump destination pc = loadL(0x6FB8 + index * 4); @@ -82,7 +82,7 @@ void int_check_pending(void) if(ipending[5] && curIFF <= prio && prio && prio != 7) { ipending[5] = 0; - interrupt(5); + interrupt(5, prio); return; } @@ -90,7 +90,7 @@ void int_check_pending(void) if(ipending[6] && curIFF <= prio && prio && prio != 7) { ipending[6] = 0; - interrupt(6); + interrupt(6, prio); return; } @@ -98,7 +98,7 @@ void int_check_pending(void) if(ipending[7] && curIFF <= prio && prio && prio != 7) { ipending[7] = 0; - interrupt(7); + interrupt(7, prio); return; } @@ -106,7 +106,7 @@ void int_check_pending(void) if(ipending[8] && curIFF <= prio && prio && prio != 7) { ipending[8] = 0; - interrupt(8); + interrupt(8, prio); return; } @@ -114,7 +114,7 @@ void int_check_pending(void) if(ipending[9] && curIFF <= prio && prio && prio != 7) { ipending[9] = 0; - interrupt(9); + interrupt(9, prio); return; } @@ -122,7 +122,7 @@ void int_check_pending(void) if(ipending[10] && curIFF <= prio && prio && prio != 7) { ipending[10] = 0; - interrupt(10); + interrupt(10, prio); return; } @@ -130,7 +130,7 @@ void int_check_pending(void) if(ipending[11] && curIFF <= prio && prio && prio != 7) { ipending[11] = 0; - interrupt(11); + interrupt(11, prio); return; } @@ -138,7 +138,7 @@ void int_check_pending(void) if(ipending[12] && curIFF <= prio && prio && prio != 7) { ipending[12] = 0; - interrupt(12); + interrupt(12, prio); return; } diff --git a/mednafen/ngp/interrupt.h b/mednafen/ngp/interrupt.h index a0b622f..d5e7d5f 100644 --- a/mednafen/ngp/interrupt.h +++ b/mednafen/ngp/interrupt.h @@ -19,7 +19,7 @@ namespace MDFN_IEN_NGP { -void interrupt(uint8 index); +void interrupt(const uint8 index, const int level); #define TIMER_HINT_RATE 515 //CPU Ticks between horizontal interrupts diff --git a/mednafen/ngp/neopop.cpp b/mednafen/ngp/neopop.cpp index 0dfd5bc..968ee67 100644 --- a/mednafen/ngp/neopop.cpp +++ b/mednafen/ngp/neopop.cpp @@ -391,6 +391,7 @@ MDFNGI EmulatedNGP = MODPRIO_INTERNAL_HIGH, NULL, PortInfo, + NULL, Load, TestMagic, NULL, diff --git a/mednafen/ngp/neopop.h b/mednafen/ngp/neopop.h index 9d7ff9b..518fe12 100644 --- a/mednafen/ngp/neopop.h +++ b/mednafen/ngp/neopop.h @@ -19,7 +19,7 @@ #include #include -#include "TLCS-900h/TLCS900h_disassemble.h" +//#include "TLCS-900h/TLCS900h_disassemble.h" #include "TLCS-900h/TLCS900h_interpret_dst.h" #include "TLCS-900h/TLCS900h_interpret.h" #include "TLCS-900h/TLCS900h_interpret_reg.h" diff --git a/mednafen/pce/pce.cpp b/mednafen/pce/pce.cpp index 0a19c13..e599bf8 100644 --- a/mednafen/pce/pce.cpp +++ b/mednafen/pce/pce.cpp @@ -1222,6 +1222,7 @@ MDFNGI EmulatedPCE = NULL, #endif PCEPortInfo, + NULL, Load, TestMagic, LoadCD, diff --git a/mednafen/pce/pcecd.cpp b/mednafen/pce/pcecd.cpp index 4ac0113..5d21fbb 100644 --- a/mednafen/pce/pcecd.cpp +++ b/mednafen/pce/pcecd.cpp @@ -525,14 +525,12 @@ MDFN_FASTCALL uint8 PCECD_Read(uint32 timestamp, uint32 A, int32 &next_event, co if((A & 0x18c0) == 0x18c0) { - switch (A & 0x18cf) + ret = 0xFF; + if(!(A & 0xC)) { - case 0x18c1: ret = 0xaa; break; - case 0x18c2: ret = 0x55; break; - case 0x18c3: ret = 0x00; break; - case 0x18c5: ret = 0xaa; break; - case 0x18c6: ret = 0x55; break; - case 0x18c7: ret = 0x03; break; + static const uint8 sig[4] = { 0x00, 0xAA, 0x55, 0x03 }; + + ret = sig[A & 0x3]; } } else diff --git a/mednafen/pce_fast/pce.cpp b/mednafen/pce_fast/pce.cpp index 96da4ec..cac383f 100644 --- a/mednafen/pce_fast/pce.cpp +++ b/mednafen/pce_fast/pce.cpp @@ -744,6 +744,7 @@ MDFNGI EmulatedPCE_Fast = MODPRIO_INTERNAL_LOW, NULL, PCEPortInfo, + NULL, Load, TestMagic, LoadCD, diff --git a/mednafen/pcfx/pcfx.cpp b/mednafen/pcfx/pcfx.cpp index 77a0fdb..d3758fc 100644 --- a/mednafen/pcfx/pcfx.cpp +++ b/mednafen/pcfx/pcfx.cpp @@ -1103,6 +1103,7 @@ MDFNGI EmulatedPCFX = PCFXPortInfo, NULL, NULL, + NULL, LoadCD, TestMagicCD, CloseGame, diff --git a/mednafen/psx/cdc.cpp b/mednafen/psx/cdc.cpp index b14124c..4ca750d 100644 --- a/mednafen/psx/cdc.cpp +++ b/mednafen/psx/cdc.cpp @@ -220,6 +220,8 @@ void PS_CDC::Power(void) SoftReset(); + HoldLogicalPos = false; + DiscStartupDelay = 0; SPUCounter = SPU->UpdateFromCDC(0); diff --git a/mednafen/psx/psx.cpp b/mednafen/psx/psx.cpp index cedcf66..a455338 100644 --- a/mednafen/psx/psx.cpp +++ b/mednafen/psx/psx.cpp @@ -2297,6 +2297,7 @@ MDFNGI EmulatedPSX = NULL, #endif FIO_PortInfo, + NULL, Load, TestMagic, LoadCD, diff --git a/mednafen/sms/system.cpp b/mednafen/sms/system.cpp index 6299ea4..6a35c0c 100644 --- a/mednafen/sms/system.cpp +++ b/mednafen/sms/system.cpp @@ -435,6 +435,7 @@ MDFNGI EmulatedSMS = MODPRIO_INTERNAL_HIGH, NULL, SMSPortInfo, + NULL, LoadSMS, TestMagicSMS, NULL, @@ -486,6 +487,7 @@ MDFNGI EmulatedGG = MODPRIO_INTERNAL_HIGH, NULL, GGPortInfo, + NULL, LoadGG, TestMagicGG, NULL, diff --git a/mednafen/snes/interface.cpp b/mednafen/snes/interface.cpp index 342efb5..b3f2428 100644 --- a/mednafen/snes/interface.cpp +++ b/mednafen/snes/interface.cpp @@ -1364,6 +1364,7 @@ MDFNGI EmulatedSNES = MODPRIO_INTERNAL_HIGH, NULL, // Debugger PortInfo, + NULL, Load, TestMagic, NULL, diff --git a/mednafen/snes_faust/Core65816.h b/mednafen/snes_faust/Core65816.h new file mode 100644 index 0000000..1dd6e15 --- /dev/null +++ b/mednafen/snes_faust/Core65816.h @@ -0,0 +1,283 @@ +/******************************************************************************/ +/* Mednafen - Multi-system Emulator */ +/******************************************************************************/ +/* Core65816.h - 65816 CPU Emulator Core +** Copyright (C) 2015-2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +class Core65816 +{ + public: + Core65816() MDFN_COLD; + ~Core65816() MDFN_COLD; + + void Power(void) MDFN_COLD; + void Reset(void) MDFN_COLD; + + void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname); + + //private: + + enum + { + N_FLAG = 0x80, + V_FLAG = 0x40, + + M_FLAG = 0x20, // Memory/Accumulator(0=16-bit) + X_FLAG = 0x10, // Index(0=16-bit) + + D_FLAG = 0x08, + I_FLAG = 0x04, + Z_FLAG = 0x02, + C_FLAG = 0x01, + }; + + union + { + struct + { +#ifdef MSB_FIRST + uint8 PCPBRDummy; + uint8 PBR; + uint16 PC; +#else + uint16 PC; + uint8 PBR; + uint8 PCPBRDummy; +#endif + }; + uint32 PCPBR; + }; + uint32 DBRSL16; + + uint16 S; + uint16 D; + + union + { + uint16 C; + struct + { +#ifdef MSB_FIRST + uint8 B; + uint8 A; +#else + uint8 A; + uint8 B; +#endif + }; + }; + + template + INLINE T& AC(void) // Clever and/or horrible. + { +/* + if(sizeof(T) == 2) + return (T&)C; + else + return (T&)A; +*/ + return *(T*)((sizeof(T) == 2) ? (void*)&C : (void*)&A); + } + + uint16 X, Y; + uint8 P; + bool E; + + void SampleIRQ(void); +/* + INLINE void SampleIRQ(void) + { + PIN_Delay = ((P ^ I_FLAG) | 0x01) & CPUM.CombinedNIState; + } +*/ + + template + void RunInstruction(void); + + template + void MemWrite(uint32 addr, T val); + + template + T MemRead(uint32 addr); + + void IO(void); + + void BranchOccurred(unsigned iseq = ~0U); + + enum + { + GSREG_PCPBR, + GSREG_DBR, + GSREG_S, + GSREG_D, + GSREG_A, + GSREG_X, + GSREG_Y, + GSREG_P, + GSREG_E, + GSREG__BOUND + }; + + void SetRegister(const unsigned id, const uint32 value) MDFN_COLD; + uint32 GetRegister(const unsigned id, char* const special, const uint32 special_len) MDFN_COLD; + + //private: + + uint8 OpRead(uint32 addr); + + template void SetZN(const T arg); + template void Push(T arg); + template T Pull(void); + + enum + { + ISEQ_COP, + ISEQ_BRK, + ISEQ_ABORT, + ISEQ_NMI, + ISEQ_IRQ + }; + + void ISequence(unsigned which); + + template void Op_ADC(T arg); + template void Op_AND(T arg); + template void Op_BIT(T arg); + template void Op_Compare(T rv, T arg); + template void Op_CMP(T arg); + template void Op_CPX(T arg); + template void Op_CPY(T arg); + template void Op_EOR(T arg); + template void Op_LDA(T arg); + template void Op_LDX(T arg); + template void Op_LDY(T arg); + template void Op_ORA(T arg); + template void Op_SBC(T arg); + + template void Op_ASL(T& arg); + template void Op_DEC(T& arg); + template void Op_INC(T& arg); + template void Op_LSR(T& arg); + template void Op_ROL(T& arg); + template void Op_ROR(T& arg); + template void Op_TRB(T& arg); + template void Op_TSB(T& arg); + + template INLINE T Op_STA(void) { return C; } + template INLINE T Op_STX(void) { return X; } + template INLINE T Op_STY(void) { return Y; } + template INLINE T Op_STZ(void) { return 0; } + + uint32 GetEA_AB(void); + template uint32 GetEA_ABI(uint16 index); + template uint32 GetEA_ABX(void); + template uint32 GetEA_ABY(void); + uint32 GetEA_ABL(void); + uint32 GetEA_ABLX(void); + + uint16 GetEA_DP(void); + uint16 GetEA_DPI(uint16 index); + uint16 GetEA_DPX(void); + uint16 GetEA_DPY(void); + uint32 GetEA_IND(void); + uint32 GetEA_INDL(void); + uint32 GetEA_IX(void); + template uint32 GetEA_IY(void); + uint32 GetEA_ILY(void); + + uint16 GetEA_SR(void); + uint32 GetEA_SRIY(void); + + template void Instr_LD_IM(void (Core65816::*op)(T)); + template void Instr_LD(EAT (Core65816::*eafn)(void), void (Core65816::*op)(T)); + + template void Instr_RMW_A (void (Core65816::*op)(T&)); + template void Instr_RMW(EAT (Core65816::*eafn)(void), void (Core65816::*op)(T&)); + + template void Instr_ST(EAT (Core65816::*eafn)(void), T (Core65816::*op)(void)); + + void Instr_BRK(void); + void Instr_COP(void); + void Instr_NOP(void); + void Instr_STP(void); + void Instr_WAI(void); + void Instr_WDM(void); + + void Instr_Bxx(bool cond); + void Instr_BRL(void); + + void Instr_PEA(void); + void Instr_PEI(void); + void Instr_PER(void); + template void Instr_PHA(void); + void Instr_PHB(void); + void Instr_PHD(void); + void Instr_PHK(void); + void Instr_PHP(void); + template void Instr_PHX(void); + template void Instr_PHY(void); + + template void Instr_PLA(void); + void Instr_PLB(void); + void Instr_PLD(void); + void Instr_PLP(void); + template void Instr_PLX(void); + template void Instr_PLY(void); + + void Instr_REP(void); + void Instr_SEP(void); + + void Instr_JMP(void); + void Instr_JMP_I(void); + void Instr_JMP_II(void); + void Instr_JML(void); + void Instr_JML_I(void); + + void Instr_JSL(void); + void Instr_JSR(void); + void Instr_JSR_II(void); + + void Instr_RTI(void); + void Instr_RTL(void); + void Instr_RTS(void); + + template void Instr_INX(void); + template void Instr_INY(void); + + template void Instr_DEX(void); + template void Instr_DEY(void); + + template void Instr_TAX(void); + template void Instr_TAY(void); + void Instr_TCD(void); + void Instr_TCS(void); + void Instr_TDC(void); + void Instr_TSC(void); + template void Instr_TSX(void); + template void Instr_TXA(void); + void Instr_TXS(void); + template void Instr_TXY(void); + template void Instr_TYA(void); + template void Instr_TYX(void); + void Instr_XBA(void); + void Instr_XCE(void); + template void Instr_CLx(void); + template void Instr_SEx(void); + template void Instr_MVx(void); +}; + diff --git a/mednafen/snes_faust/Core65816.inc b/mednafen/snes_faust/Core65816.inc new file mode 100644 index 0000000..55f398c --- /dev/null +++ b/mednafen/snes_faust/Core65816.inc @@ -0,0 +1,1871 @@ +/******************************************************************************/ +/* Mednafen - Multi-system Emulator */ +/******************************************************************************/ +/* Core65816.inc - 65816 CPU Emulator Core +** Copyright (C) 2015-2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +Core65816::Core65816() +{ + PCPBRDummy = 0x00; +} + +Core65816::~Core65816() +{ + + +} + +// +// +// +template +INLINE void Core65816::SetZN(T arg) +{ + P &= ~(Z_FLAG | N_FLAG); + + if(!arg) + P |= Z_FLAG; + + P |= (arg >> ((sizeof(T) - 1) * 8)) & N_FLAG; +} + +template +INLINE void Core65816::Push(T arg) +{ + if(sizeof(T) == 2) + { + MemWrite(S, arg >> 8); + S--; + } + + MemWrite(S, arg); + S--; +} + +template +INLINE T Core65816::Pull(void) +{ + T ret = 0; + + S++; + ret |= MemRead(S); + + if(sizeof(T) == 2) + { + S++; + ret |= MemRead(S) << 8; + } + + return ret; +} + +// ABORT not fully implemented/tested. +INLINE void Core65816::ISequence(unsigned which) +{ + uint16 vecaddr; + + switch(which) + { + case ISEQ_COP: vecaddr = 0xFFE4; break; + case ISEQ_BRK: vecaddr = 0xFFE6; break; + case ISEQ_ABORT: vecaddr = 0xFFE8; break; + case ISEQ_NMI: vecaddr = 0xFFEA; break; + case ISEQ_IRQ: vecaddr = 0xFFEE; break; + } + + Push(PBR); + Push(PC); + Push(P); + + P = (P & ~D_FLAG) | I_FLAG; + PBR = 0x00; + PC = MemRead(vecaddr); + BranchOccurred(which); + + SNES_DBG("[CPU] ISeq %u: %04x\n", which, PC); +} + +// +// +// + +INLINE void Core65816::Instr_BRK(void) +{ + OpRead(PCPBR); + PC++; + OpRead(PCPBR); + + ISequence(ISEQ_BRK); + SampleIRQ(); +} + +INLINE void Core65816::Instr_COP(void) +{ + OpRead(PCPBR); + PC++; + OpRead(PCPBR); + + ISequence(ISEQ_COP); + SampleIRQ(); +} + +INLINE void Core65816::Instr_NOP(void) +{ + IO(); +} + +INLINE void Core65816::Instr_WDM(void) +{ + OpRead(PCPBR); + PC++; +} + +// +// +// +template +INLINE void Core65816::Op_ADC(T arg) +{ + T& AA = AC(); + uint32 tmp; + + if(P & D_FLAG) + { + uint32 a, b, c, d; + + a = (AA & 0x000F) + (arg & 0x000F) + (P & 1); + b = (AA & 0x00F0) + (arg & 0x00F0); + + P &= ~(C_FLAG | V_FLAG); + + if(sizeof(T) == 2) + { + c = (AA & 0x0F00) + (arg & 0x0F00); + d = (AA & 0xF000) + (arg & 0xF000); + + if(a > 0x0009) { b += 0x0010; a += 0x0006; } + if(b > 0x0090) { c += 0x0100; b += 0x0060; } + if(c > 0x0900) { d += 0x1000; c += 0x0600; } + P |= ((~(AA ^ arg) & (AA ^ d)) >> (sizeof(T) * 8 - 7)) & 0x40; // V flag + if(d > 0x9000) { P |= C_FLAG; d += 0x6000; } + + tmp = (a & 0x000F) | (b & 0x00F0) | (c & 0x0F00) | (d & 0xF000); + } + else + { + if(a > 0x0009) { b += 0x0010; a += 0x0006; } + P |= ((~(AA ^ arg) & (AA ^ b)) >> (sizeof(T) * 8 - 7)) & 0x40; // V flag + if(b > 0x0090) { P |= C_FLAG; b += 0x0060; } + + tmp = (a & 0x000F) | (b & 0x00F0); + } + } + else + { + tmp = AA + arg + (P & 1); + + P &= ~(C_FLAG | V_FLAG); + P |= (tmp >> (sizeof(T) * 8)) & 1; // C flag + P |= ((~(AA ^ arg) & (AA ^ tmp)) >> (sizeof(T) * 8 - 7)) & 0x40; // V flag + } + + AA = tmp; + SetZN(AA); +} + +template +INLINE void Core65816::Op_AND(T arg) +{ + T& AA = AC(); + + AA &= arg; + + SetZN(AA); +} + +template +INLINE void Core65816::Op_BIT(T arg) // N and V flags are not modified in the immediate addressing form of BIT. +{ + T& AA = AC(); + + P &= ~Z_FLAG; + + if(!(AA & arg)) + P |= Z_FLAG; + + if(!immediate) + { + P &= ~(N_FLAG | V_FLAG); + P |= (arg >> ((sizeof(T) - 1) * 8)) & (N_FLAG | V_FLAG); + } +} + +template +INLINE void Core65816::Op_Compare(T rv, T arg) +{ + uint32 tmp = rv - arg; + + SetZN(tmp); + + P &= ~C_FLAG; + P |= ((tmp >> (sizeof(T) * 8)) & 1) ^ 1; +} + +template +INLINE void Core65816::Op_CMP(T arg) +{ + Op_Compare(C, arg); +} + +template +INLINE void Core65816::Op_CPX(T arg) +{ + Op_Compare(X, arg); +} + +template +INLINE void Core65816::Op_CPY(T arg) +{ + Op_Compare(Y, arg); +} + +template +INLINE void Core65816::Op_EOR(T arg) +{ + T& AA = AC(); + + AA ^= arg; + + SetZN(AA); +} + +template +INLINE void Core65816::Op_LDA(T arg) +{ + T& AA = AC(); + + AA = arg; + + SetZN(AA); +} + +template +INLINE void Core65816::Op_LDX(T arg) +{ + X = arg; + + SetZN(X); +} + +template +INLINE void Core65816::Op_LDY(T arg) +{ + Y = arg; + + SetZN(Y); +} + +template +INLINE void Core65816::Op_ORA(T arg) +{ + T& AA = AC(); + + AA |= arg; + + SetZN(AA); +} + +template +INLINE void Core65816::Op_SBC(T arg) +{ + T& AA = AC(); + uint32 tmp; + + arg = ~arg; + + if(P & D_FLAG) + { + uint32 a, b, c, d; + + a = (AA & 0x000F) + (arg & 0x000F) + (P & 1); + b = (AA & 0x00F0) + (arg & 0x00F0) + (a & 0x0010); + + P &= ~(C_FLAG | V_FLAG); + + if(sizeof(T) == 2) + { + c = (AA & 0x0F00) + (arg & 0x0F00) + (b & 0x0100); + d = (AA & 0xF000) + (arg & 0xF000) + (c & 0x1000); + + P |= ((d >> (sizeof(T) * 8)) & 1); // C flag + + if(a < 0x00010) { a -= 0x0006; } + if(b < 0x00100) { b -= 0x0060; } + if(c < 0x01000) { c -= 0x0600; } + P |= ((~(AA ^ arg) & (AA ^ d)) >> (sizeof(T) * 8 - 7)) & 0x40; // V flag + if(d < 0x10000) { d -= 0x6000; } + + tmp = (a & 0x000F) | (b & 0x00F0) | (c & 0x0F00) | (d & 0xF000); + } + else + { + P |= ((b >> (sizeof(T) * 8)) & 1); // C flag + + if(a < 0x0010) { a -= 0x0006; } + P |= ((~(AA ^ arg) & (AA ^ b)) >> (sizeof(T) * 8 - 7)) & 0x40; // V flag + if(b < 0x0100) { b -= 0x0060; } + + tmp = (a & 0x000F) | (b & 0x00F0); + } + } + else + { + tmp = AA + arg + (P & 1); + + P &= ~(C_FLAG | V_FLAG); + P |= ((tmp >> (sizeof(T) * 8)) & 1); // C flag + P |= ((~(AA ^ arg) & (AA ^ tmp)) >> (sizeof(T) * 8 - 7)) & 0x40; // V flag + } + + AA = tmp; + SetZN(AA); +} + + +// +// +// +template +INLINE void Core65816::Op_ASL(T& arg) +{ + P &= ~C_FLAG; + P |= arg >> (8 * sizeof(T) - 1); + + arg <<= 1; + + SetZN(arg); +} + +template +INLINE void Core65816::Op_DEC(T& arg) +{ + arg--; + + SetZN(arg); +} + +template +INLINE void Core65816::Op_INC(T& arg) +{ + arg++; + + SetZN(arg); +} + +template +INLINE void Core65816::Op_LSR(T& arg) +{ + P &= ~C_FLAG; + P |= arg & 1; + + arg >>= 1; + + SetZN(arg); +} + +template +INLINE void Core65816::Op_ROL(T& arg) +{ + const bool new_CF = arg >> (sizeof(T) * 8 - 1); + + arg <<= 1; + + arg |= (P & 1); + P &= ~C_FLAG; + P |= new_CF; + + SetZN(arg); +} + +template +INLINE void Core65816::Op_ROR(T& arg) +{ + const bool new_CF = arg & 1; + + arg >>= 1; + + arg |= (P & 1) << (sizeof(T) * 8 - 1); + P &= ~C_FLAG; + P |= new_CF; + + SetZN(arg); +} + +template +INLINE void Core65816::Op_TRB(T& arg) +{ + T& AA = AC(); + + P &= ~Z_FLAG; + if(!(arg & AA)) + P |= Z_FLAG; + + arg &= ~AA; +} + +template +INLINE void Core65816::Op_TSB(T& arg) +{ + T& AA = AC(); + + P &= ~Z_FLAG; + if(!(arg & AA)) + P |= Z_FLAG; + + arg |= AA; +} + +// +// +// +// NOTE: Since we're hardcoding in DBR in GetEA_AB(), don't use it +// to implement JSR/JMP/whatever(at least not without modification). +INLINE uint32 Core65816::GetEA_AB(void) +{ + uint32 ea = DBRSL16; + + ea |= OpRead(PCPBR); + PC++; + + ea |= OpRead(PCPBR) << 8; + PC++; + + return ea; +} + +template +INLINE uint32 Core65816::GetEA_ABI(uint16 index) +{ + uint32 ea; + + ea = GetEA_AB(); + + if(UncondEC || (((ea + index) ^ ea) & 0x100)) + IO(); + + ea = (ea + index) & 0xFFFFFF; + + return ea; +} + +template +INLINE uint32 Core65816::GetEA_ABX(void) +{ + return GetEA_ABI(X); +} + +template +INLINE uint32 Core65816::GetEA_ABY(void) +{ + return GetEA_ABI(Y); +} + +INLINE uint32 Core65816::GetEA_ABL(void) +{ + uint32 ea; + + ea = OpRead(PCPBR); + PC++; + + ea |= OpRead(PCPBR) << 8; + PC++; + + ea |= OpRead(PCPBR) << 16; + PC++; + + return ea; +} + +INLINE uint32 Core65816::GetEA_ABLX(void) +{ + uint32 ea; + + ea = GetEA_ABL(); + ea = (ea + X) & 0xFFFFFF; + + return ea; +} + +INLINE uint16 Core65816::GetEA_DP(void) // d +{ + uint16 ea; + + ea = OpRead(PCPBR); + PC++; + + if(D & 0xFF) + IO(); + + ea = (ea + D); + + return ea; +} + +INLINE uint16 Core65816::GetEA_DPI(uint16 index) +{ + uint16 ea; + + ea = GetEA_DP(); + + IO(); + ea = (ea + index); + + return ea; +} + +INLINE uint16 Core65816::GetEA_DPX(void) // d, X +{ + return GetEA_DPI(X); +} + +INLINE uint16 Core65816::GetEA_DPY(void) // d, Y +{ + return GetEA_DPI(Y); +} + +INLINE uint32 Core65816::GetEA_IND(void) // (d) +{ + uint16 eadp; + uint32 ea = DBRSL16; + + eadp = GetEA_DP(); + + ea |= MemRead(eadp); + eadp++; + + ea |= MemRead(eadp) << 8; + + return ea; +} + +INLINE uint32 Core65816::GetEA_INDL(void) // [d] +{ + uint16 eadp; + uint32 ea; + + eadp = GetEA_DP(); + + ea = MemRead(eadp); + eadp++; + + ea |= MemRead(eadp) << 8; + eadp++; + + ea |= MemRead(eadp) << 16; + + return ea; +} + +INLINE uint32 Core65816::GetEA_IX(void) // (d, X) +{ + uint16 eadp; + uint32 ea = DBRSL16; + + eadp = GetEA_DPX(); + + ea |= MemRead(eadp); + eadp++; + + ea |= MemRead(eadp) << 8; + + return ea; +} + +template +INLINE uint32 Core65816::GetEA_IY(void) // (d), Y +{ + uint32 ea; + + ea = GetEA_IND(); + + if(UncondEC || (((ea + Y) ^ ea) & 0x100)) + IO(); + + ea = (ea + Y) & 0xFFFFFF; + + return ea; +} + +INLINE uint32 Core65816::GetEA_ILY(void) // [d], Y +{ + uint32 ea; + + ea = GetEA_INDL(); + + ea = (ea + Y) & 0xFFFFFF; + + return ea; +} + +INLINE uint16 Core65816::GetEA_SR(void) +{ + uint16 ea; + + ea = OpRead(PCPBR); + PC++; + + IO(); + ea = (ea + S); + + return ea; +} + +INLINE uint32 Core65816::GetEA_SRIY(void) // (whatever, S), Y +{ + uint16 easp; + uint32 ea = DBRSL16; + + easp = GetEA_SR(); + + ea |= MemRead(easp); + easp++; + + ea |= MemRead(easp) << 8; + + IO(); + ea = (ea + Y) & 0xFFFFFF; + + return ea; +} + +// +// +// +template +INLINE void Core65816::Instr_LD_IM(void (Core65816::*op)(T)) +{ + T tmp; + + tmp = OpRead(PCPBR); + PC++; + + if(sizeof(T) == 2) + { + tmp |= OpRead(PCPBR) << 8; + PC++; + } + + (this->*op)(tmp); +} + +template +INLINE void Core65816::Instr_LD(EAT (Core65816::*eafn)(void), void (Core65816::*op)(T)) +{ + EAT ea = (this->*eafn)(); + T tmp = MemRead(ea); + + (this->*op)(tmp); +} + +template +INLINE void Core65816::Instr_RMW_A(void (Core65816::*op)(T&)) +{ + IO(); + (this->*op)(AC()); +} + +template +INLINE void Core65816::Instr_RMW(EAT (Core65816::*eafn)(void), void (Core65816::*op)(T&)) +{ + // For 16-bit: L, H, H, L + EAT ea = (this->*eafn)(); + T tmp = MemRead(ea); + + IO(); + (this->*op)(tmp); + + if(sizeof(T) == 2) + MemWrite(ea + 1, tmp >> 8); + + MemWrite(ea, tmp); +} + +template +INLINE void Core65816::Instr_ST(EAT (Core65816::*eafn)(void), T (Core65816::*op)(void)) +{ + EAT ea = (this->*eafn)(); + T tmp = (this->*op)(); + + MemWrite(ea, tmp); +} + +// +// +// + +// +// +// + +INLINE void Core65816::Instr_Bxx(bool cond) +{ + int8 disp; + + disp = OpRead(PCPBR); + PC++; + + if(cond) + { + IO(); + PC += disp; + BranchOccurred(); + } +} + +INLINE void Core65816::Instr_BRL(void) +{ + uint16 disp; + + disp = OpRead(PCPBR); + PC++; + + disp |= OpRead(PCPBR) << 8; + PC++; + + IO(); + PC += disp; + BranchOccurred(); +} + +INLINE void Core65816::Instr_JML(void) +{ + uint16 npc; + + npc = OpRead(PCPBR); + PC++; + + npc |= OpRead(PCPBR) << 8; + PC++; + + PBR = OpRead(PCPBR); + + PC = npc; + BranchOccurred(); +} + +INLINE void Core65816::Instr_JML_I(void) +{ + uint32 ea = 0; // Bank 0, not DBR! + + ea |= OpRead(PCPBR); + PC++; + + ea |= OpRead(PCPBR) << 8; + + PC = MemRead(ea); + PBR = MemRead((ea + 2) & 0xFFFFFF); + BranchOccurred(); +} + +INLINE void Core65816::Instr_JMP(void) +{ + uint16 npc; + + npc = OpRead(PCPBR); + PC++; + + npc |= OpRead(PCPBR) << 8; + + PC = npc; + BranchOccurred(); +} + +INLINE void Core65816::Instr_JMP_I(void) +{ + uint32 ea = 0; // Bank 0, not DBR! + + ea |= OpRead(PCPBR); + PC++; + + ea |= OpRead(PCPBR) << 8; + + PC = MemRead(ea); + BranchOccurred(); +} + +// +// PBR not DBR, and wrap within bank for both + X and reading high byte of PC. +// +INLINE void Core65816::Instr_JMP_II(void) +{ + uint16 ea; + + ea = OpRead(PCPBR); + PC++; + + ea |= OpRead(PCPBR) << 8; + IO(); + ea += X; + + PC = MemRead((PBR << 16) | ea); + ea++; + PC |= MemRead((PBR << 16) | ea) << 8; + BranchOccurred(); +} + +INLINE void Core65816::Instr_JSL(void) +{ + uint16 npc; + + npc = OpRead(PCPBR); + PC++; + npc |= OpRead(PCPBR) << 8; + PC++; + + Push(PBR); + + IO(); + + PBR = OpRead(PCPBR); + + Push(PC); + + PC = npc; + BranchOccurred(); +} + +INLINE void Core65816::Instr_JSR(void) // Different memory access order from 6502... +{ + uint16 npc; + + npc = OpRead(PCPBR); + PC++; + npc |= OpRead(PCPBR) << 8; + + IO(); + + Push(PC); + PC = npc; + BranchOccurred(); +} + +// +// PBR not DBR, and wrap within bank for both + X and reading high byte of PC. +// +INLINE void Core65816::Instr_JSR_II(void) +{ + uint16 ea; + + ea = OpRead(PCPBR); + PC++; + + Push(PC); + + ea |= OpRead(PCPBR) << 8; + IO(); + ea += X; + + PC = MemRead((PBR << 16) | ea); + ea++; + PC |= MemRead((PBR << 16) | ea) << 8; +} + + +INLINE void Core65816::Instr_RTI(void) +{ + IO(); + IO(); + + P = Pull(); + PC = Pull(); + // TODO: SampleIRQ(); + PBR = Pull(); + BranchOccurred(); + + if(P & X_FLAG) + { + X = (uint8)X; + Y = (uint8)Y; + } + + SampleIRQ(); +} + +INLINE void Core65816::Instr_RTL(void) +{ + IO(); + IO(); + + PC = Pull() + 1; + PBR = Pull(); + BranchOccurred(); +} + +INLINE void Core65816::Instr_RTS(void) +{ + IO(); + IO(); + + PC = Pull() + 1; + BranchOccurred(); + + IO(); +} + +// +// +// + +template +INLINE void Core65816::Instr_INX(void) +{ + IO(); + X = (T)(X + 1); + SetZN(X); +} + +template +INLINE void Core65816::Instr_INY(void) +{ + IO(); + Y = (T)(Y + 1); + SetZN(Y); +} + +template +INLINE void Core65816::Instr_DEX(void) +{ + IO(); + X = (T)(X - 1); + SetZN(X); +} + +template +INLINE void Core65816::Instr_DEY(void) +{ + IO(); + Y = (T)(Y - 1); + SetZN(Y); +} + +// +// +// + +template +INLINE void Core65816::Instr_TAX(void) +{ + IO(); + + X = (T)C; + + SetZN(X); +} + +template +INLINE void Core65816::Instr_TAY(void) +{ + IO(); + + Y = (T)C; + + SetZN(Y); +} + +INLINE void Core65816::Instr_TCD(void) +{ + IO(); + + D = C; + + SetZN(D); +} + +INLINE void Core65816::Instr_TCS(void) +{ + IO(); + if(MDFN_UNLIKELY(E)) + S = 0x100 | (uint8)C; + else + S = C; +} + +INLINE void Core65816::Instr_TDC(void) +{ + IO(); + C = D; + + SetZN(C); +} + +INLINE void Core65816::Instr_TSC(void) +{ + IO(); + C = S; + + SetZN(C); +} + +template +INLINE void Core65816::Instr_TSX(void) +{ + IO(); + X = (T)S; + + SetZN(X); +} + +template +INLINE void Core65816::Instr_TXA(void) +{ + IO(); + AC() = X; + + SetZN(C); +} + +INLINE void Core65816::Instr_TXS(void) +{ + IO(); + if(MDFN_UNLIKELY(E)) // SNES "Metal Marines" definitely needs this. + S = 0x100 | (uint8)X; + else + S = X; +} + +template +INLINE void Core65816::Instr_TXY(void) +{ + IO(); + Y = X; + + SetZN(Y); +} + +template +INLINE void Core65816::Instr_TYA(void) +{ + IO(); + AC() = Y; + + SetZN(C); +} + +template +INLINE void Core65816::Instr_TYX(void) +{ + IO(); + X = Y; + + SetZN(X); +} + +INLINE void Core65816::Instr_XBA(void) +{ + uint8 tmp = B; + + IO(); + IO(); + + B = A; + A = tmp; + + SetZN(A); +} + +INLINE void Core65816::Instr_XCE(void) +{ + bool new_E = P & C_FLAG; + + P &= ~C_FLAG; + P |= E; + + E = new_E; + + IO(); + SNES_DBG("[CPU] XCE: %u\n", E); +} + +// +// +// + +template +INLINE void Core65816::Instr_CLx(void) +{ + IO(); + P &= ~TA_Mask; +} + +template +INLINE void Core65816::Instr_SEx(void) +{ + IO(); + P |= TA_Mask; +} + +// +// +// + +template +INLINE void Core65816::Instr_MVx(void) +{ + // opcode, dstbank, srcbank + // + // dstbank is loaded into DBR. + // + // source addr: srcbank, X reg + // dest addr, dstbank, Y reg + // + // Respects X flag, seems to ignore M flag. + uint8 SB; + uint8 tmp; + + DBRSL16 = OpRead(PCPBR) << 16; + PC++; + + SB = OpRead(PCPBR); + PC++; + + // + // + tmp = MemRead((SB << 16) | X); + MemWrite((DBRSL16) | Y, tmp); + // + // + + X = (X_type)(X + increment); + Y = (X_type)(Y + increment); + + IO(); + IO(); + + C--; + if(C != 0xFFFF) + PC -= 3; +} + +INLINE void Core65816::Instr_PEA(void) // Push Effective Absolute Address +{ + uint16 ea = GetEA_AB(); + + Push(ea); +} + +INLINE void Core65816::Instr_PEI(void) // Push Effective Indirect Address +{ + uint16 ea = GetEA_IND(); + + Push(ea); +} + +INLINE void Core65816::Instr_PER(void) // Push Effective PC Relative Address +{ + uint16 ea = GetEA_AB(); + + IO(); + ea += PC; + + Push(ea); +} + +template +INLINE void Core65816::Instr_PHA(void) +{ + IO(); + Push(AC()); +} + +INLINE void Core65816::Instr_PHB(void) +{ + IO(); + Push(DBRSL16 >> 16); +} + +INLINE void Core65816::Instr_PHD(void) +{ + IO(); + Push(D); +} + +INLINE void Core65816::Instr_PHK(void) +{ + IO(); + Push(PBR); +} + +INLINE void Core65816::Instr_PHP(void) +{ + IO(); + Push(P); +} + +template +INLINE void Core65816::Instr_PHX(void) +{ + IO(); + Push(X); +} + +template +INLINE void Core65816::Instr_PHY(void) +{ + IO(); + Push(Y); +} + +template +INLINE void Core65816::Instr_PLA(void) +{ + IO(); + IO(); + + AC() = Pull(); + SetZN(AC()); +} + +INLINE void Core65816::Instr_PLB(void) +{ + IO(); + IO(); + + uint8 tmp = Pull(); + + SetZN(tmp); + DBRSL16 = tmp << 16; +} + +INLINE void Core65816::Instr_PLD(void) +{ + IO(); + IO(); + + D = Pull(); + SetZN(D); +} + +INLINE void Core65816::Instr_PLP(void) +{ + IO(); + IO(); + + P = Pull(); + + if(P & X_FLAG) + { + X = (uint8)X; + Y = (uint8)Y; + } +} + +template +INLINE void Core65816::Instr_PLX(void) +{ + IO(); + IO(); + + X = Pull(); + SetZN(X); +} + +template +INLINE void Core65816::Instr_PLY(void) +{ + IO(); + IO(); + + Y = Pull(); + SetZN(Y); +} + +INLINE void Core65816::Instr_REP(void) +{ + uint8 tmp; + + tmp = OpRead(PCPBR); + PC++; + + IO(); + P &= ~tmp; +} + +INLINE void Core65816::Instr_SEP(void) +{ + uint8 tmp; + + tmp = OpRead(PCPBR); + PC++; + + IO(); + P |= tmp; + + if(P & X_FLAG) + { + X = (uint8)X; + Y = (uint8)Y; + } +} + + +template +INLINE void Core65816::RunInstruction(void) +{ + switch(opcode) + { + case 0x00: Instr_BRK(); break; // BRK + case 0x02: Instr_COP(); break; // COP + case 0xEA: Instr_NOP(); break; // NOP + case 0xDB: Instr_STP(); break; // STP + case 0xCB: Instr_WAI(); break; // WAI + case 0x42: Instr_WDM(); break; // WDM (effectively 2-byte NOP). + + // + // Block transfer + // + case 0x44: Instr_MVx(); break; // MVP + case 0x54: Instr_MVx(); break; // MVN + + // + // Stack pushing... + // + case 0xF4: Instr_PEA(); break; // PEA + case 0xD4: Instr_PEI(); break; // PEI + case 0x62: Instr_PER(); break; // PER + case 0x48: Instr_PHA(); break; // PHA + case 0x8B: Instr_PHB(); break; // PHB + case 0x0B: Instr_PHD(); break; // PHD + case 0x4B: Instr_PHK(); break; // PHK + case 0x08: Instr_PHP(); break; // PHP + case 0xDA: Instr_PHX(); break; // PHX + case 0x5A: Instr_PHY(); break; // PHY + + // + // ...and pulling. + // + case 0x68: Instr_PLA(); break; // PLA + case 0xAB: Instr_PLB(); break; // PLB + case 0x2B: Instr_PLD(); break; // PLD + case 0x28: Instr_PLP(); break; // PLP + case 0xFA: Instr_PLX(); break; // PLX + case 0x7A: Instr_PLY(); break; // PLY + + case 0x4C: Instr_JMP(); break; // JMP $addr + case 0x6C: Instr_JMP_I(); break; // JMP ($addr) + case 0x7C: Instr_JMP_II(); break; // JMP ($addr, X) + case 0x5C: Instr_JML(); break; // JMP long(aka JML). + case 0xDC: Instr_JML_I(); break; // JMP [long] (aka JML) + + case 0x22: Instr_JSL(); break; // JSR long(aka JSL) + case 0x20: Instr_JSR(); break; // JSR $addr + case 0xFC: Instr_JSR_II(); break; // JSR ($addr, X) + + case 0x40: Instr_RTI(); break; // RTI + case 0x6B: Instr_RTL(); break; // RTL + case 0x60: Instr_RTS(); break; // RTS + + #define INSTR(J, K, L) Instr_##J(&Core65816::GetEA_##K, &Core65816::Op_##L) + // + // ADC + // + case 0x69: Instr_LD_IM (&Core65816::Op_ADC); break; + case 0x65: INSTR(LD, DP, ADC); break; + case 0x75: INSTR(LD, DPX, ADC); break; + case 0x6D: INSTR(LD, AB, ADC); break; + case 0x6F: INSTR(LD, ABL, ADC); break; + case 0x7D: INSTR(LD, ABX, ADC); break; + case 0x7F: INSTR(LD, ABLX, ADC); break; + case 0x79: INSTR(LD, ABY, ADC); break; + case 0x72: INSTR(LD, IND, ADC); break; + case 0x67: INSTR(LD, INDL, ADC); break; + case 0x61: INSTR(LD, IX, ADC); break; + case 0x71: INSTR(LD, IY, ADC); break; + case 0x77: INSTR(LD, ILY, ADC); break; + case 0x63: INSTR(LD, SR, ADC); break; + case 0x73: INSTR(LD, SRIY, ADC); break; + + // + // AND + // + case 0x29: Instr_LD_IM (&Core65816::Op_AND); break; + case 0x25: INSTR(LD, DP, AND); break; + case 0x35: INSTR(LD, DPX, AND); break; + case 0x2D: INSTR(LD, AB, AND); break; + case 0x2F: INSTR(LD, ABL, AND); break; + case 0x3D: INSTR(LD, ABX, AND); break; + case 0x3F: INSTR(LD, ABLX, AND); break; + case 0x39: INSTR(LD, ABY, AND); break; + case 0x32: INSTR(LD, IND, AND); break; + case 0x27: INSTR(LD, INDL, AND); break; + case 0x21: INSTR(LD, IX, AND); break; + case 0x31: INSTR(LD, IY, AND); break; + case 0x37: INSTR(LD, ILY, AND); break; + case 0x23: INSTR(LD, SR, AND); break; + case 0x33: INSTR(LD, SRIY, AND); break; + + // + // CMP + // + case 0xC9: Instr_LD_IM (&Core65816::Op_CMP); break; + case 0xC5: INSTR(LD, DP, CMP); break; + case 0xD5: INSTR(LD, DPX, CMP); break; + case 0xCD: INSTR(LD, AB, CMP); break; + case 0xCF: INSTR(LD, ABL, CMP); break; + case 0xDD: INSTR(LD, ABX, CMP); break; + case 0xDF: INSTR(LD, ABLX, CMP); break; + case 0xD9: INSTR(LD, ABY, CMP); break; + case 0xD2: INSTR(LD, IND, CMP); break; + case 0xC7: INSTR(LD, INDL, CMP); break; + case 0xC1: INSTR(LD, IX, CMP); break; + case 0xD1: INSTR(LD, IY, CMP); break; + case 0xD7: INSTR(LD, ILY, CMP); break; + case 0xC3: INSTR(LD, SR, CMP); break; + case 0xD3: INSTR(LD, SRIY, CMP); break; + + // + // EOR + // + case 0x49: Instr_LD_IM (&Core65816::Op_EOR); break; + case 0x45: INSTR(LD, DP, EOR); break; + case 0x55: INSTR(LD, DPX, EOR); break; + case 0x4D: INSTR(LD, AB, EOR); break; + case 0x4F: INSTR(LD, ABL, EOR); break; + case 0x5D: INSTR(LD, ABX, EOR); break; + case 0x5F: INSTR(LD, ABLX, EOR); break; + case 0x59: INSTR(LD, ABY, EOR); break; + case 0x52: INSTR(LD, IND, EOR); break; + case 0x47: INSTR(LD, INDL, EOR); break; + case 0x41: INSTR(LD, IX, EOR); break; + case 0x51: INSTR(LD, IY, EOR); break; + case 0x57: INSTR(LD, ILY, EOR); break; + case 0x43: INSTR(LD, SR, EOR); break; + case 0x53: INSTR(LD, SRIY, EOR); break; + + // + // LDA + // + case 0xA9: Instr_LD_IM (&Core65816::Op_LDA); break; + case 0xA5: INSTR(LD, DP, LDA); break; + case 0xB5: INSTR(LD, DPX, LDA); break; + case 0xAD: INSTR(LD, AB, LDA); break; + case 0xAF: INSTR(LD, ABL, LDA); break; + case 0xBD: INSTR(LD, ABX, LDA); break; + case 0xBF: INSTR(LD, ABLX, LDA); break; + case 0xB9: INSTR(LD, ABY, LDA); break; + case 0xB2: INSTR(LD, IND, LDA); break; + case 0xA7: INSTR(LD, INDL, LDA); break; + case 0xA1: INSTR(LD, IX, LDA); break; + case 0xB1: INSTR(LD, IY, LDA); break; + case 0xB7: INSTR(LD, ILY, LDA); break; + case 0xA3: INSTR(LD, SR, LDA); break; + case 0xB3: INSTR(LD, SRIY, LDA); break; + + // + // ORA + // + case 0x09: Instr_LD_IM (&Core65816::Op_ORA); break; + case 0x05: INSTR(LD, DP, ORA); break; + case 0x15: INSTR(LD, DPX, ORA); break; + case 0x0D: INSTR(LD, AB, ORA); break; + case 0x0F: INSTR(LD, ABL, ORA); break; + case 0x1D: INSTR(LD, ABX, ORA); break; + case 0x1F: INSTR(LD, ABLX, ORA); break; + case 0x19: INSTR(LD, ABY, ORA); break; + case 0x12: INSTR(LD, IND, ORA); break; + case 0x07: INSTR(LD, INDL, ORA); break; + case 0x01: INSTR(LD, IX, ORA); break; + case 0x11: INSTR(LD, IY, ORA); break; + case 0x17: INSTR(LD, ILY, ORA); break; + case 0x03: INSTR(LD, SR, ORA); break; + case 0x13: INSTR(LD, SRIY, ORA); break; + + // + // SBC + // + case 0xE9: Instr_LD_IM (&Core65816::Op_SBC); break; + case 0xE5: INSTR(LD, DP, SBC); break; + case 0xF5: INSTR(LD, DPX, SBC); break; + case 0xED: INSTR(LD, AB, SBC); break; + case 0xEF: INSTR(LD, ABL, SBC); break; + case 0xFD: INSTR(LD, ABX, SBC); break; + case 0xFF: INSTR(LD, ABLX, SBC); break; + case 0xF9: INSTR(LD, ABY, SBC); break; + case 0xF2: INSTR(LD, IND, SBC); break; + case 0xE7: INSTR(LD, INDL, SBC); break; + case 0xE1: INSTR(LD, IX, SBC); break; + case 0xF1: INSTR(LD, IY, SBC); break; + case 0xF7: INSTR(LD, ILY, SBC); break; + case 0xE3: INSTR(LD, SR, SBC); break; + case 0xF3: INSTR(LD, SRIY, SBC); break; + + // + // STA + // + case 0x85: INSTR(ST, DP, STA); break; + case 0x95: INSTR(ST, DPX, STA); break; + case 0x8D: INSTR(ST, AB, STA); break; + case 0x8F: INSTR(ST, ABL, STA); break; + case 0x9D: INSTR(ST, ABX, STA); break; + case 0x9F: INSTR(ST, ABLX, STA); break; + case 0x99: INSTR(ST, ABY, STA); break; + case 0x92: INSTR(ST, IND, STA); break; + case 0x87: INSTR(ST, INDL, STA); break; + case 0x81: INSTR(ST, IX, STA); break; + case 0x91: INSTR(ST, IY, STA); break; + case 0x97: INSTR(ST, ILY, STA); break; + case 0x83: INSTR(ST, SR, STA); break; + case 0x93: INSTR(ST, SRIY, STA); break; + + // + // BIT + // + case 0x89: Instr_LD_IM(&Core65816::Op_BIT); break; + case 0x24: INSTR(LD, DP, BIT); break; + case 0x34: INSTR(LD, DPX, BIT); break; + case 0x2C: INSTR(LD, AB, BIT); break; + case 0x3C: INSTR(LD, ABX, BIT); break; + + // + // CPX + // + case 0xE0: Instr_LD_IM (&Core65816::Op_CPX); break; + case 0xE4: INSTR(LD, DP, CPX); break; + case 0xEC: INSTR(LD, AB, CPX); break; + + // + // CPY + // + case 0xC0: Instr_LD_IM (&Core65816::Op_CPY); break; + case 0xC4: INSTR(LD, DP, CPY); break; + case 0xCC: INSTR(LD, AB, CPY); break; + + // + // LDX + // + case 0xA2: Instr_LD_IM (&Core65816::Op_LDX); break; + case 0xA6: INSTR(LD, DP, LDX); break; + case 0xB6: INSTR(LD, DPY, LDX); break; + case 0xAE: INSTR(LD, AB, LDX); break; + case 0xBE: INSTR(LD, ABY, LDX); break; + + // + // LDY + // + case 0xA0: Instr_LD_IM (&Core65816::Op_LDY); break; + case 0xA4: INSTR(LD, DP, LDY); break; + case 0xB4: INSTR(LD, DPX, LDY); break; + case 0xAC: INSTR(LD, AB, LDY); break; + case 0xBC: INSTR(LD, ABX, LDY); break; + + // + // STX + // + case 0x86: INSTR(ST, DP, STX); break; + case 0x96: INSTR(ST, DPY, STX); break; + case 0x8E: INSTR(ST, AB, STX); break; + + // + // STY + // + case 0x84: INSTR(ST, DP, STY); break; + case 0x94: INSTR(ST, DPX, STY); break; + case 0x8C: INSTR(ST, AB, STY); break; + + // + // STZ + // + case 0x64: INSTR(ST, DP, STZ); break; + case 0x74: INSTR(ST, DPX, STZ); break; + case 0x9C: INSTR(ST, AB, STZ); break; + case 0x9E: INSTR(ST, ABX, STZ); break; + + // + // + // ASL + // + case 0x0A: Instr_RMW_A(&Core65816::Op_ASL); break; + case 0x06: INSTR(RMW, DP, ASL); break; + case 0x16: INSTR(RMW, DPX, ASL); break; + case 0x0E: INSTR(RMW, AB, ASL); break; + case 0x1E: INSTR(RMW, ABX, ASL); break; + + // + // DEC + // + case 0x3A: Instr_RMW_A(&Core65816::Op_DEC); break; + case 0xC6: INSTR(RMW, DP, DEC); break; + case 0xD6: INSTR(RMW, DPX, DEC); break; + case 0xCE: INSTR(RMW, AB, DEC); break; + case 0xDE: INSTR(RMW, ABX, DEC); break; + + // + // INC + // + case 0x1A: Instr_RMW_A(&Core65816::Op_INC); break; + case 0xE6: INSTR(RMW, DP, INC); break; + case 0xF6: INSTR(RMW, DPX, INC); break; + case 0xEE: INSTR(RMW, AB, INC); break; + case 0xFE: INSTR(RMW, ABX, INC); break; + + // + // LSR + // + case 0x4A: Instr_RMW_A(&Core65816::Op_LSR); break; + case 0x46: INSTR(RMW, DP, LSR); break; + case 0x56: INSTR(RMW, DPX, LSR); break; + case 0x4E: INSTR(RMW, AB, LSR); break; + case 0x5E: INSTR(RMW, ABX, LSR); break; + + // + // ROL + // + case 0x2A: Instr_RMW_A(&Core65816::Op_ROL); break; + case 0x26: INSTR(RMW, DP, ROL); break; + case 0x36: INSTR(RMW, DPX, ROL); break; + case 0x2E: INSTR(RMW, AB, ROL); break; + case 0x3E: INSTR(RMW, ABX, ROL); break; + + // + // ROR + // + case 0x6A: Instr_RMW_A(&Core65816::Op_ROR); break; + case 0x66: INSTR(RMW, DP, ROR); break; + case 0x76: INSTR(RMW, DPX, ROR); break; + case 0x6E: INSTR(RMW, AB, ROR); break; + case 0x7E: INSTR(RMW, ABX, ROR); break; + + // + // TRB + // + case 0x14: INSTR(RMW, DP, TRB); break; + case 0x1C: INSTR(RMW, AB, TRB); break; + + // + // TSB + // + case 0x04: INSTR(RMW, DP, TSB); break; + case 0x0C: INSTR(RMW, AB, TSB); break; + + #undef INSTR + + case 0xE8: Instr_INX(); break; + case 0xC8: Instr_INY(); break; + + case 0xCA: Instr_DEX(); break; + case 0x88: Instr_DEY(); break; + + // + // Branch Instructions + // + case 0x90: Instr_Bxx(!(P & C_FLAG)); break; // BCC + case 0xB0: Instr_Bxx( (P & C_FLAG)); break; // BCS + case 0xF0: Instr_Bxx( (P & Z_FLAG)); break; // BEQ + case 0x30: Instr_Bxx( (P & N_FLAG)); break; // BMI + case 0xD0: Instr_Bxx(!(P & Z_FLAG)); break; // BNE + case 0x10: Instr_Bxx(!(P & N_FLAG)); break; // BPL + case 0x80: Instr_Bxx( true ); break; // BRA + case 0x50: Instr_Bxx(!(P & V_FLAG)); break; // BVC + case 0x70: Instr_Bxx( (P & V_FLAG)); break; // BVS + case 0x82: Instr_BRL(); break; // BRL + + // + // Exchange/Transfer instructions + // + case 0xAA: Instr_TAX(); break; // TAX + case 0xA8: Instr_TAY(); break; // TAY + case 0x5B: Instr_TCD(); break; // TCD + case 0x1B: Instr_TCS(); break; // TCS + case 0x7B: Instr_TDC(); break; // TDC + case 0x3B: Instr_TSC(); break; // TSC + case 0xBA: Instr_TSX(); break; // TSX + case 0x8A: Instr_TXA(); break; // TXA + case 0x9A: Instr_TXS(); break; // TXS + case 0x9B: Instr_TXY(); break; // TXY + case 0x98: Instr_TYA(); break; // TYA + case 0xBB: Instr_TYX(); break; // TYX + case 0xEB: Instr_XBA(); break; // XBA + case 0xFB: Instr_XCE(); break; // XCE + + // + // Simple flag setting and clearing instructions. + // + case 0x18: Instr_CLx(); break; // CLC + case 0xD8: Instr_CLx(); break; // CLD + case 0x58: Instr_CLx(); break; // CLI + case 0xB8: Instr_CLx(); break; // CLV + + case 0x38: Instr_SEx(); break; // SEC + case 0xF8: Instr_SEx(); break; // SED + case 0x78: Instr_SEx(); break; // SEI + + case 0xC2: Instr_REP(); break; // REP (Reset Status Bits) + case 0xE2: Instr_SEP(); break; // SEP (Set Processor Status Bits) + } +} + +void Core65816::Power(void) +{ + E = true; + D = 0; + DBRSL16 = 0; + PC = 0; + PBR = 0; + S = 0; + P = 0; + X = 0; + Y = 0; + C = 0; +} + +void Core65816::Reset(void) +{ + E = true; // Oh Tetris Attack, you're so crazy~ + D = 0x0000; + DBRSL16 = 0x00 << 16; + PBR = 0x00; + S = 0x01FD; + P = M_FLAG | X_FLAG | I_FLAG; + + PC = MemRead(0xFFFC); + BranchOccurred(); +} + +void Core65816::StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname) +{ + SFORMAT StateRegs[] = + { + SFVAR(PC), + SFVAR(PBR), + SFVAR(DBRSL16), + SFVAR(S), + SFVAR(D), + SFVAR(C), + SFVAR(X), + SFVAR(Y), + SFVAR(P), + SFVAR(E), + + SFEND + }; + + MDFNSS_StateAction(sm, load, data_only, StateRegs, sname); +}; +// +// +// +uint32 Core65816::GetRegister(const unsigned id, char* const special, const uint32 special_len) +{ + uint32 ret = 0xDEADBEEF; + + switch(id) + { + case GSREG_PCPBR: + ret = PCPBR; + break; + + case GSREG_DBR: + ret = DBRSL16 >> 16; + break; + + case GSREG_S: + ret = S; + break; + + case GSREG_D: + ret = D; + break; + + case GSREG_A: + ret = C; + break; + + case GSREG_X: + ret = X; + break; + + case GSREG_Y: + ret = Y; + break; + + case GSREG_P: + ret = P; + break; + + case GSREG_E: + ret = E; + break; + } + + return ret; +} + +void Core65816::SetRegister(const unsigned id, const uint32 value) +{ + switch(id) + { + case GSREG_PCPBR: + PCPBR = value & 0xFFFFFF; + break; + + case GSREG_DBR: + DBRSL16 = (value & 0xFF) << 16; + break; + + case GSREG_S: + S = value; + break; + + case GSREG_D: + D = value; + break; + + case GSREG_A: + C = value; + break; + + case GSREG_X: + X = value; + if(P & X_FLAG) + { + X = (uint8)X; + } + break; + + case GSREG_Y: + Y = value; + if(P & X_FLAG) + { + Y = (uint8)Y; + } + break; + + case GSREG_P: + P = value; + if(P & X_FLAG) + { + X = (uint8)X; + Y = (uint8)Y; + } + break; + + case GSREG_E: + //TODO E = value; + break; + } +} + diff --git a/mednafen/snes_faust/Makefile.am.inc b/mednafen/snes_faust/Makefile.am.inc index f833092..16e0f4a 100644 --- a/mednafen/snes_faust/Makefile.am.inc +++ b/mednafen/snes_faust/Makefile.am.inc @@ -1,2 +1,5 @@ mednafen_SOURCES += snes_faust/cpu.cpp snes_faust/snes.cpp snes_faust/apu.cpp snes_faust/cart.cpp snes_faust/input.cpp snes_faust/ppu.cpp +mednafen_SOURCES += snes_faust/cart/dsp1.cpp snes_faust/cart/dsp2.cpp snes_faust/cart/sdd1.cpp snes_faust/cart/cx4.cpp snes_faust/cart/superfx.cpp +mednafen_SOURCES += snes_faust/cart/sa1.cpp snes_faust/cart/sa1cpu.cpp +mednafen_SOURCES += snes_faust/debug.cpp snes_faust/dis65816.cpp diff --git a/mednafen/snes_faust/apu.cpp b/mednafen/snes_faust/apu.cpp index ab67115..ab2ff0b 100644 --- a/mednafen/snes_faust/apu.cpp +++ b/mednafen/snes_faust/apu.cpp @@ -19,7 +19,7 @@ ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -//#define MDFN_SNES_FAUST_SPC700_IPL_HLE 1 +#define MDFN_SNES_FAUST_SPC700_IPL_HLE 1 //#define MDFN_SNES_FAUST_SPC700_IPL_EFFECTS_ANALYZE 1 #include "snes.h" @@ -236,6 +236,11 @@ static void MDFN_HOT MDFN_FASTCALL NO_INLINE APU_Update(uint32 master_timestamp) static DEFREAD(MainCPU_APUIORead) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return IOFromSPC700[A & 0x3]; + } + CPUM.timestamp += MEMCYC_FAST / 2; APU_Update(CPUM.timestamp); @@ -292,10 +297,23 @@ INLINE void SPC700::IPL_HLE(void) //if(PC != 0xFFC1) // printf("Begin %04x\n", PC); +/* + if(PC == 0xFFC3) // Not sure what effect this has. + { + // Bishoujo Senshi Sailor Moon S - Jougai Rantou! Shuyaku Soudatsusen + // Gaia Saver - Hero Saidai no Sakusen + // Kawa no Nushi Tsuri 2 + // Umi no Nushi Tsuri + // Zero 4 Champ RR + printf("%02x %02x %02x\n", PSW, SP, A); + abort(); + } +*/ + if(PC == 0xFFCA) goto SkipMemInit; - assert(PC == 0xFFC1); + assert(PC == 0xFFC1 || PC == 0xFFC3); PSW = 0x00; SP = 0xEF; @@ -316,6 +334,8 @@ INLINE void SPC700::IPL_HLE(void) HLE_DUMMY_READ(0xF5); HLE_WRITE(0xF5, 0xBB); + HLE_SUCK(1); + do { HLE_SUCK(2); @@ -379,7 +399,7 @@ INLINE void SPC700::IPL_HLE(void) { HLE_SUCK(4); HLE_READ(0xF5, A); - HLE_SUCK(1); + HLE_SUCK(2); HLE_READ(0xF4, HLETemp); HLE_WRITE(0xF4, HLETemp); @@ -634,8 +654,28 @@ void APU_StateAction(StateMem* sm, const unsigned load, const bool data_only) SFEND }; - MDFNSS_StateAction(sm, load, data_only, HLE_StateRegs, "APU_IPL_HLE"); + const bool hle_section_optional = SPC_CPU.GetRegister(SPC700::GSREG_PC) < 0xFFC0; + + if(!MDFNSS_StateAction(sm, load, data_only, HLE_StateRegs, "APU_IPL_HLE", hle_section_optional)) + { + HLEPhase = 0; + HLELoadAddr = 0; + HLECounter = 0; + HLEHS = 0; + HLESuckCounter = 0; + HLETemp = 0; + } #endif } +void APU_PokeRAM(uint32 addr, const uint8 val) +{ + APURAM[addr & 0xFFFF] = val; +} + +uint8 APU_PeekRAM(uint32 addr) +{ + return APURAM[addr & 0xFFFF]; +} + } diff --git a/mednafen/snes_faust/apu.h b/mednafen/snes_faust/apu.h index 68bef16..59d0cd1 100644 --- a/mednafen/snes_faust/apu.h +++ b/mednafen/snes_faust/apu.h @@ -35,7 +35,11 @@ void APU_StartFrame(double master_clock, double rate); void APU_SetSPC(SPCReader* s) MDFN_COLD; // Call after APU_Reset() void APU_StateAction(StateMem* sm, const unsigned load, const bool data_only); - +// +// +// +uint8 APU_PeekRAM(uint32 addr) MDFN_COLD; +void APU_PokeRAM(uint32 addr, const uint8 val) MDFN_COLD; } #endif diff --git a/mednafen/snes_faust/apu_ipl.inc b/mednafen/snes_faust/apu_ipl.inc deleted file mode 100644 index b0bd7fc..0000000 --- a/mednafen/snes_faust/apu_ipl.inc +++ /dev/null @@ -1,9 +0,0 @@ - 0xcd, 0xef, 0xbd, 0xe8, 0x00, 0xc6, 0x1d, 0xd0, - 0xfc, 0x8f, 0xaa, 0xf4, 0x8f, 0xbb, 0xf5, 0x78, - 0xcc, 0xf4, 0xd0, 0xfb, 0x2f, 0x19, 0xeb, 0xf4, - 0xd0, 0xfc, 0x7e, 0xf4, 0xd0, 0x0b, 0xe4, 0xf5, - 0xcb, 0xf4, 0xd7, 0x00, 0xfc, 0xd0, 0xf3, 0xab, - 0x01, 0x10, 0xef, 0x7e, 0xf4, 0x10, 0xeb, 0xba, - 0xf6, 0xda, 0x00, 0xba, 0xf4, 0xc4, 0xf4, 0xdd, - 0x5d, 0xd0, 0xdb, 0x1f, 0x00, 0x00, 0xc0, 0xff - diff --git a/mednafen/snes_faust/cart-private.h b/mednafen/snes_faust/cart-private.h new file mode 100644 index 0000000..e1b8c71 --- /dev/null +++ b/mednafen/snes_faust/cart-private.h @@ -0,0 +1,64 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* cart-private.h: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __MDFN_SNES_FAUST_CART_PRIVATE_H +#define __MDFN_SNES_FAUST_CART_PRIVATE_H + +namespace MDFN_IEN_SNES_FAUST +{ + +enum +{ + ROM_LAYOUT_LOROM = 0, + ROM_LAYOUT_HIROM, + ROM_LAYOUT_EXLOROM, + ROM_LAYOUT_EXHIROM, + + ROM_LAYOUT_INVALID = 0xFFFFFFFF +}; + +struct CartInfo +{ + void (*Reset)(bool powering_up); + void (*Kill)(void); + + void (*StateAction)(StateMem* sm, const unsigned load, const bool data_only); + + void (*AdjustTS)(const int32 delta); + + snes_event_handler EventHandler; + // + // + // + uint8* RAM; + size_t RAM_Mask; + size_t RAM_Size; + + size_t ROM_Size; + unsigned ROMLayout; + // + uint8 ROM[8192 * 1024]; +}; + + extern CartInfo Cart; +} + +#endif diff --git a/mednafen/snes_faust/cart.cpp b/mednafen/snes_faust/cart.cpp index e574c68..822cd46 100644 --- a/mednafen/snes_faust/cart.cpp +++ b/mednafen/snes_faust/cart.cpp @@ -2,7 +2,7 @@ /* Mednafen Fast SNES Emulation Module */ /******************************************************************************/ /* cart.cpp: -** Copyright (C) 2015-2016 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -21,6 +21,13 @@ #include "snes.h" #include "cart.h" +#include "cart-private.h" +#include "cart/dsp1.h" +#include "cart/dsp2.h" +#include "cart/sdd1.h" +#include "cart/cx4.h" +#include "cart/sa1.h" +#include "cart/superfx.h" #include #include @@ -28,40 +35,55 @@ namespace MDFN_IEN_SNES_FAUST { -static uint8 CartROM[8192 * 1024]; -static std::vector CartRAM; + +CartInfo Cart; template static DEFREAD(CartRead_LoROM) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return (Cart.ROM + rom_offset)[(A & 0x7FFF) | ((A >> 1) & 0x3F8000)]; + } + if(cyc >= 0) CPUM.timestamp += cyc; else CPUM.timestamp += MemSelect ? MEMCYC_FAST : MEMCYC_SLOW; - return (CartROM + rom_offset)[(A & 0x7FFF) | ((A >> 1) & 0x3F8000)]; + return (Cart.ROM + rom_offset)[(A & 0x7FFF) | ((A >> 1) & 0x3F8000)]; } template static DEFREAD(CartRead_HiROM) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return (Cart.ROM + rom_offset)[A & 0x3FFFFF]; + } + if(cyc >= 0) CPUM.timestamp += cyc; else CPUM.timestamp += MemSelect ? MEMCYC_FAST : MEMCYC_SLOW; - return (CartROM + rom_offset)[A & 0x3FFFFF]; + return (Cart.ROM + rom_offset)[A & 0x3FFFFF]; } template static DEFREAD(CartRead_SRAM_LoROM) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return Cart.RAM[((A & 0x7FFF) | ((A >> 1) &~ 0x7FFF)) & Cart.RAM_Mask]; + } + if(cyc >= 0) CPUM.timestamp += cyc; else CPUM.timestamp += MemSelect ? MEMCYC_FAST : MEMCYC_SLOW; - return CartRAM[((A & 0x7FFF) | ((A >> 1) &~ 0x7FFF)) & (CartRAM.size() - 1)]; + return Cart.RAM[((A & 0x7FFF) | ((A >> 1) &~ 0x7FFF)) & Cart.RAM_Mask]; } template @@ -72,49 +94,41 @@ static DEFWRITE(CartWrite_SRAM_LoROM) else CPUM.timestamp += MemSelect ? MEMCYC_FAST : MEMCYC_SLOW; - CartRAM[((A & 0x7FFF) | ((A >> 1) &~ 0x7FFF)) & (CartRAM.size() - 1)] = V; + Cart.RAM[((A & 0x7FFF) | ((A >> 1) &~ 0x7FFF)) & Cart.RAM_Mask] = V; } -template static DEFREAD(CartRead_SRAM_HiROM) { - if(cyc >= 0) - CPUM.timestamp += cyc; - else - CPUM.timestamp += MemSelect ? MEMCYC_FAST : MEMCYC_SLOW; + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return Cart.RAM[((A & 0x1FFF) | ((A >> 3) & 0x3E000)) & Cart.RAM_Mask]; + } + + CPUM.timestamp += MEMCYC_SLOW; // // const unsigned raw_sram_index = (A & 0x1FFF) | ((A >> 3) & 0x3E000); - return CartRAM[raw_sram_index & (CartRAM.size() - 1)]; + return Cart.RAM[raw_sram_index & Cart.RAM_Mask]; } -template static DEFWRITE(CartWrite_SRAM_HiROM) { - if(cyc >= 0) - CPUM.timestamp += cyc; - else - CPUM.timestamp += MemSelect ? MEMCYC_FAST : MEMCYC_SLOW; + CPUM.timestamp += MEMCYC_SLOW; // // const unsigned raw_sram_index = (A & 0x1FFF) | ((A >> 3) & 0x3E000); - CartRAM[raw_sram_index & (CartRAM.size() - 1)] = V; + Cart.RAM[raw_sram_index & Cart.RAM_Mask] = V; } -enum +static MDFN_COLD uint32 DummyEventHandler(uint32 timestamp) { - ROM_LAYOUT_LOROM = 0, - ROM_LAYOUT_HIROM, - ROM_LAYOUT_EXLOROM, - ROM_LAYOUT_EXHIROM, - - ROM_LAYOUT_INVALID = 0xFFFFFFFF -}; + return SNES_EVENT_MAXTS; +} -bool CART_Init(Stream* fp, uint8 id[16]) +bool CART_Init(Stream* fp, uint8 id[16], const int32 cx4_ocmultiplier, const int32 superfx_ocmultiplier) { bool IsPAL = false; static const uint64 max_rom_size = 8192 * 1024; @@ -128,10 +142,10 @@ bool CART_Init(Stream* fp, uint8 id[16]) throw MDFN_Error(0, _("SNES ROM image is too large.")); fp->seek(copier_header_adjust, SEEK_SET); - fp->read(CartROM, size); + fp->read(Cart.ROM, size); { - sha1_digest sd = sha1(CartROM, size); + sha1_digest sd = sha1(Cart.ROM, size); memcpy(id, &sd[0], 16); } @@ -140,21 +154,38 @@ bool CART_Init(Stream* fp, uint8 id[16]) if(s & (1U << i)) { SNES_DBG("[CART] Copy 0x%08x bytes from 0x%08x to 0x%08x\n", 1U << i, s - (1U << i), s); - memcpy(CartROM + s, CartROM + s - (1U << i), 1U << i); + memcpy(Cart.ROM + s, Cart.ROM + s - (1U << i), 1U << i); s += (1U << i); } } // // // - + enum + { + SPECIAL_CHIP_NONE = 0, + SPECIAL_CHIP_SUPERFX, + SPECIAL_CHIP_OBC1, + SPECIAL_CHIP_SA1, + SPECIAL_CHIP_SDD1, + SPECIAL_CHIP_SPC7110, + SPECIAL_CHIP_ST018, + SPECIAL_CHIP_CX4, + SPECIAL_CHIP_DSP1, + SPECIAL_CHIP_DSP2, + SPECIAL_CHIP_DSP3, + SPECIAL_CHIP_DSP4, + SPECIAL_CHIP_ST010, + SPECIAL_CHIP_ST011 + }; + unsigned special_chip = SPECIAL_CHIP_NONE; unsigned rom_layout = ROM_LAYOUT_INVALID; unsigned ram_size = 0; - uint8* header = NULL; + //uint8* header = NULL; for(unsigned s = 0; s < 2; s++) { - unsigned char* tmp = &CartROM[s * 0x8000]; + unsigned char* tmp = &Cart.ROM[s * 0x8000]; unsigned rv = MDFN_de16lsb(&tmp[0x7FFC]); if(rv >= 0x8000) @@ -162,7 +193,10 @@ bool CART_Init(Stream* fp, uint8 id[16]) const uint8 header_ram_size = tmp[0x7FD8]; const uint8 header_rom_size = tmp[0x7FD7]; const uint8 country_code = tmp[0x7FD9]; - const uint8 header_rom_type = tmp[0x7FD5]; + const uint8 header_rom_speedmap = tmp[0x7FD5]; + const uint8 header_chipset = tmp[0x7FD6]; + const uint8 header_developer = tmp[0x7FDA]; + const uint8 header_subchip = tmp[0x7FBF]; if(rom_layout == ROM_LAYOUT_INVALID) rom_layout = (s ? ROM_LAYOUT_HIROM : ROM_LAYOUT_LOROM); @@ -190,7 +224,7 @@ bool CART_Init(Stream* fp, uint8 id[16]) break; } - switch(header_rom_type) + switch(header_rom_speedmap) { case 0x30: case 0x20: @@ -218,7 +252,78 @@ bool CART_Init(Stream* fp, uint8 id[16]) break; } - ram_size = (header_ram_size ? (0x800 << (header_ram_size - 1)) : 0); + { + const unsigned ln = header_chipset & 0xF; + const unsigned hn = header_chipset >> 4; + + SNES_DBG("[CART] %02x %02x\n", header_chipset, header_subchip); + + ram_size = (header_ram_size ? (0x800 << (header_ram_size - 1)) : 0); + + SNES_DBG("[CART] %02x %02x %02x %02x\n", rom_layout, header_ram_size, header_rom_size, header_developer); + + if(ln >= 0x3 && ln <= 0xA && ln != 0x7 && ln != 0x8) + { + switch(hn) + { + case 0x0: // DSPn + if(rom_layout == ROM_LAYOUT_LOROM && header_ram_size == 0x05 && header_rom_size == 0x0A) + { + SNES_DBG("[CART] DSP2\n"); + special_chip = SPECIAL_CHIP_DSP2; + } + else if(rom_layout == ROM_LAYOUT_LOROM && header_ram_size == 0x03 && header_rom_size == 0x0A && header_developer == 0xB2) + { + SNES_DBG("[CART] DSP3\n"); + special_chip = SPECIAL_CHIP_DSP3; + } + else if(rom_layout == ROM_LAYOUT_LOROM && header_ram_size == 0x00 && header_rom_size == 0x0A && header_developer == 0x33) + { + SNES_DBG("[CART] DSP4\n"); + special_chip = SPECIAL_CHIP_DSP4; + } +/* + else if(rom_layout == ROM_LAYOUT_LOROM && header_ram_size == 0x03 && header_rom_size == 0x0A && header_developer == 0x29) + { + SNES_DBG("ST010\n"); + special_chip = SPECIAL_CHIP_ST010; + } +*/ + else + { + SNES_DBG("[CART] DSP1\n"); + special_chip = SPECIAL_CHIP_DSP1; + } + break; + + case 0x1: + special_chip = SPECIAL_CHIP_SUPERFX; + if(!ram_size) + { + const uint8 ex_header_ram_size = tmp[0x7FBD]; + + if(ex_header_ram_size == 0x5 || ex_header_ram_size == 0x6) + ram_size = 0x400 << ex_header_ram_size; + else + ram_size = 32768; + } + break; + case 0x2: special_chip = SPECIAL_CHIP_OBC1; break; // OBC1 + case 0x3: special_chip = SPECIAL_CHIP_SA1; break; // SA1 + case 0x4: special_chip = SPECIAL_CHIP_SDD1; break; // SDD1 + case 0xF: + switch(header_subchip) + { + case 0x00: special_chip = SPECIAL_CHIP_SPC7110; break; + case 0x01: /*special_chip = SPECIAL_CHIP_ST010_ST011;*/ break; + case 0x02: special_chip = SPECIAL_CHIP_ST018; break; + case 0x10: special_chip = SPECIAL_CHIP_CX4; break; + } + break; + } + } + } + break; } } @@ -229,6 +334,8 @@ bool CART_Init(Stream* fp, uint8 id[16]) rom_layout = ROM_LAYOUT_LOROM; SNES_DBG("[CART] rom_layout=%d\n", rom_layout); + Cart.ROMLayout = rom_layout; + Cart.ROM_Size = size; //if((rom_type &~ 0x10) == 0x20) //{ // assert(raw_ram_size <= 0x09); @@ -238,76 +345,129 @@ bool CART_Init(Stream* fp, uint8 id[16]) // assert(raw_ram_size <= 0x05); //} - CartRAM.resize(ram_size); + if(ram_size) + { + Cart.RAM = new uint8[ram_size]; + memset(Cart.RAM, 0x00, ram_size); + } - SNES_DBG("[CART] Cart RAM Size: %zu\n", CartRAM.size()); - //printf("%zu\n", CartRAM.size()); + Cart.RAM_Size = ram_size; + Cart.RAM_Mask = (size_t)ram_size - 1; + SNES_DBG("[CART] Cart RAM Size: %zu\n", Cart.RAM_Size); + //printf("%zu\n", Cart.RAM_Size); // abort(); // // // - for(unsigned bank = 0x00; bank < 0x100; bank++) + if(special_chip != SPECIAL_CHIP_SUPERFX && special_chip != SPECIAL_CHIP_SDD1) { - if(bank == 0x7E || bank == 0x7F) - continue; + for(unsigned bank = 0x00; bank < 0x100; bank++) + { + if(bank == 0x7E || bank == 0x7F) + continue; - readfunc cart_r; - writefunc cart_w; + readfunc cart_r; + writefunc cart_w; - if(rom_layout == ROM_LAYOUT_LOROM || rom_layout == ROM_LAYOUT_EXLOROM) - { - if(rom_layout == ROM_LAYOUT_EXLOROM && bank < 0xC0) - cart_r = ((bank >= 0x80) ? CartRead_LoROM<-1, 0x400000> : CartRead_LoROM); - else - cart_r = ((bank >= 0x80) ? CartRead_LoROM<-1> : CartRead_LoROM); + if(rom_layout == ROM_LAYOUT_LOROM || rom_layout == ROM_LAYOUT_EXLOROM) + { + if(rom_layout == ROM_LAYOUT_EXLOROM && bank < 0xC0) + cart_r = ((bank >= 0x80) ? CartRead_LoROM<-1, 0x400000> : CartRead_LoROM); + else + cart_r = ((bank >= 0x80) ? CartRead_LoROM<-1> : CartRead_LoROM); - cart_w = OBWrite_SLOW; + cart_w = OBWrite_SLOW; - Set_A_Handlers((bank << 16) | 0x8000, (bank << 16) | 0xFFFF, cart_r, cart_w); + Set_A_Handlers((bank << 16) | 0x8000, (bank << 16) | 0xFFFF, cart_r, cart_w); - if(CartRAM.size()) - { - if(bank >= 0x70 && bank <= 0x7D) - Set_A_Handlers((bank << 16) | 0x0000, (bank << 16) | 0x7FFF, CartRead_SRAM_LoROM, CartWrite_SRAM_LoROM); - else if(bank >= 0xF0) - Set_A_Handlers((bank << 16) | 0x0000, (bank << 16) | 0x7FFF, CartRead_SRAM_LoROM<-1>, CartWrite_SRAM_LoROM<-1>); + if(Cart.RAM_Mask != SIZE_MAX) + { + if(bank >= 0x70 && bank <= 0x7D) + Set_A_Handlers((bank << 16) | 0x0000, (bank << 16) | 0x7FFF, CartRead_SRAM_LoROM, CartWrite_SRAM_LoROM); + else if(bank >= 0xF0) + Set_A_Handlers((bank << 16) | 0x0000, (bank << 16) | 0x7FFF, CartRead_SRAM_LoROM<-1>, CartWrite_SRAM_LoROM<-1>); + } } - } - else - { - if(rom_layout == ROM_LAYOUT_EXHIROM && bank < 0xC0) - cart_r = ((bank >= 0x80) ? CartRead_HiROM<-1, 0x400000> : CartRead_HiROM); else - cart_r = ((bank >= 0x80) ? CartRead_HiROM<-1> : CartRead_HiROM); + { + if(rom_layout == ROM_LAYOUT_EXHIROM && bank < 0xC0) + cart_r = ((bank >= 0x80) ? CartRead_HiROM<-1, 0x400000> : CartRead_HiROM); + else + cart_r = ((bank >= 0x80) ? CartRead_HiROM<-1> : CartRead_HiROM); - cart_w = OBWrite_SLOW; + cart_w = OBWrite_SLOW; - uint16 romlb = 0x8000; - if(((bank & 0x7F) >= 0x40 && (bank & 0x7F) <= 0x7D) || bank >= 0xFE) - romlb = 0x0000; + uint16 romlb = 0x8000; + if(((bank & 0x7F) >= 0x40 && (bank & 0x7F) <= 0x7D) || bank >= 0xFE) + romlb = 0x0000; - Set_A_Handlers((bank << 16) | romlb, (bank << 16) | 0xFFFF, cart_r, cart_w); + Set_A_Handlers((bank << 16) | romlb, (bank << 16) | 0xFFFF, cart_r, cart_w); - if(CartRAM.size()) - { - if((bank & 0x7F) >= 0x20 && (bank & 0x7F) <= 0x3F) + if(Cart.RAM_Mask != SIZE_MAX) { - Set_A_Handlers((bank << 16) | 0x6000, + if((bank & 0x7F) >= 0x20 && (bank & 0x7F) <= 0x3F) + { + Set_A_Handlers((bank << 16) | 0x6000, (bank << 16) | 0x7FFF, - ((bank & 0x80) ? CartRead_SRAM_HiROM<-1> : CartRead_SRAM_HiROM), - ((bank & 0x80) ? CartWrite_SRAM_HiROM<-1> : CartWrite_SRAM_HiROM)); + CartRead_SRAM_HiROM, CartWrite_SRAM_HiROM); + } } - } - } + } + } } + // + // + // + const int32 master_clock = IsPAL ? 21281370 : 21477273; + Cart.EventHandler = DummyEventHandler; + Cart.Reset = nullptr; + Cart.Kill = nullptr; + Cart.StateAction = nullptr; + Cart.AdjustTS = nullptr; + + switch(special_chip) + { + default: + //assert(0); + break; + + case SPECIAL_CHIP_NONE: + break; + case SPECIAL_CHIP_SA1: + CART_SA1_Init(master_clock); + break; + + case SPECIAL_CHIP_DSP1: + CART_DSP1_Init(master_clock); + break; + + case SPECIAL_CHIP_DSP2: + CART_DSP2_Init(master_clock); + break; + + case SPECIAL_CHIP_SDD1: + CART_SDD1_Init(master_clock); + break; + + case SPECIAL_CHIP_CX4: + CART_CX4_Init(master_clock, cx4_ocmultiplier); + break; + + case SPECIAL_CHIP_SUPERFX: + CART_SuperFX_Init(master_clock, superfx_ocmultiplier); + break; + } + // + // + // return IsPAL; } bool CART_LoadNV(void) { - if(CartRAM.size() > 0) + if(Cart.RAM_Size) { try { @@ -315,11 +475,11 @@ bool CART_LoadNV(void) FileStream fp(path, FileStream::MODE_READ); const uint64 fp_size_tmp = fp.size(); - if(CartRAM.size() != fp_size_tmp) // Check before reading any data. + if(Cart.RAM_Size != fp_size_tmp) // Check before reading any data. throw MDFN_Error(0, _("Save game memory file \"%s\" is an incorrect size(%llu bytes). The correct size is %llu bytes."), path.c_str(), - (unsigned long long)fp_size_tmp, (unsigned long long)CartRAM.size()); + (unsigned long long)fp_size_tmp, (unsigned long long)Cart.RAM_Size); - fp.read(CartRAM.data(), CartRAM.size()); + fp.read(Cart.RAM, Cart.RAM_Size); return true; } @@ -334,38 +494,84 @@ bool CART_LoadNV(void) void CART_SaveNV(void) { - if(CartRAM.size() > 0) + if(Cart.RAM_Size) { const std::string path = MDFN_MakeFName(MDFNMKF_SAV, 0, "srm"); FileStream fp(path, FileStream::MODE_WRITE_INPLACE); - fp.write(CartRAM.data(), CartRAM.size()); + fp.write(Cart.RAM, Cart.RAM_Size); fp.close(); } } void CART_Kill(void) { - CartRAM.resize(0); + if(Cart.Kill) + { + Cart.Kill(); + Cart.Kill = nullptr; + } + + if(Cart.RAM) + { + delete[] Cart.RAM; + Cart.RAM = nullptr; + } } void CART_Reset(bool powering_up) { + if(Cart.Reset) + Cart.Reset(powering_up); +} - +void CART_AdjustTS(const int32 delta) +{ + if(Cart.AdjustTS) + Cart.AdjustTS(delta); } +snes_event_handler CART_GetEventHandler(void) +{ + return Cart.EventHandler; +} void CART_StateAction(StateMem* sm, const unsigned load, const bool data_only) { SFORMAT StateRegs[] = { - SFPTR8N(CartRAM.size() ? &CartRAM[0] : NULL, CartRAM.size(), "&CartRAM[0]"), + SFPTR8N(Cart.RAM, Cart.RAM_Size, "&CartRAM[0]"), SFEND }; MDFNSS_StateAction(sm, load, data_only, StateRegs, "CART"); + + if(Cart.StateAction) + Cart.StateAction(sm, load, data_only); +} +// +// +// +uint8 CART_PeekRAM(uint32 addr) +{ + if(Cart.RAM_Mask != SIZE_MAX) + return Cart.RAM[addr & Cart.RAM_Mask]; + + return 0; +} + +void CART_PokeRAM(uint32 addr, uint8 val) +{ + if(Cart.RAM_Mask != SIZE_MAX) + { + Cart.RAM[addr & Cart.RAM_Mask] = val; + } +} + +uint32 CART_GetRAMSize(void) +{ + return (size_t)(Cart.RAM_Mask + 1); } } diff --git a/mednafen/snes_faust/cart.h b/mednafen/snes_faust/cart.h index 8f64d56..7733b9f 100644 --- a/mednafen/snes_faust/cart.h +++ b/mednafen/snes_faust/cart.h @@ -2,7 +2,7 @@ /* Mednafen Fast SNES Emulation Module */ /******************************************************************************/ /* cart.h: -** Copyright (C) 2015-2017 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -24,13 +24,28 @@ namespace MDFN_IEN_SNES_FAUST { - bool CART_Init(Stream* fp, uint8 id[16]) MDFN_COLD; +// +// +// + bool CART_Init(Stream* fp, uint8 id[16], const int32 cx4_ocmultiplier, const int32 superfx_ocmultiplier) MDFN_COLD; void CART_Kill(void) MDFN_COLD; void CART_Reset(bool powering_up) MDFN_COLD; void CART_StateAction(StateMem* sm, const unsigned load, const bool data_only); + void CART_AdjustTS(const int32 delta) MDFN_COLD; + snes_event_handler CART_GetEventHandler(void) MDFN_COLD; + bool CART_LoadNV(void) MDFN_COLD; void CART_SaveNV(void); +// +// +// + uint8 CART_PeekRAM(uint32 addr) MDFN_COLD; + void CART_PokeRAM(uint32 addr, uint8 val) MDFN_COLD; + uint32 CART_GetRAMSize(void) MDFN_COLD; +// +// +// } #endif diff --git a/mednafen/snes_faust/cart/common.h b/mednafen/snes_faust/cart/common.h new file mode 100644 index 0000000..2bd58d9 --- /dev/null +++ b/mednafen/snes_faust/cart/common.h @@ -0,0 +1,29 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* common.h: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __MDFN_SNES_FAUST_CART_COMMON_H +#define __MDFN_SNES_FAUST_CART_COMMON_H + +#include "../snes.h" +#include "../cart.h" +#include "../cart-private.h" + +#endif diff --git a/mednafen/snes_faust/cart/cx4.cpp b/mednafen/snes_faust/cart/cx4.cpp new file mode 100644 index 0000000..2a30c14 --- /dev/null +++ b/mednafen/snes_faust/cart/cx4.cpp @@ -0,0 +1,1663 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* cx4.cpp: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* + Take any information derived from this CX4 emulation code with a large grain of + KCN, as it has guesswork and performance compromises with only MMX2 and + MMX3 in mind. +*/ + +#include "common.h" +#include "cx4.h" + +namespace MDFN_IEN_SNES_FAUST +{ + +/* + static unsigned tab[0x400]; + + for(unsigned i = 0; i < 0x100; i++) + { + tab[0x000 + i] = i ? (0x800000 / i) : 0xFFFFFF; + tab[0x100 + i] = 0x100000 * sqrt(i); + } + + for(unsigned i = 0; i < 0x80; i++) + { + tab[0x200 + i] = 0x1000000 * sin(M_PI * 2 * i / (0x80 * 4)); + tab[0x280 + i] = 0x1000000 * asin((double)i / 0x80) / M_PI; + tab[0x300 + i] = floor(0.001 + 0x10000 * tan(M_PI * 2 * i / (0x80 * 4))); + tab[0x380 + i] = std::min(0xFFFFFF, 0x1000000 * cos(M_PI * 2 * i / (0x80 * 4))); + } + + for(unsigned i = 0; i < 0x400; i++) + { + printf(" 0x%06x,", tab[i]); + if((i & 0x7) == 0x7) + printf("\n"); + } +*/ +static const uint32 DataROM[0x400] = +{ + 0xffffff, 0x800000, 0x400000, 0x2aaaaa, 0x200000, 0x199999, 0x155555, 0x124924, + 0x100000, 0x0e38e3, 0x0ccccc, 0x0ba2e8, 0x0aaaaa, 0x09d89d, 0x092492, 0x088888, + 0x080000, 0x078787, 0x071c71, 0x06bca1, 0x066666, 0x061861, 0x05d174, 0x0590b2, + 0x055555, 0x051eb8, 0x04ec4e, 0x04bda1, 0x049249, 0x0469ee, 0x044444, 0x042108, + 0x040000, 0x03e0f8, 0x03c3c3, 0x03a83a, 0x038e38, 0x03759f, 0x035e50, 0x034834, + 0x033333, 0x031f38, 0x030c30, 0x02fa0b, 0x02e8ba, 0x02d82d, 0x02c859, 0x02b931, + 0x02aaaa, 0x029cbc, 0x028f5c, 0x028282, 0x027627, 0x026a43, 0x025ed0, 0x0253c8, + 0x024924, 0x023ee0, 0x0234f7, 0x022b63, 0x022222, 0x02192e, 0x021084, 0x020820, + 0x020000, 0x01f81f, 0x01f07c, 0x01e913, 0x01e1e1, 0x01dae6, 0x01d41d, 0x01cd85, + 0x01c71c, 0x01c0e0, 0x01bacf, 0x01b4e8, 0x01af28, 0x01a98e, 0x01a41a, 0x019ec8, + 0x019999, 0x01948b, 0x018f9c, 0x018acb, 0x018618, 0x018181, 0x017d05, 0x0178a4, + 0x01745d, 0x01702e, 0x016c16, 0x016816, 0x01642c, 0x016058, 0x015c98, 0x0158ed, + 0x015555, 0x0151d0, 0x014e5e, 0x014afd, 0x0147ae, 0x01446f, 0x014141, 0x013e22, + 0x013b13, 0x013813, 0x013521, 0x01323e, 0x012f68, 0x012c9f, 0x0129e4, 0x012735, + 0x012492, 0x0121fb, 0x011f70, 0x011cf0, 0x011a7b, 0x011811, 0x0115b1, 0x01135c, + 0x011111, 0x010ecf, 0x010c97, 0x010a68, 0x010842, 0x010624, 0x010410, 0x010204, + 0x010000, 0x00fe03, 0x00fc0f, 0x00fa23, 0x00f83e, 0x00f660, 0x00f489, 0x00f2b9, + 0x00f0f0, 0x00ef2e, 0x00ed73, 0x00ebbd, 0x00ea0e, 0x00e865, 0x00e6c2, 0x00e525, + 0x00e38e, 0x00e1fc, 0x00e070, 0x00dee9, 0x00dd67, 0x00dbeb, 0x00da74, 0x00d901, + 0x00d794, 0x00d62b, 0x00d4c7, 0x00d368, 0x00d20d, 0x00d0b6, 0x00cf64, 0x00ce16, + 0x00cccc, 0x00cb87, 0x00ca45, 0x00c907, 0x00c7ce, 0x00c698, 0x00c565, 0x00c437, + 0x00c30c, 0x00c1e4, 0x00c0c0, 0x00bfa0, 0x00be82, 0x00bd69, 0x00bc52, 0x00bb3e, + 0x00ba2e, 0x00b921, 0x00b817, 0x00b70f, 0x00b60b, 0x00b509, 0x00b40b, 0x00b30f, + 0x00b216, 0x00b11f, 0x00b02c, 0x00af3a, 0x00ae4c, 0x00ad60, 0x00ac76, 0x00ab8f, + 0x00aaaa, 0x00a9c8, 0x00a8e8, 0x00a80a, 0x00a72f, 0x00a655, 0x00a57e, 0x00a4a9, + 0x00a3d7, 0x00a306, 0x00a237, 0x00a16b, 0x00a0a0, 0x009fd8, 0x009f11, 0x009e4c, + 0x009d89, 0x009cc8, 0x009c09, 0x009b4c, 0x009a90, 0x0099d7, 0x00991f, 0x009868, + 0x0097b4, 0x009701, 0x00964f, 0x0095a0, 0x0094f2, 0x009445, 0x00939a, 0x0092f1, + 0x009249, 0x0091a2, 0x0090fd, 0x00905a, 0x008fb8, 0x008f17, 0x008e78, 0x008dda, + 0x008d3d, 0x008ca2, 0x008c08, 0x008b70, 0x008ad8, 0x008a42, 0x0089ae, 0x00891a, + 0x008888, 0x0087f7, 0x008767, 0x0086d9, 0x00864b, 0x0085bf, 0x008534, 0x0084a9, + 0x008421, 0x008399, 0x008312, 0x00828c, 0x008208, 0x008184, 0x008102, 0x008080, + 0x000000, 0x100000, 0x16a09e, 0x1bb67a, 0x200000, 0x23c6ef, 0x27311c, 0x2a54ff, + 0x2d413c, 0x300000, 0x3298b0, 0x3510e5, 0x376cf5, 0x39b056, 0x3bddd4, 0x3df7bd, + 0x400000, 0x41f83d, 0x43e1db, 0x45be0c, 0x478dde, 0x49523a, 0x4b0bf1, 0x4cbbb9, + 0x4e6238, 0x500000, 0x519595, 0x532370, 0x54a9fe, 0x5629a2, 0x57a2b7, 0x591590, + 0x5a8279, 0x5be9ba, 0x5d4b94, 0x5ea843, 0x600000, 0x6152fe, 0x62a170, 0x63eb83, + 0x653160, 0x667332, 0x67b11d, 0x68eb44, 0x6a21ca, 0x6b54cd, 0x6c846c, 0x6db0c2, + 0x6ed9eb, 0x700000, 0x712318, 0x72434a, 0x7360ad, 0x747b54, 0x759354, 0x76a8bf, + 0x77bba8, 0x78cc1f, 0x79da34, 0x7ae5f9, 0x7bef7a, 0x7cf6c8, 0x7dfbef, 0x7efefd, + 0x800000, 0x80ff01, 0x81fc0f, 0x82f734, 0x83f07b, 0x84e7ee, 0x85dd98, 0x86d182, + 0x87c3b6, 0x88b43d, 0x89a31f, 0x8a9066, 0x8b7c19, 0x8c6641, 0x8d4ee4, 0x8e360b, + 0x8f1bbc, 0x900000, 0x90e2db, 0x91c456, 0x92a475, 0x938341, 0x9460bd, 0x953cf1, + 0x9617e2, 0x96f196, 0x97ca11, 0x98a159, 0x997773, 0x9a4c64, 0x9b2031, 0x9bf2de, + 0x9cc470, 0x9d94eb, 0x9e6454, 0x9f32af, 0xa00000, 0xa0cc4a, 0xa19792, 0xa261dc, + 0xa32b2a, 0xa3f382, 0xa4bae6, 0xa5815a, 0xa646e1, 0xa70b7e, 0xa7cf35, 0xa89209, + 0xa953fd, 0xaa1513, 0xaad550, 0xab94b4, 0xac5345, 0xad1103, 0xadcdf2, 0xae8a15, + 0xaf456e, 0xb00000, 0xb0b9cc, 0xb172d6, 0xb22b20, 0xb2e2ac, 0xb3997c, 0xb44f93, + 0xb504f3, 0xb5b99d, 0xb66d95, 0xb720dc, 0xb7d375, 0xb88560, 0xb936a0, 0xb9e738, + 0xba9728, 0xbb4673, 0xbbf51a, 0xbca320, 0xbd5086, 0xbdfd4e, 0xbea979, 0xbf5509, + 0xc00000, 0xc0aa5f, 0xc15428, 0xc1fd5c, 0xc2a5fd, 0xc34e0d, 0xc3f58c, 0xc49c7d, + 0xc542e1, 0xc5e8b8, 0xc68e05, 0xc732c9, 0xc7d706, 0xc87abb, 0xc91deb, 0xc9c098, + 0xca62c1, 0xcb0469, 0xcba591, 0xcc463a, 0xcce664, 0xcd8612, 0xce2544, 0xcec3fc, + 0xcf623a, 0xd00000, 0xd09d4e, 0xd13a26, 0xd1d689, 0xd27277, 0xd30df3, 0xd3a8fc, + 0xd44394, 0xd4ddbc, 0xd57774, 0xd610be, 0xd6a99b, 0xd7420b, 0xd7da0f, 0xd871a9, + 0xd908d8, 0xd99f9f, 0xda35fe, 0xdacbf5, 0xdb6185, 0xdbf6b0, 0xdc8b76, 0xdd1fd8, + 0xddb3d7, 0xde4773, 0xdedaad, 0xdf6d86, 0xe00000, 0xe09219, 0xe123d4, 0xe1b530, + 0xe24630, 0xe2d6d2, 0xe36719, 0xe3f704, 0xe48694, 0xe515cb, 0xe5a4a8, 0xe6332d, + 0xe6c15a, 0xe74f2f, 0xe7dcad, 0xe869d6, 0xe8f6a9, 0xe98326, 0xea0f50, 0xea9b26, + 0xeb26a8, 0xebb1d9, 0xec3cb7, 0xecc743, 0xed517f, 0xeddb6a, 0xee6506, 0xeeee52, + 0xef7750, 0xf00000, 0xf08861, 0xf11076, 0xf1983e, 0xf21fba, 0xf2a6ea, 0xf32dcf, + 0xf3b469, 0xf43ab9, 0xf4c0c0, 0xf5467d, 0xf5cbf2, 0xf6511e, 0xf6d602, 0xf75a9f, + 0xf7def5, 0xf86305, 0xf8e6ce, 0xf96a52, 0xf9ed90, 0xfa708a, 0xfaf33f, 0xfb75b1, + 0xfbf7df, 0xfc79ca, 0xfcfb72, 0xfd7cd8, 0xfdfdfb, 0xfe7ede, 0xfeff7f, 0xff7fdf, + 0x000000, 0x03243a, 0x064855, 0x096c32, 0x0c8fb2, 0x0fb2b7, 0x12d520, 0x15f6d0, + 0x1917a6, 0x1c3785, 0x1f564e, 0x2273e1, 0x259020, 0x28aaed, 0x2bc428, 0x2edbb3, + 0x31f170, 0x350540, 0x381704, 0x3b269f, 0x3e33f2, 0x413ee0, 0x444749, 0x474d10, + 0x4a5018, 0x4d5043, 0x504d72, 0x534789, 0x563e69, 0x5931f7, 0x5c2214, 0x5f0ea4, + 0x61f78a, 0x64dca9, 0x67bde5, 0x6a9b20, 0x6d7440, 0x704927, 0x7319ba, 0x75e5dd, + 0x78ad74, 0x7b7065, 0x7e2e93, 0x80e7e4, 0x839c3c, 0x864b82, 0x88f59a, 0x8b9a6b, + 0x8e39d9, 0x90d3cc, 0x93682a, 0x95f6d9, 0x987fbf, 0x9b02c5, 0x9d7fd1, 0x9ff6ca, + 0xa26799, 0xa4d224, 0xa73655, 0xa99414, 0xabeb49, 0xae3bdd, 0xb085ba, 0xb2c8c9, + 0xb504f3, 0xb73a22, 0xb96841, 0xbb8f3a, 0xbdaef9, 0xbfc767, 0xc1d870, 0xc3e200, + 0xc5e403, 0xc7de65, 0xc9d112, 0xcbbbf7, 0xcd9f02, 0xcf7a1f, 0xd14d3d, 0xd31848, + 0xd4db31, 0xd695e4, 0xd84852, 0xd9f269, 0xdb941a, 0xdd2d53, 0xdebe05, 0xe04621, + 0xe1c597, 0xe33c59, 0xe4aa59, 0xe60f87, 0xe76bd7, 0xe8bf3b, 0xea09a6, 0xeb4b0b, + 0xec835e, 0xedb293, 0xeed89d, 0xeff573, 0xf10908, 0xf21352, 0xf31447, 0xf40bdd, + 0xf4fa0a, 0xf5dec6, 0xf6ba07, 0xf78bc5, 0xf853f7, 0xf91297, 0xf9c79d, 0xfa7301, + 0xfb14be, 0xfbaccd, 0xfc3b27, 0xfcbfc9, 0xfd3aab, 0xfdabcb, 0xfe1323, 0xfe70af, + 0xfec46d, 0xff0e57, 0xff4e6d, 0xff84ab, 0xffb10f, 0xffd397, 0xffec43, 0xfffb10, + 0x000000, 0x00a2f9, 0x0145f6, 0x01e8f8, 0x028c01, 0x032f14, 0x03d234, 0x047564, + 0x0518a5, 0x05bbfb, 0x065f68, 0x0702ef, 0x07a692, 0x084a54, 0x08ee38, 0x099240, + 0x0a366e, 0x0adac7, 0x0b7f4c, 0x0c2401, 0x0cc8e7, 0x0d6e02, 0x0e1355, 0x0eb8e3, + 0x0f5eae, 0x1004b9, 0x10ab08, 0x11519e, 0x11f87d, 0x129fa9, 0x134725, 0x13eef4, + 0x149719, 0x153f99, 0x15e875, 0x1691b2, 0x173b53, 0x17e55c, 0x188fd1, 0x193ab4, + 0x19e60a, 0x1a91d8, 0x1b3e20, 0x1beae7, 0x1c9831, 0x1d4602, 0x1df45f, 0x1ea34c, + 0x1f52ce, 0x2002ea, 0x20b3a3, 0x216500, 0x221705, 0x22c9b8, 0x237d1e, 0x24313c, + 0x24e618, 0x259bb9, 0x265224, 0x27095f, 0x27c171, 0x287a61, 0x293436, 0x29eef6, + 0x2aaaaa, 0x2b6759, 0x2c250a, 0x2ce3c7, 0x2da398, 0x2e6485, 0x2f2699, 0x2fe9dc, + 0x30ae59, 0x31741b, 0x323b2c, 0x330398, 0x33cd6b, 0x3498b1, 0x356578, 0x3633ce, + 0x3703c1, 0x37d560, 0x38a8bb, 0x397de4, 0x3a54ec, 0x3b2de6, 0x3c08e6, 0x3ce601, + 0x3dc54d, 0x3ea6e3, 0x3f8adc, 0x407152, 0x415a62, 0x42462c, 0x4334d0, 0x442671, + 0x451b37, 0x46134a, 0x470ed6, 0x480e0c, 0x491120, 0x4a184c, 0x4b23cd, 0x4c33ea, + 0x4d48ec, 0x4e6327, 0x4f82f9, 0x50a8c9, 0x51d50a, 0x53083f, 0x5442fc, 0x5585ea, + 0x56d1cc, 0x582782, 0x598815, 0x5af4bc, 0x5c6eed, 0x5df86c, 0x5f9369, 0x6142a3, + 0x6309a5, 0x64ed1e, 0x66f381, 0x692617, 0x6b9322, 0x6e52a5, 0x71937c, 0x75ceb4, + 0x000000, 0x000324, 0x000648, 0x00096d, 0x000c93, 0x000fba, 0x0012e2, 0x00160b, + 0x001936, 0x001c63, 0x001f93, 0x0022c4, 0x0025f9, 0x002930, 0x002c6b, 0x002fa9, + 0x0032eb, 0x003632, 0x00397c, 0x003ccb, 0x00401f, 0x004379, 0x0046d8, 0x004a3d, + 0x004da8, 0x005119, 0x005492, 0x005811, 0x005b99, 0x005f28, 0x0062c0, 0x006660, + 0x006a09, 0x006dbc, 0x00717a, 0x007541, 0x007914, 0x007cf2, 0x0080dc, 0x0084d2, + 0x0088d5, 0x008ce6, 0x009105, 0x009533, 0x009970, 0x009dbe, 0x00a21c, 0x00a68b, + 0x00ab0d, 0x00afa2, 0x00b44b, 0x00b909, 0x00bddc, 0x00c2c6, 0x00c7c8, 0x00cce3, + 0x00d218, 0x00d767, 0x00dcd3, 0x00e25d, 0x00e806, 0x00edcf, 0x00f3bb, 0x00f9ca, + 0x010000, 0x01065c, 0x010ce2, 0x011394, 0x011a73, 0x012183, 0x0128c6, 0x01303e, + 0x0137ef, 0x013fdc, 0x014808, 0x015077, 0x01592d, 0x01622d, 0x016b7d, 0x017522, + 0x017f21, 0x018980, 0x019444, 0x019f76, 0x01ab1c, 0x01b73e, 0x01c3e7, 0x01d11f, + 0x01def1, 0x01ed69, 0x01fc95, 0x020c83, 0x021d44, 0x022ee9, 0x024186, 0x025533, + 0x026a09, 0x028025, 0x0297a7, 0x02b0b5, 0x02cb78, 0x02e823, 0x0306ec, 0x032815, + 0x034beb, 0x0372c6, 0x039d10, 0x03cb47, 0x03fe02, 0x0435f7, 0x047405, 0x04b93f, + 0x0506ff, 0x055ef9, 0x05c35d, 0x063709, 0x06bdcf, 0x075ce6, 0x081b97, 0x09046d, + 0x0a2736, 0x0b9cc6, 0x0d8e81, 0x1046e9, 0x145aff, 0x1b2671, 0x28bc48, 0x517bb5, + 0xffffff, 0xfffb10, 0xffec43, 0xffd397, 0xffb10f, 0xff84ab, 0xff4e6d, 0xff0e57, + 0xfec46d, 0xfe70af, 0xfe1323, 0xfdabcb, 0xfd3aab, 0xfcbfc9, 0xfc3b27, 0xfbaccd, + 0xfb14be, 0xfa7301, 0xf9c79d, 0xf91297, 0xf853f7, 0xf78bc5, 0xf6ba07, 0xf5dec6, + 0xf4fa0a, 0xf40bdd, 0xf31447, 0xf21352, 0xf10908, 0xeff573, 0xeed89d, 0xedb293, + 0xec835e, 0xeb4b0b, 0xea09a6, 0xe8bf3b, 0xe76bd7, 0xe60f87, 0xe4aa59, 0xe33c59, + 0xe1c597, 0xe04621, 0xdebe05, 0xdd2d53, 0xdb941a, 0xd9f269, 0xd84852, 0xd695e4, + 0xd4db31, 0xd31848, 0xd14d3d, 0xcf7a1f, 0xcd9f02, 0xcbbbf7, 0xc9d112, 0xc7de65, + 0xc5e403, 0xc3e200, 0xc1d870, 0xbfc767, 0xbdaef9, 0xbb8f3a, 0xb96841, 0xb73a22, + 0xb504f3, 0xb2c8c9, 0xb085ba, 0xae3bdd, 0xabeb49, 0xa99414, 0xa73655, 0xa4d224, + 0xa26799, 0x9ff6ca, 0x9d7fd1, 0x9b02c5, 0x987fbf, 0x95f6d9, 0x93682a, 0x90d3cc, + 0x8e39d9, 0x8b9a6b, 0x88f59a, 0x864b82, 0x839c3c, 0x80e7e4, 0x7e2e93, 0x7b7065, + 0x78ad74, 0x75e5dd, 0x7319ba, 0x704927, 0x6d7440, 0x6a9b20, 0x67bde5, 0x64dca9, + 0x61f78a, 0x5f0ea4, 0x5c2214, 0x5931f7, 0x563e69, 0x534789, 0x504d72, 0x4d5043, + 0x4a5018, 0x474d10, 0x444749, 0x413ee0, 0x3e33f2, 0x3b269f, 0x381704, 0x350540, + 0x31f170, 0x2edbb3, 0x2bc428, 0x28aaed, 0x259020, 0x2273e1, 0x1f564e, 0x1c3785, + 0x1917a6, 0x15f6d0, 0x12d520, 0x0fb2b7, 0x0c8fb2, 0x096c32, 0x064855, 0x03243a, +}; +static uint8 DataRAM[0x400 * 3]; + +enum : size_t +{ + RegsIndex_A = 0x00, + RegsIndex_MACH, + RegsIndex_MACL, + RegsIndex_MBR, + RegsIndex_ROMB, + RegsIndex_RAMB, + RegsIndex_MAR, + RegsIndex_DPR, + RegsIndex_IP, + RegsIndex_P, + RegsIndex_IR0, + RegsIndex_IR15 = RegsIndex_IR0 + 0xF, + RegsIndex_R0, + RegsIndex_R15 = RegsIndex_R0 + 0xF, + // + RegsIndex_NextIP, + // + RegsIndex_WriteDummy, + // + RegsIndex__Count +}; +static uint32 Regs[RegsIndex__Count]; +static uint8 RegsRMap[0x80]; +static uint8 RegsWMap[0x80]; +static uint32 RegsWMask[0x80]; + +static uint32& Accum = Regs[RegsIndex_A]; +static uint32& MACL = Regs[RegsIndex_MACL]; +static uint32& MACH = Regs[RegsIndex_MACH]; +static uint32& MBR = Regs[RegsIndex_MBR]; +static uint32& IP = Regs[RegsIndex_IP]; +static uint32& NextIP = Regs[RegsIndex_NextIP]; +static uint32& ROMB = Regs[RegsIndex_ROMB]; +static uint32& RAMB = Regs[RegsIndex_RAMB]; +static uint32& MAR = Regs[RegsIndex_MAR]; +static uint32& DPR = Regs[RegsIndex_DPR]; +static uint32& P = Regs[RegsIndex_P]; + +//static uint32 Accum; +static bool Flag_Z, Flag_N, Flag_C, Flag_V; + +static uint32 Stack[8]; +static uint32 SP; + +static uint32 NextInstr; +static struct Cache_S +{ + uint16 Data[256 + 2]; + uint32 Tag; + bool Locked; +} Cache[2]; +static Cache_S* Cache_Active; +static uint32 ProgROM_Base; + +static uint32 DMASource; +static uint16 DMALength; +static uint32 DMADest; + +static uint32 Status; +static bool IRQOut; +static uint8 WSControl; +static uint8 IRQControl; +static uint16 VectorRegs[0x10]; + +static uint32 last_master_timestamp; +static unsigned run_count_mod; +static unsigned clock_multiplier; +static int32 cycle_counter; + +static INLINE uint32 ReadReg(unsigned o) +{ + return Regs[RegsRMap[o & 0x7F]]; +} + +static INLINE void WriteReg(unsigned o, uint32 v) +{ + Regs[RegsWMap[o & 0x7F]] = v & RegsWMask[o]; +} + +static void LoadCache(unsigned EffP) +{ + SNES_DBG("[CX4] LoadCache %u: ProgROM_Base=0x%06x, P=0x%04x\n", (unsigned)(Cache_Active - Cache), ProgROM_Base, EffP); + + for(unsigned i = 0; i < 256; i++) + { + uint32 rom_addr; + uint32 tmp; + + rom_addr = ProgROM_Base + (((EffP << 8) + i) << 1); + //assert(rom_addr & 0x8000); + rom_addr = (rom_addr & 0x7FFF) + ((rom_addr >> 1) & 0x7F8000); + + tmp = Cart.ROM[(rom_addr + 0) & (sizeof(Cart.ROM) - 1)]; + tmp |= Cart.ROM[(rom_addr + 1) & (sizeof(Cart.ROM) - 1)] << 8; + + Cache_Active->Data[i] = tmp; + + cycle_counter -= (1 + (WSControl >> 4)) << 1; + } + Cache_Active->Tag = EffP; +} + +static void CheckCache(const unsigned EffP) +{ + if(Cache_Active->Tag == EffP) + return; + + Cache_Active = &Cache[!(Cache_Active - &Cache[0])]; + if(Cache_Active->Tag == EffP) + return; + + if(Cache_Active->Locked) + { + SNES_DBG("[CX4] Wanted to load to cache page %u, but it's locked!\n", (unsigned)(Cache_Active - Cache)); + Cache_Active = &Cache[!(Cache_Active - &Cache[0])]; + } + + if(Cache_Active->Locked) + { + SNES_DBG("[CX4] Unable to load cache, both pages locked!\n"); + Status &= ~0x40; + if(!(Status & 0x100)) + cycle_counter = std::min(cycle_counter, 0); + return; + } + + LoadCache(EffP); +} + +static const unsigned preshift_tab[4] = { 0, 1, 8, 16 }; + + +template +static INLINE void Instr_Branch(uint32 instr) +{ + const bool bsub = opcode & 0x20; + bool cond; + + static_assert(((opcode >> 2) & 0x7) >= 0x2 && ((opcode >> 2) & 0x7) <= 0x6, "bad opcode"); + + switch((opcode >> 2) & 0x7) + { + case 0x2: + cond = true; + break; + + case 0x3: + cond = Flag_Z; + break; + + case 0x4: + cond = Flag_C; + break; + + case 0x5: + cond = Flag_N; + break; + + case 0x6: + cond = Flag_V; + break; + } + + if(cond) + { + if(bsub) + { + SP = (SP + 1) & 0x7; + Stack[SP] = (Cache_Active->Tag << 8) | (uint8)IP; + } + + cycle_counter--; + NextIP = (instr & 0xFF); + NextInstr = 0; + if(opcode & 0x2) + CheckCache(P); + } +} + +template +static INLINE void Instr_SKIP(uint32 instr) +{ + bool cond; + + switch(opcode & 0x3) + { + case 0x0: + cond = Flag_V; + break; + + case 0x1: + cond = Flag_C; + break; + + case 0x2: + cond = Flag_Z; + break; + + case 0x3: + cond = Flag_N; + break; + } + + cond ^= instr & 1; + + if(!cond) + NextInstr = 0; +} + +template +static INLINE void Instr_WRRAM(uint32 instr) +{ + const size_t w = opcode & 0x3; + const unsigned shift = w << 3; + const size_t index = ((opcode & 0x4) ? (DPR + (instr & 0xFF)) : Accum) & 0xFFF; + + if(!(opcode & 0x4) && (instr & 0xFF)) + SNES_DBG("[CX4] WRRAM with non-zero lower instruction byte: 0x%04x\n", instr); + + if(index < sizeof(DataRAM)) + DataRAM[index] = RAMB >> shift; +} + +template +static INLINE void Instr_RDRAM(uint32 instr) +{ + const size_t w = opcode & 0x3; + const unsigned shift = w << 3; + const size_t index = ((opcode & 0x4) ? (DPR + (instr & 0xFF)) : Accum) & 0xFFF; + + if(!(opcode & 0x4) && (instr & 0xFF)) + SNES_DBG("[CX4] RDRAM with non-zero lower instruction byte: 0x%04x\n", instr); + + if(index < sizeof(DataRAM)) + RAMB = (RAMB & ~(0xFF << shift)) | (DataRAM[index] << shift); +} + +template +static INLINE void Instr_RDROM(uint32 instr) +{ + const size_t index = (opcode & 0x4) ? (instr & 0x3FF) : (Accum & 0x3FF); + + if(!(opcode & 0x4) && (instr & 0xFF)) + SNES_DBG("[CX4] RDROM with non-zero lower instruction byte: 0x%04x\n", instr); + + ROMB = DataROM[index]; +} + +template +static INLINE void Instr_MUL(uint32 instr) +{ + const uint32 arg = (opcode & 0x4) ? (instr & 0xFF) : Regs[RegsRMap[instr & 0x7F]]; + uint64 result; + + result = (int64)sign_x_to_s32(24, Accum) * sign_x_to_s32(24, arg); + + //printf("MUL 0x%06x * 0x%06x -> 0x%16llx\n", Accum, arg, (unsigned long long)result); + + MACH = (result >> 24) & 0xFFFFFF; + MACL = result & 0xFFFFFF; +} + +template +static INLINE void Instr_BitOps(uint32 instr) +{ + const unsigned ss = opcode & 0x3; + uint32 arg = (opcode & 0x4) ? (instr & 0xFF) : Regs[RegsRMap[instr & 0x7F]]; + uint32 tmp = (Accum << preshift_tab[ss]) & 0xFFFFFF; + const unsigned subop = ((opcode - 0xA0) >> 3) & 0x07; + // + + if(subop & 0x4) + { + if(ss != 0) + SNES_DBG("[CX4] Shift instruction with SS!=0: 0x%04x\n", instr); + + arg &= 0x1F; + + if(arg >= 24) + SNES_DBG("[CX4] Instr 0x%04x, large shift=%u\n", instr, arg); + + if(arg > 24) + arg = 0; + } + + switch(subop) + { + case 0x0: tmp ^= ~arg; break; // XNOR + case 0x1: tmp ^= arg; break; // XOR + case 0x2: tmp &= arg; break; // AND + case 0x3: tmp |= arg; break; // OR + + case 0x4: tmp >>= arg; break; // SHLR + case 0x5: tmp = sign_x_to_s32(24, tmp) >> arg; break; // SHAR + case 0x6: tmp = (tmp >> arg) | (tmp << (24 - arg)); break; // ROTR + case 0x7: tmp <<= arg; break; // SHLL + } + // + Accum = tmp & 0xFFFFFF; + Flag_N = (bool)(Accum & 0x800000); + Flag_Z = !Accum; +} + + +template +static INLINE void Instr_CMP(uint32 instr) +{ + const unsigned ss = opcode & 0x3; + uint32 a = (Accum << preshift_tab[ss]) & 0xFFFFFF; + uint32 b = (opcode & 0x4) ? (instr & 0xFF) : Regs[RegsRMap[instr & 0x7F]]; + uint32 tmp; + + switch(((opcode - 0x48) >> 3) & 0x1) + { + case 0: tmp = b - a; + Flag_V = (((a ^ b) & (b ^ tmp)) >> 23) & 1; + Flag_C = (~tmp >> 24) & 1; + break; + + case 1: tmp = a - b; + Flag_V = (((a ^ b) & (a ^ tmp)) >> 23) & 1; + Flag_C = (~tmp >> 24) & 1; + break; + } + // + Flag_N = (bool)(tmp & 0x800000); + Flag_Z = !(tmp & 0xFFFFFF); +} + +template +static INLINE void Instr_ADDSUB(uint32 instr) +{ + const unsigned ss = opcode & 0x3; + uint32 a = (Accum << preshift_tab[ss]) & 0xFFFFFF; + uint32 b = (opcode & 0x4) ? (instr & 0xFF) : Regs[RegsRMap[instr & 0x7F]]; + uint32 tmp; + + switch((opcode >> 3) & 0x3) + { + case 0: tmp = a + b; + Flag_V = (((~(a ^ b)) & (a ^ tmp)) >> 23) & 1; + Flag_C = (tmp >> 24) & 1; + break; + + case 1: tmp = b - a; + Flag_V = (((a ^ b) & (b ^ tmp)) >> 23) & 1; + Flag_C = (~tmp >> 24) & 1; + break; + + case 2: tmp = a - b; + Flag_V = (((a ^ b) & (a ^ tmp)) >> 23) & 1; + Flag_C = (~tmp >> 24) & 1; + break; + } + // + Accum = tmp & 0xFFFFFF; + Flag_N = (bool)(Accum & 0x800000); + Flag_Z = !Accum; +} + +static NO_INLINE void Update(uint32 master_timestamp) +{ + { + int32 tmp; + + tmp = ((master_timestamp - last_master_timestamp) * clock_multiplier) + run_count_mod; + last_master_timestamp = master_timestamp; + run_count_mod = (uint16)tmp; + cycle_counter += tmp >> 16; + } + + if((Status & 0x141) != 0x40) // Not running + { + if(MDFN_UNLIKELY(Status & 0x100)) // DMA + { + while(cycle_counter > 0) + { + uint8 tmp; + + if(!DMALength) + { + Status &= ~0x100; + break; + } + + if(MDFN_UNLIKELY(!(DMASource & 0x8000))) + { + SNES_DBG("[CX4] Unhandled DMA source address: 0x%06x\n", DMASource); + Status &= ~0x100; + break; + } + + { + const unsigned bank = DMADest >> 16; + const unsigned offs = DMADest & 0xFFFF; + + if(MDFN_UNLIKELY((offs & 0x8000) || offs < 0x6000 || offs >= 0x7C00 || (bank & 0x40))) + { + SNES_DBG("[CX4] Unhandled DMA dest address: 0x%06x\n", DMADest); + Status &= ~0x100; + break; + } + } + + tmp = Cart.ROM[((DMASource & 0x7FFF) | ((DMASource >> 1) & 0x7F8000)) & (sizeof(Cart.ROM) - 1)]; + cycle_counter -= 1 + (WSControl >> 4); + { + const size_t index = DMADest & 0xFFF; + + if(index < sizeof(DataRAM)) + DataRAM[index] = tmp; + } + + //printf("DMA: %08x->%08x, %02x\n", DMASource, DMADest, tmp); + + DMADest = (DMADest + 1) & 0xFFFFFF; + DMASource = (DMASource + 1) & 0xFFFFFF; + DMALength--; + } + } + else + cycle_counter = 0; + } + + while(cycle_counter > 0) + { + const uint32 instr = (uint16)NextInstr; + + //printf("IP=%d:0x%02x, Instr=0x%04x (P=0x%04x) ;;; Accum=0x%06x, Flag_Z=%d, Flag_N=%d, Flag_C=%d, Flag_V=%d --- SP=0x%02x\n", (int)Cache_Active, IP, instr, P, Accum, Flag_Z, Flag_N, Flag_C, Flag_V, SP); + + NextInstr = Cache_Active->Data[NextIP]; + IP = (uint8)NextIP; + NextIP++; + + cycle_counter--; + + switch(instr >> 8) + { + default: + SNES_DBG("[CX4] Unknown instruction: 0x%04x\n", instr); + break; + + // + // NOP + // + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + { + // + } + break; + + // + // Branch + // + case 0x08: Instr_Branch<0x08>(instr); break; + case 0x09: Instr_Branch<0x09>(instr); break; + case 0x0A: Instr_Branch<0x0A>(instr); break; + case 0x0B: Instr_Branch<0x0B>(instr); break; + case 0x0C: Instr_Branch<0x0C>(instr); break; + case 0x0D: Instr_Branch<0x0D>(instr); break; + case 0x0E: Instr_Branch<0x0E>(instr); break; + case 0x0F: Instr_Branch<0x0F>(instr); break; + case 0x10: Instr_Branch<0x10>(instr); break; + case 0x11: Instr_Branch<0x11>(instr); break; + case 0x12: Instr_Branch<0x12>(instr); break; + case 0x13: Instr_Branch<0x13>(instr); break; + case 0x14: Instr_Branch<0x14>(instr); break; + case 0x15: Instr_Branch<0x15>(instr); break; + case 0x16: Instr_Branch<0x16>(instr); break; + case 0x17: Instr_Branch<0x17>(instr); break; + case 0x18: Instr_Branch<0x18>(instr); break; + case 0x19: Instr_Branch<0x19>(instr); break; + case 0x1A: Instr_Branch<0x1A>(instr); break; + case 0x1B: Instr_Branch<0x1B>(instr); break; + + case 0x1C: // TODO + break; + + // + // SKIP* + // + case 0x24: Instr_SKIP<0x24>(instr); break; + case 0x25: Instr_SKIP<0x25>(instr); break; + case 0x26: Instr_SKIP<0x26>(instr); break; + case 0x27: Instr_SKIP<0x27>(instr); break; + + // + // Branch (subroutine) + // + case 0x28: Instr_Branch<0x28>(instr); break; + case 0x29: Instr_Branch<0x29>(instr); break; + case 0x2A: Instr_Branch<0x2A>(instr); break; + case 0x2B: Instr_Branch<0x2B>(instr); break; + case 0x2C: Instr_Branch<0x2C>(instr); break; + case 0x2D: Instr_Branch<0x2D>(instr); break; + case 0x2E: Instr_Branch<0x2E>(instr); break; + case 0x2F: Instr_Branch<0x2F>(instr); break; + case 0x30: Instr_Branch<0x30>(instr); break; + case 0x31: Instr_Branch<0x31>(instr); break; + case 0x32: Instr_Branch<0x32>(instr); break; + case 0x33: Instr_Branch<0x33>(instr); break; + case 0x34: Instr_Branch<0x34>(instr); break; + case 0x35: Instr_Branch<0x35>(instr); break; + case 0x36: Instr_Branch<0x36>(instr); break; + case 0x37: Instr_Branch<0x37>(instr); break; + case 0x38: Instr_Branch<0x38>(instr); break; + case 0x39: Instr_Branch<0x39>(instr); break; + case 0x3A: Instr_Branch<0x3A>(instr); break; + case 0x3B: Instr_Branch<0x3B>(instr); break; + + // + // RTS + // + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + { + const uint32 tmp = Stack[SP]; + SP = (SP - 1) & 0x7; + + NextIP = (uint8)tmp; + NextInstr = 0; + CheckCache(tmp >> 8); + cycle_counter--; + } + break; + + // + // MAR++? + // + case 0x40: + case 0x41: + case 0x42: + case 0x43: + { + MAR = (MAR + 1) & 0xFFFFFF; + } + break; + + // + // CMP + // + case 0x48: Instr_CMP<0x48>(instr); break; + case 0x49: Instr_CMP<0x49>(instr); break; + case 0x4A: Instr_CMP<0x4A>(instr); break; + case 0x4B: Instr_CMP<0x4B>(instr); break; + case 0x4C: Instr_CMP<0x4C>(instr); break; + case 0x4D: Instr_CMP<0x4D>(instr); break; + case 0x4E: Instr_CMP<0x4E>(instr); break; + case 0x4F: Instr_CMP<0x4F>(instr); break; + case 0x50: Instr_CMP<0x50>(instr); break; + case 0x51: Instr_CMP<0x51>(instr); break; + case 0x52: Instr_CMP<0x52>(instr); break; + case 0x53: Instr_CMP<0x53>(instr); break; + case 0x54: Instr_CMP<0x54>(instr); break; + case 0x55: Instr_CMP<0x55>(instr); break; + case 0x56: Instr_CMP<0x56>(instr); break; + case 0x57: Instr_CMP<0x57>(instr); break; + + // + // Sign extension(8 bits) + // + case 0x59: + { + Accum = (int8)Accum & 0xFFFFFF; + Flag_N = (bool)(Accum & 0x800000); + Flag_Z = !Accum; + } + break; + + // + // Sign extension(16 bits) + // + case 0x5A: + { + Accum = (int16)Accum & 0xFFFFFF; + Flag_N = (bool)(Accum & 0x800000); + Flag_Z = !Accum; + } + break; + + // + // MOV + // + case 0x60: + { + const unsigned r = instr & 0x7F; + + Accum = Regs[RegsRMap[r]]; + } + break; + + // + // MOV + // + case 0x61: + { + const unsigned r = instr & 0x7F; + + if(r == 0x2E) + { + // Read cart ROM + //printf("MAR: %08x\n", MAR); + MBR = Cart.ROM[((MAR & 0x7FFF) | ((MAR >> 1) & 0x7F8000)) & (sizeof(Cart.ROM) - 1)]; + //MBR = Cart.ROM[MAR & (sizeof(Cart.ROM) - 1)]; + // MBR_ReadyDelay = + } + else if(r == 0x2F) + { + SNES_DBG("[CX4] Unhandled instruction: 0x%04x\n", instr); + } + else + MBR = Regs[RegsRMap[r]]; + } + break; + + // + // MOV + // + case 0x62: + { + MAR = Regs[RegsIndex_R0 + (instr & 0xF)]; + } + break; + + // + // MOV + // + case 0x63: + { + P = Regs[RegsIndex_R0 + (instr & 0xF)] & 0x7FFF; + } + break; + + // + // MOV + // + case 0x64: + { + Accum = instr & 0xFF; + } + break; + + // + // MOV + // + case 0x65: + { + MBR = instr & 0xFF; + } + break; + + // + // MOV + // + case 0x66: + { + MAR = instr & 0xFF; + } + break; + + // + // MOV + // + case 0x67: + { + P = instr & 0xFF; + } + break; + + // + // RDRAM + // + case 0x68: Instr_RDRAM<0x68>(instr); break; + case 0x69: Instr_RDRAM<0x69>(instr); break; + case 0x6A: Instr_RDRAM<0x6A>(instr); break; + case 0x6C: Instr_RDRAM<0x6C>(instr); break; + case 0x6D: Instr_RDRAM<0x6D>(instr); break; + case 0x6E: Instr_RDRAM<0x6E>(instr); break; + + // + // RDROM + // + case 0x70: Instr_RDROM<0x70>(instr); break; + case 0x71: Instr_RDROM<0x71>(instr); break; + case 0x72: Instr_RDROM<0x72>(instr); break; + case 0x73: Instr_RDROM<0x73>(instr); break; + case 0x74: Instr_RDROM<0x74>(instr); break; + case 0x75: Instr_RDROM<0x75>(instr); break; + case 0x76: Instr_RDROM<0x76>(instr); break; + case 0x77: Instr_RDROM<0x77>(instr); break; + + + // + // MOV + // + case 0x78: + case 0x7A: + { + P = (P & 0x7F00) | (Regs[RegsRMap[instr & 0x7F]] & 0xFF); + } + break; + + // + // MOV + // + case 0x79: + case 0x7B: + { + P = (P & 0xFF) | ((Regs[RegsRMap[instr & 0x7F]] & 0x7F) << 8); + } + break; + + // + // MOV + // + case 0x7C: + case 0x7E: + { + P = (P & 0x7F00) | (instr & 0xFF); + } + break; + + // + // MOV + // + case 0x7D: + case 0x7F: + { + P = (P & 0xFF) | ((instr & 0x7F) << 8); + } + break; + + // + // ADD/SUBR/SUB + // + case 0x80: Instr_ADDSUB<0x80>(instr); break; + case 0x81: Instr_ADDSUB<0x81>(instr); break; + case 0x82: Instr_ADDSUB<0x82>(instr); break; + case 0x83: Instr_ADDSUB<0x83>(instr); break; + case 0x84: Instr_ADDSUB<0x84>(instr); break; + case 0x85: Instr_ADDSUB<0x85>(instr); break; + case 0x86: Instr_ADDSUB<0x86>(instr); break; + case 0x87: Instr_ADDSUB<0x87>(instr); break; + case 0x88: Instr_ADDSUB<0x88>(instr); break; + case 0x89: Instr_ADDSUB<0x89>(instr); break; + case 0x8A: Instr_ADDSUB<0x8A>(instr); break; + case 0x8B: Instr_ADDSUB<0x8B>(instr); break; + case 0x8C: Instr_ADDSUB<0x8C>(instr); break; + case 0x8D: Instr_ADDSUB<0x8D>(instr); break; + case 0x8E: Instr_ADDSUB<0x8E>(instr); break; + case 0x8F: Instr_ADDSUB<0x8F>(instr); break; + case 0x90: Instr_ADDSUB<0x90>(instr); break; + case 0x91: Instr_ADDSUB<0x91>(instr); break; + case 0x92: Instr_ADDSUB<0x92>(instr); break; + case 0x93: Instr_ADDSUB<0x93>(instr); break; + case 0x94: Instr_ADDSUB<0x94>(instr); break; + case 0x95: Instr_ADDSUB<0x95>(instr); break; + case 0x96: Instr_ADDSUB<0x96>(instr); break; + case 0x97: Instr_ADDSUB<0x97>(instr); break; + + // + // MUL + // + case 0x98: Instr_MUL<0x98>(instr); break; + case 0x99: Instr_MUL<0x99>(instr); break; + case 0x9A: Instr_MUL<0x9A>(instr); break; + case 0x9B: Instr_MUL<0x9B>(instr); break; + case 0x9C: Instr_MUL<0x9C>(instr); break; + case 0x9D: Instr_MUL<0x9D>(instr); break; + case 0x9E: Instr_MUL<0x9E>(instr); break; + case 0x9F: Instr_MUL<0x9F>(instr); break; + + // + // Bit ops + // + case 0xA0: Instr_BitOps<0xA0>(instr); break; + case 0xA1: Instr_BitOps<0xA1>(instr); break; + case 0xA2: Instr_BitOps<0xA2>(instr); break; + case 0xA3: Instr_BitOps<0xA3>(instr); break; + case 0xA4: Instr_BitOps<0xA4>(instr); break; + case 0xA5: Instr_BitOps<0xA5>(instr); break; + case 0xA6: Instr_BitOps<0xA6>(instr); break; + case 0xA7: Instr_BitOps<0xA7>(instr); break; + case 0xA8: Instr_BitOps<0xA8>(instr); break; + case 0xA9: Instr_BitOps<0xA9>(instr); break; + case 0xAA: Instr_BitOps<0xAA>(instr); break; + case 0xAB: Instr_BitOps<0xAB>(instr); break; + case 0xAC: Instr_BitOps<0xAC>(instr); break; + case 0xAD: Instr_BitOps<0xAD>(instr); break; + case 0xAE: Instr_BitOps<0xAE>(instr); break; + case 0xAF: Instr_BitOps<0xAF>(instr); break; + case 0xB0: Instr_BitOps<0xB0>(instr); break; + case 0xB1: Instr_BitOps<0xB1>(instr); break; + case 0xB2: Instr_BitOps<0xB2>(instr); break; + case 0xB3: Instr_BitOps<0xB3>(instr); break; + case 0xB4: Instr_BitOps<0xB4>(instr); break; + case 0xB5: Instr_BitOps<0xB5>(instr); break; + case 0xB6: Instr_BitOps<0xB6>(instr); break; + case 0xB7: Instr_BitOps<0xB7>(instr); break; + case 0xB8: Instr_BitOps<0xB8>(instr); break; + case 0xB9: Instr_BitOps<0xB9>(instr); break; + case 0xBA: Instr_BitOps<0xBA>(instr); break; + case 0xBB: Instr_BitOps<0xBB>(instr); break; + case 0xBC: Instr_BitOps<0xBC>(instr); break; + case 0xBD: Instr_BitOps<0xBD>(instr); break; + case 0xBE: Instr_BitOps<0xBE>(instr); break; + case 0xBF: Instr_BitOps<0xBF>(instr); break; + case 0xC0: Instr_BitOps<0xC0>(instr); break; + case 0xC1: Instr_BitOps<0xC1>(instr); break; + case 0xC2: Instr_BitOps<0xC2>(instr); break; + case 0xC3: Instr_BitOps<0xC3>(instr); break; + case 0xC4: Instr_BitOps<0xC4>(instr); break; + case 0xC5: Instr_BitOps<0xC5>(instr); break; + case 0xC6: Instr_BitOps<0xC6>(instr); break; + case 0xC7: Instr_BitOps<0xC7>(instr); break; + case 0xC8: Instr_BitOps<0xC8>(instr); break; + case 0xC9: Instr_BitOps<0xC9>(instr); break; + case 0xCA: Instr_BitOps<0xCA>(instr); break; + case 0xCB: Instr_BitOps<0xCB>(instr); break; + case 0xCC: Instr_BitOps<0xCC>(instr); break; + case 0xCD: Instr_BitOps<0xCD>(instr); break; + case 0xCE: Instr_BitOps<0xCE>(instr); break; + case 0xCF: Instr_BitOps<0xCF>(instr); break; + case 0xD0: Instr_BitOps<0xD0>(instr); break; + case 0xD1: Instr_BitOps<0xD1>(instr); break; + case 0xD2: Instr_BitOps<0xD2>(instr); break; + case 0xD3: Instr_BitOps<0xD3>(instr); break; + case 0xD4: Instr_BitOps<0xD4>(instr); break; + case 0xD5: Instr_BitOps<0xD5>(instr); break; + case 0xD6: Instr_BitOps<0xD6>(instr); break; + case 0xD7: Instr_BitOps<0xD7>(instr); break; + case 0xD8: Instr_BitOps<0xD8>(instr); break; + case 0xD9: Instr_BitOps<0xD9>(instr); break; + case 0xDA: Instr_BitOps<0xDA>(instr); break; + case 0xDB: Instr_BitOps<0xDB>(instr); break; + case 0xDC: Instr_BitOps<0xDC>(instr); break; + case 0xDD: Instr_BitOps<0xDD>(instr); break; + case 0xDE: Instr_BitOps<0xDE>(instr); break; + case 0xDF: Instr_BitOps<0xDF>(instr); break; + + + // + // MOV + // + case 0xE0: + { + const unsigned r = instr & 0x7F; + + Regs[RegsWMap[r]] = Accum & RegsWMask[r]; + } + break; + + // + // MOV + // + case 0xE1: + { + const unsigned r = instr & 0x7F; + + if(r == 0x2E || r == 0x2F) + { + SNES_DBG("[CX4] Unhandled instruction: 0x%04x\n", instr); + } + + Regs[RegsWMap[r]] = Regs[RegsIndex_MBR] & RegsWMask[r]; + } + break; + + // + // WRRAM + // + case 0xE8: Instr_WRRAM<0xE8>(instr); break; + case 0xE9: Instr_WRRAM<0xE9>(instr); break; + case 0xEA: Instr_WRRAM<0xEA>(instr); break; + case 0xEC: Instr_WRRAM<0xEC>(instr); break; + case 0xED: Instr_WRRAM<0xED>(instr); break; + case 0xEE: Instr_WRRAM<0xEE>(instr); break; + + // + // SWAP + // + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + { + //printf("SWAP: %04x\n", instr); + std::swap(Accum, Regs[RegsIndex_R0 + (instr & 0xF)]); + } + break; + + // + // Clear + // + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + { + Accum = 0; + RAMB = 0; + DPR = 0; + P = 0; + } + break; + + // + // Halt + // + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + { + Status &= ~0x40; + cycle_counter = std::min(cycle_counter, 0); + } + break; + } + } +} + +static uint32 EventHandler(uint32 timestamp) +{ + Update(timestamp); + + return SNES_EVENT_MAXTS; +} + +static void AdjustTS(int32 delta) +{ + last_master_timestamp += delta; +} + +static DEFREAD(MainCPU_ReadRAM) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + if(MDFN_UNLIKELY((Status & 0x41) == 0x40)) + { + SNES_DBG("[CX4] MainCPU read from data RAM while CX4 busy: 0x%06x\n", A); + return 0xFF; + } + else + return DataRAM[A & 0xFFF]; +} + +static DEFWRITE(MainCPU_WriteRAM) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + //printf("MainCPU_WriteRAM: %03x %02x\n", A & 0xFFF, V); + if(MDFN_UNLIKELY((Status & 0x41) == 0x40)) + SNES_DBG("[CX4] MainCPU write to data RAM while CX4 busy: 0x%06x 0x%02x\n", A, V); + else + DataRAM[A & 0xFFF] = V; +} + +static DEFREAD(MainCPU_ReadGPR) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + if(MDFN_UNLIKELY((Status & 0x41) == 0x40)) + { + SNES_DBG("[CX4] MainCPU read from GPR while CX4 busy: 0x%06x\n", A); + return 0xFF; + } + else + { + const unsigned index = (A & 0x3F) / 3; + const unsigned shift = ((A & 0x3F) % 3) << 3; + + return Regs[RegsIndex_R0 + index] >> shift; + } +} + +static DEFWRITE(MainCPU_WriteGPR) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + if(MDFN_UNLIKELY((Status & 0x41) == 0x40)) + { + SNES_DBG("[CX4] MainCPU write to GPR while CX4 busy: 0x%06x 0x%02x\n", A, V); + } + else + { + const unsigned index = (A & 0x3F) / 3; + const unsigned shift = ((A & 0x3F) % 3) << 3; + uint32 &r = Regs[RegsIndex_R0 + index]; + + r = (r & ~(0xFF << shift)) | (V << shift); + //printf("WriteGPR: A=0x%06x, V=0x%02x, index=%d, shift=%d, r=0x%06x\n", A, V, index, shift, r); + } +} + + +static DEFREAD(MainCPU_ReadZero) +{ + CPUM.timestamp += MEMCYC_SLOW; + // + return 0; +} + +static DEFWRITE(MainCPU_WriteCachePage) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + Cache_Active = &Cache[V & 1]; + LoadCache(P); +} + +static DEFREAD(MainCPU_ReadCachePage) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + return Cache_Active - &Cache[0]; +} + +static DEFWRITE(MainCPU_WriteCacheLock) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + Cache[0].Locked = (V >> 0) & 1; + Cache[1].Locked = (V >> 1) & 1; +} + +static DEFREAD(MainCPU_ReadCacheLock) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + return Cache[0].Locked | (Cache[1].Locked << 1); +} + +static DEFWRITE(MainCPU_WriteProgROMBase) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + const unsigned shift = ((A & 0x3) - 1) << 3; + + ProgROM_Base = (ProgROM_Base & ~(0xFF << shift)) | (V << shift); +} + +static DEFREAD(MainCPU_ReadProgROMBase) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + const unsigned shift = ((A & 0x3) - 1) << 3; + + return ProgROM_Base >> shift; +} + +static DEFWRITE(MainCPU_WriteProgROMPage) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + const unsigned shift = ((A & 0x1) ^ 1) << 3; + + P = ((P & ~(0xFF << shift)) | (V << shift)) & 0x7FFF; +} + +static DEFREAD(MainCPU_ReadProgROMPage) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + const unsigned shift = ((A & 0x1) ^ 1) << 3; + + return P >> shift; +} + +static DEFWRITE(MainCPU_WriteIP) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + SNES_DBG("[CX4] Command 0x%04x:0x%02x\n", P, V); + NextIP = IP = V; + NextInstr = 0; + Status |= 0x40; + LoadCache(P); +} + +static DEFREAD(MainCPU_ReadIP) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + return IP; +} + +template +static DEFWRITE(MainCPU_WriteDMARegs) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + if(w <= 2) + { + const unsigned shift = (w & 3) << 3; + DMASource = (DMASource & ~(0xFF << shift)) | (V << shift); + } + else if(w <= 4) + { + const unsigned shift = ((w - 3) & 1) << 3; + DMALength = (DMALength & ~(0xFF << shift)) | (V << shift); + } + else + { + const unsigned shift = ((w - 5) & 3) << 3; + + DMADest = (DMADest & ~(0xFF << shift)) | (V << shift); + + if(w == 7) + Status |= 0x100; + } +} + +template +static DEFREAD(MainCPU_ReadDMARegs) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + if(w <= 2) + return DMASource >> ((w & 3) << 3); + else if(w <= 4) + return DMALength >> (((w - 2) & 1) << 3); + else + return DMADest >> (((w - 5) & 3) << 3); +} + +static DEFWRITE(MainCPU_WriteWSControl) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + WSControl = V & 0x77; +} + +static DEFREAD(MainCPU_ReadWSControl) +{ + CPUM.timestamp += MEMCYC_SLOW; + // + return WSControl; +} + +static DEFWRITE(MainCPU_WriteIRQControl) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + IRQControl = V & 1; +} + +static DEFREAD(MainCPU_ReadIRQControl) +{ + CPUM.timestamp += MEMCYC_SLOW; + // + return IRQControl; +} + +static DEFREAD(MainCPU_ReadROMConfig) +{ + CPUM.timestamp += MEMCYC_SLOW; + // + return 0x00; //TODO/FIXME? +} + +static DEFREAD(MainCPU_ReadStatus) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + return Status; +} + +static DEFWRITE(MainCPU_ClearSuspend) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + Status &= ~0x01; +} + +static DEFWRITE(MainCPU_ClearStatusIRQ) +{ + CPUM.timestamp += MEMCYC_SLOW; + Update(CPUM.timestamp); + // + // TODO/FIXME + //Status &= ~ +} + +static DEFWRITE(MainCPU_WriteVectorReg) +{ + CPUM.timestamp += MEMCYC_SLOW; + // + const unsigned shift = (A & 1) << 3; + uint16& vr = VectorRegs[(A >> 1) & 0xF]; + + vr = (vr & ~(0xFF << shift)) | (V << shift); +} + +static DEFREAD(MainCPU_ReadVectorReg) +{ + CPUM.timestamp += MEMCYC_SLOW; + // + const unsigned shift = (A & 1) << 3; + const uint16& vr = VectorRegs[(A >> 1) & 0xF]; + + return vr >> shift; +} + +static MDFN_COLD void Reset(bool powering_up) +{ + memset(DataRAM, 0x00, sizeof(DataRAM)); + + Regs[RegsIndex_A] = 0xFFFFFF; + Regs[RegsIndex_MACH] = 0; + Regs[RegsIndex_MACL] = 0; + Regs[RegsIndex_MBR] = 0; + Regs[RegsIndex_ROMB] = 0; + Regs[RegsIndex_RAMB] = 0; + Regs[RegsIndex_MAR] = 0; + Regs[RegsIndex_DPR] = 0; + Regs[RegsIndex_IP] = 0; + Regs[RegsIndex_P] = 0; + + for(unsigned i = 0; i < 16; i++) + Regs[RegsIndex_R0 + i] = 0; + + Regs[RegsIndex_NextIP] = 0; + Regs[RegsIndex_WriteDummy] = 0; + + Flag_Z = false; + Flag_N = false; + Flag_C = false; + Flag_V = false; + + memset(Stack, 0, sizeof(Stack)); + SP = 0; + + NextInstr = 0; + for(unsigned i = 0; i < 2; i++) + { + memset(Cache[i].Data, 0, sizeof(Cache[i].Data)); + Cache[i].Data[0x100] = 0xFC00; + Cache[i].Data[0x101] = 0xFC00; + Cache[i].Tag = ~0U; + Cache[i].Locked = false; + } + Cache_Active = &Cache[0]; + ProgROM_Base = 0; + + DMASource = 0; + DMALength = 0; + DMADest = 0; + + Status = 0; + IRQOut = false; + WSControl = 0; + IRQControl = 0; + + for(unsigned i = 0; i < 0x10; i++) + VectorRegs[i] = 0; + + cycle_counter = 0; + + if(powering_up) + run_count_mod = 0; +} + +static void StateAction(StateMem* sm, const unsigned load, const bool data_only) +{ + bool lca = Cache_Active - Cache; + + SFORMAT StateRegs[] = + { + SFVAR(DataRAM), + + SFVARN(Regs[RegsIndex_A], "A"), + SFVARN(Regs[RegsIndex_MACH], "MACH"), + SFVARN(Regs[RegsIndex_MACL], "MACL"), + SFVARN(Regs[RegsIndex_MBR], "MBR"), + SFVARN(Regs[RegsIndex_ROMB], "ROMB"), + SFVARN(Regs[RegsIndex_RAMB], "RAMB"), + SFVARN(Regs[RegsIndex_MAR], "MAR"), + SFVARN(Regs[RegsIndex_DPR], "DPR"), + SFVARN(Regs[RegsIndex_IP], "IP"), + SFVARN(Regs[RegsIndex_P], "P"), + + SFPTR32N(&Regs[RegsIndex_R0], 16, "R"), + + SFVARN(Regs[RegsIndex_NextIP], "NextIP"), + + SFVAR(Flag_Z), + SFVAR(Flag_N), + SFVAR(Flag_C), + SFVAR(Flag_V), + + SFVAR(Stack), + SFVAR(SP), + + SFVAR(NextInstr), + SFVAR(Cache->Data, 2, sizeof(*Cache), Cache), + SFVAR(Cache->Tag, 2, sizeof(*Cache), Cache), + SFVAR(Cache->Locked, 2, sizeof(*Cache), Cache), + SFVARN(lca, "Cache_Active"), + SFVAR(ProgROM_Base), + + SFVAR(DMASource), + SFVAR(DMALength), + SFVAR(DMADest), + + SFVAR(Status), + SFVAR(IRQOut), + SFVAR(WSControl), + SFVAR(IRQControl), + + SFVAR(VectorRegs), + + SFVAR(cycle_counter), + + SFVAR(run_count_mod), + + // + SFEND + }; + + MDFNSS_StateAction(sm, load, data_only, StateRegs, "CX4"); + + if(load) + { + Cache_Active = &Cache[lca]; + NextIP = std::min(0x101, NextIP); + } +} + +void CART_CX4_Init(const int32 master_clock, const int32 ocmultiplier) +{ + for(unsigned bank = 0x00; bank < 0x100; bank++) + { + if(!(bank & 0x40)) + { + Set_A_Handlers((bank << 16) | 0x6000, (bank << 16) | 0x6BFF, MainCPU_ReadRAM, MainCPU_WriteRAM); + Set_A_Handlers((bank << 16) | 0x7000, (bank << 16) | 0x7BFF, MainCPU_ReadRAM, MainCPU_WriteRAM); + + Set_A_Handlers((bank << 16) | 0x7F40, MainCPU_ReadDMARegs<0>, MainCPU_WriteDMARegs<0>); + Set_A_Handlers((bank << 16) | 0x7F41, MainCPU_ReadDMARegs<1>, MainCPU_WriteDMARegs<1>); + Set_A_Handlers((bank << 16) | 0x7F42, MainCPU_ReadDMARegs<2>, MainCPU_WriteDMARegs<2>); + Set_A_Handlers((bank << 16) | 0x7F43, MainCPU_ReadDMARegs<3>, MainCPU_WriteDMARegs<3>); + Set_A_Handlers((bank << 16) | 0x7F44, MainCPU_ReadDMARegs<4>, MainCPU_WriteDMARegs<4>); + Set_A_Handlers((bank << 16) | 0x7F45, MainCPU_ReadDMARegs<5>, MainCPU_WriteDMARegs<5>); + Set_A_Handlers((bank << 16) | 0x7F46, MainCPU_ReadDMARegs<6>, MainCPU_WriteDMARegs<6>); + Set_A_Handlers((bank << 16) | 0x7F47, MainCPU_ReadDMARegs<7>, MainCPU_WriteDMARegs<7>); + Set_A_Handlers((bank << 16) | 0x7F48, MainCPU_ReadCachePage, MainCPU_WriteCachePage); + Set_A_Handlers((bank << 16) | 0x7F49, (bank << 16) | 0x7F4B, MainCPU_ReadProgROMBase, MainCPU_WriteProgROMBase); + Set_A_Handlers((bank << 16) | 0x7F4C, MainCPU_ReadCacheLock, MainCPU_WriteCacheLock); + Set_A_Handlers((bank << 16) | 0x7F4D, (bank << 16) | 0x7F4E, MainCPU_ReadProgROMPage, MainCPU_WriteProgROMPage); + Set_A_Handlers((bank << 16) | 0x7F4F, MainCPU_ReadIP, MainCPU_WriteIP); + Set_A_Handlers((bank << 16) | 0x7F50, MainCPU_ReadWSControl, MainCPU_WriteWSControl); + Set_A_Handlers((bank << 16) | 0x7F51, MainCPU_ReadIRQControl, MainCPU_WriteIRQControl); + Set_A_Handlers((bank << 16) | 0x7F52, MainCPU_ReadROMConfig, OBWrite_SLOW); //MainCPU_WriteROMConfig); + + Set_A_Handlers((bank << 16) | 0x7F53, MainCPU_ReadStatus, OBWrite_SLOW); // MainCPU_WriteForceIdle + Set_A_Handlers((bank << 16) | 0x7F54, MainCPU_ReadStatus, OBWrite_SLOW); + Set_A_Handlers((bank << 16) | 0x7F55, MainCPU_ReadStatus, OBWrite_SLOW); // MainCPU_WriteSuspend + Set_A_Handlers((bank << 16) | 0x7F56, MainCPU_ReadStatus, OBWrite_SLOW); // MainCPU_WriteSuspend + Set_A_Handlers((bank << 16) | 0x7F57, MainCPU_ReadStatus, OBWrite_SLOW); // MainCPU_WriteSuspend + Set_A_Handlers((bank << 16) | 0x7F58, MainCPU_ReadZero, OBWrite_SLOW); // MainCPU_WriteSuspend + Set_A_Handlers((bank << 16) | 0x7F59, MainCPU_ReadStatus, OBWrite_SLOW); // MainCPU_WriteSuspend + Set_A_Handlers((bank << 16) | 0x7F5A, MainCPU_ReadZero, OBWrite_SLOW); // MainCPU_WriteSuspend + Set_A_Handlers((bank << 16) | 0x7F5B, MainCPU_ReadStatus, OBWrite_SLOW); // MainCPU_WriteSuspend + Set_A_Handlers((bank << 16) | 0x7F5C, MainCPU_ReadStatus, OBWrite_SLOW); // MainCPU_WriteSuspend + Set_A_Handlers((bank << 16) | 0x7F5D, MainCPU_ReadStatus, MainCPU_ClearSuspend); + Set_A_Handlers((bank << 16) | 0x7F5E, MainCPU_ReadStatus, MainCPU_ClearStatusIRQ); + Set_A_Handlers((bank << 16) | 0x7F5F, MainCPU_ReadStatus, OBWrite_SLOW); + Set_A_Handlers((bank << 16) | 0x7F60, (bank << 16) | 0x7F7F, MainCPU_ReadVectorReg, MainCPU_WriteVectorReg); + + Set_A_Handlers((bank << 16) | 0x7F80, (bank << 16) | 0x7FAF, MainCPU_ReadGPR, MainCPU_WriteGPR); + Set_A_Handlers((bank << 16) | 0x7FB0, (bank << 16) | 0x7FBF, MainCPU_ReadZero, OBWrite_SLOW); + Set_A_Handlers((bank << 16) | 0x7FC0, (bank << 16) | 0x7FEF, MainCPU_ReadGPR, MainCPU_WriteGPR); + Set_A_Handlers((bank << 16) | 0x7FF0, (bank << 16) | 0x7FFF, MainCPU_ReadZero, OBWrite_SLOW); + } + } + // + // + // + last_master_timestamp = 0; + clock_multiplier = ((int64)ocmultiplier * 20000000 * 2 + master_clock) / (master_clock * 2); + + memset(RegsRMap, RegsIndex_IR0, sizeof(RegsRMap)); + memset(RegsWMap, RegsIndex_WriteDummy, sizeof(RegsWMap)); + + for(unsigned i = 0; i < 0x80; i++) + RegsWMask[i] = 0; + + RegsRMap[0x00] = RegsWMap[0x00] = RegsIndex_A; + RegsWMask[0x00] = 0xFFFFFF; + + RegsRMap[0x01] = RegsIndex_MACH; + RegsRMap[0x02] = RegsIndex_MACL; + RegsRMap[0x03] = RegsWMap[0x03] = RegsIndex_MBR; + RegsWMask[0x03] = 0xFF; + + RegsRMap[0x08] = RegsIndex_ROMB; + RegsRMap[0x0C] = RegsIndex_RAMB; + RegsWMap[0x0C] = RegsIndex_RAMB; + RegsWMask[0x0C] = 0xFFFFFF; + + RegsRMap[0x13] = RegsWMap[0x13] = RegsIndex_MAR; + RegsWMask[0x13] = 0xFFFFFF; + + RegsRMap[0x1C] = RegsWMap[0x1C] = RegsIndex_DPR; + RegsWMask[0x1C] = 0xFFF; + + RegsRMap[0x20] = RegsIndex_IP; + RegsWMap[0x20] = RegsIndex_NextIP; + RegsWMask[0x20] = 0xFF; + + RegsRMap[0x28] = RegsWMap[0x28] = RegsIndex_P; + RegsWMask[0x28] = 0x7FFF; + + for(unsigned i = 0; i < 0x10; i++) + { + static const uint32 ctab[16] = + { + 0x000000, 0xFFFFFF, 0x00FF00, 0xFF0000, 0x00FFFF, 0xFFFF00, 0x800000, 0x7FFFFF, + 0x008000, 0x007FFF, 0xFF7FFF, 0xFFFF7F, 0x010000, 0xFEFFFF, 0x000100, 0x00FEFF + }; + Regs[RegsIndex_IR0 + i] = ctab[i]; + RegsRMap[0x50 + i] = RegsIndex_IR0 + i; + } + + for(unsigned i = 0x60; i < 0x80; i++) + { + RegsRMap[i] = RegsWMap[i] = RegsIndex_R0 + (i & 0xF); + RegsWMask[i] = 0xFFFFFF; + } + // + // + // + Cart.AdjustTS = AdjustTS; + Cart.EventHandler = EventHandler; + Cart.Reset = Reset; + Cart.StateAction = StateAction; +} + + + +} diff --git a/mednafen/snes_faust/cart/cx4.h b/mednafen/snes_faust/cart/cx4.h new file mode 100644 index 0000000..cba072e --- /dev/null +++ b/mednafen/snes_faust/cart/cx4.h @@ -0,0 +1,32 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* cx4.h: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __MDFN_SNES_FAUST_CART_CX4_H +#define __MDFN_SNES_FAUST_CART_CX4_H + +namespace MDFN_IEN_SNES_FAUST +{ + +// ocmultiplier, 8.16 fixed point +void CART_CX4_Init(const int32 master_clock, const int32 ocmultiplier) MDFN_COLD; + +} +#endif diff --git a/mednafen/snes_faust/cart/dsp1-datarom-synth.h b/mednafen/snes_faust/cart/dsp1-datarom-synth.h new file mode 100644 index 0000000..1a945c0 --- /dev/null +++ b/mednafen/snes_faust/cart/dsp1-datarom-synth.h @@ -0,0 +1,64 @@ +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, +16384, 32767, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 1, 8, 4, 2, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 32767, 32514, 32264, 32018, 31775, 31536, 31301, 31069, 30840, 30615, 30394, +30175, 29959, 29747, 29537, 29331, 29127, 28926, 28728, 28533, 28340, 28150, 27962, 27777, 27594, 27414, 27236, +27060, 26887, 26715, 26546, 26379, 26214, 26052, 25891, 25732, 25575, 25420, 25267, 25116, 24966, 24818, 24672, +24528, 24385, 24245, 24105, 23967, 23831, 23697, 23564, 23432, 23302, 23173, 23046, 22920, 22795, 22672, 22550, +22429, 22310, 22192, 22075, 21960, 21845, 21732, 21620, 21509, 21400, 21291, 21183, 21077, 20972, 20867, 20764, +20662, 20560, 20460, 20361, 20262, 20165, 20068, 19973, 19878, 19784, 19692, 19600, 19508, 19418, 19329, 19240, +19152, 19065, 18979, 18893, 18809, 18725, 18641, 18559, 18477, 18396, 18316, 18236, 18157, 18079, 18001, 17924, +17848, 17772, 17697, 17623, 17549, 17476, 17404, 17332, 17261, 17190, 17120, 17050, 16981, 16913, 16845, 16777, +16710, 16644, 16578, 16513, 16448, 16383, 16887, 17377, 17853, 18317, 18769, 19211, 19643, 20065, 20479, 20884, +21282, 21673, 22056, 22434, 22804, 23169, 23529, 23882, 24231, 24575, 24914, 25248, 25578, 25904, 26226, 26544, +26858, 27168, 27475, 27779, 28079, 28377, 28671, 28962, 29250, 29535, 29818, 30098, 30375, 30650, 30923, 31193, +31461, 31726, 31989, 32250, 32510, 32767, 32, 64, 0, 804, 1607, 2410, 3211, 4011, 4808, 5602, +6392, 7179, 7961, 8739, 9512, 10278, 11039, 11793, 12539, 13278, 14010, 14732, 15446, 16151, 16846, 17530, +18204, 18868, 19519, 20159, 20787, 21403, 22005, 22594, 23170, 23732, 24279, 24812, 25330, 25832, 26319, 26790, +27245, 27684, 28106, 28511, 28898, 29269, 29621, 29956, 30273, 30572, 30852, 31114, 31357, 31581, 31785, 31971, +32138, 32285, 32413, 32521, 32610, 32679, 32728, 32758, 32767, 32758, 32728, 32679, 32610, 32521, 32413, 32285, +32138, 31971, 31785, 31581, 31357, 31114, 30852, 30572, 30273, 29956, 29621, 29269, 28898, 28511, 28106, 27684, +27245, 26790, 26319, 25832, 25330, 24812, 24279, 23732, 23170, 22594, 22005, 21403, 20787, 20159, 19519, 18868, +18204, 17530, 16846, 16151, 15446, 14732, 14010, 13278, 12539, 11793, 11039, 10278, 9512, 8739, 7961, 7179, +6392, 5602, 4808, 4011, 3211, 2410, 1607, 804, 32767, 32758, 32728, 32679, 32610, 32521, 32413, 32285, +32138, 31971, 31785, 31581, 31357, 31114, 30852, 30572, 30273, 29956, 29621, 29269, 28898, 28511, 28106, 27684, +27245, 26790, 26319, 25832, 25330, 24812, 24279, 23732, 23170, 22594, 22005, 21403, 20787, 20159, 19519, 18868, +18204, 17530, 16846, 16151, 15446, 14732, 14010, 13278, 12539, 11793, 11039, 10278, 9512, 8739, 7961, 7179, +6392, 5602, 4808, 4011, 3211, 2410, 1607, 804, 0, -804, -1607, -2410, -3211, -4011, -4808, -5602, +-6392, -7179, -7961, -8739, -9512, -10278, -11039, -11793, -12539, -13278, -14010, -14732, -15446, -16151, -16846, -17530, +-18204, -18868, -19519, -20159, -20787, -21403, -22005, -22594, -23170, -23732, -24279, -24812, -25330, -25832, -26319, -26790, +-27245, -27684, -28106, -28511, -28898, -29269, -29621, -29956, -30273, -30572, -30852, -31114, -31357, -31581, -31785, -31971, +-32138, -32285, -32413, -32521, -32610, -32679, -32728, -32758, 0, 0, 0, 0, 0, 0, 16384, 16343, +16303, 16262, 16221, 16180, 16140, 16099, 16058, 16017, 15976, 15936, 15895, 15854, 15813, 15772, 15732, 15691, +15650, 15609, 15568, 15527, 15487, 15446, 15405, 15364, 15323, 15282, 15241, 15200, 15159, 15118, 15077, 15036, +14995, 14953, 14912, 14871, 14830, 14789, 14748, 14706, 14665, 14624, 14582, 14541, 14500, 14458, 14417, 14375, +14334, 14292, 14250, 14209, 14167, 14125, 14084, 14042, 14000, 13958, 13916, 13874, 13833, 13791, 13748, 13706, +13664, 13622, 13580, 13537, 13495, 13453, 13410, 13368, 13325, 13283, 13240, 13197, 13155, 13112, 13069, 13026, +12983, 12940, 12897, 12854, 12811, 12767, 12724, 12680, 12637, 12593, 12550, 12506, 12462, 12419, 12375, 12331, +12287, 12242, 12198, 12154, 12109, 12065, 12020, 11976, 11931, 11886, 11841, 11796, 11751, 11706, 11661, 11616, +11570, 11525, 11479, 11433, 11387, 11341, 11295, 11249, 11203, 11156, 11110, 11063, 11017, 10970, 10923, 10876, +10828, 10781, 10733, 10686, 10638, 10590, 10542, 10494, 10446, 10397, 10349, 10300, 10251, 10202, 10153, 10103, +10054, 10004, 9954, 9904, 9854, 9804, 9753, 9703, 9652, 9601, 9549, 9498, 9446, 9394, 9342, 9290, +9237, 9185, 9132, 9078, 9025, 8971, 8918, 8863, 8809, 8754, 8700, 8644, 8589, 8533, 8477, 8421, +8365, 8308, 8251, 8193, 8135, 8077, 8019, 7960, 7901, 7841, 7782, 7721, 7661, 7600, 7538, 7477, +7414, 7352, 7289, 7225, 7161, 7096, 7031, 6966, 6900, 6833, 6766, 6698, 6630, 6561, 6492, 6421, +6350, 6279, 6207, 6133, 6060, 5985, 5909, 5833, 5756, 5678, 5599, 5518, 5437, 5355, 5271, 5186, +5100, 5013, 4924, 4834, 4742, 4648, 4553, 4455, 4356, 4254, 4150, 4044, 3935, 3823, 3707, 3588, +3465, 3338, 3206, 3069, 2925, 2774, 2614, 2445, 2263, 2065, 1846, 1598, 1305, 922, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 25736, 0, 0, 0, 0, 0, 0, +0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, diff --git a/mednafen/snes_faust/cart/dsp1.cpp b/mednafen/snes_faust/cart/dsp1.cpp new file mode 100644 index 0000000..e0ec504 --- /dev/null +++ b/mednafen/snes_faust/cart/dsp1.cpp @@ -0,0 +1,180 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* dsp1.cpp: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "common.h" +#include "dsp1.h" +//#include "../ppu.h" +//#include + +namespace MDFN_IEN_SNES_FAUST +{ + +#include "dsp1chip.h" +static DSP1Chip DSP; + +static uint32 last_master_timestamp; +static unsigned run_count_mod; +static unsigned clock_multiplier; + +static NO_INLINE void Update(uint32 master_timestamp) +{ + int32 tmp; + + tmp = ((master_timestamp - last_master_timestamp) * clock_multiplier) + run_count_mod; + last_master_timestamp = master_timestamp; + run_count_mod = (uint16)tmp; + + DSP.Run(tmp >> 16); +} + +template +static DEFREAD(MainCPU_ReadDR) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += (cyc >= 0) ? cyc : (MemSelect ? MEMCYC_FAST : MEMCYC_SLOW); + } + // + // + Update(CPUM.timestamp); + + return DSP.ReadData(); +} + +template +static DEFWRITE(MainCPU_WriteDR) +{ + CPUM.timestamp += (cyc >= 0) ? cyc : (MemSelect ? MEMCYC_FAST : MEMCYC_SLOW); + // + // + Update(CPUM.timestamp); + + DSP.WriteData(V); +} + +template +static DEFREAD(MainCPU_ReadSR) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += (cyc >= 0) ? cyc : (MemSelect ? MEMCYC_FAST : MEMCYC_SLOW); + } + // + // + // + Update(CPUM.timestamp); + + return DSP.ReadStatus(); +} + +static void AdjustTS(int32 delta) +{ + + +} + +static uint32 EventHandler(uint32 timestamp) +{ + //DSP. + return timestamp + 10000; +} + +static MDFN_COLD void Reset(bool powering_up) +{ + DSP.Reset(powering_up); + + if(powering_up) + run_count_mod = 0; +} + +static void StateAction(StateMem* sm, const unsigned load, const bool data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(run_count_mod), + SFEND + }; + + MDFNSS_StateAction(sm, load, data_only, StateRegs, "DSP1"); + + DSP.StateAction(sm, load, data_only); +} + +void CART_DSP1_Init(const int32 master_clock) +{ + // + // TODO: Assume DSP1B for HiROM games, DSP1A for LoROM games? + // + for(unsigned bank = 0x00; bank < 0x100; bank++) + { + if(Cart.ROMLayout == ROM_LAYOUT_HIROM) + { + if(bank <= 0x0F || (bank >= 0x80 && bank <= 0x8F)) + { + Set_A_Handlers((bank << 16) | 0x6000, (bank << 16) | 0x6FFF, MainCPU_ReadDR, MainCPU_WriteDR); + Set_A_Handlers((bank << 16) | 0x7000, (bank << 16) | 0x7FFF, MainCPU_ReadSR, OBWrite_SLOW); + } + } + else + { + if(Cart.ROM_Size >= 0x180000) + { + if(bank >= 0x60 && bank <= 0x6F) + { + Set_A_Handlers((bank << 16) | 0x0000, (bank << 16) | 0x3FFF, MainCPU_ReadDR, MainCPU_WriteDR); + Set_A_Handlers((bank << 16) | 0x4000, (bank << 16) | 0x7FFF, MainCPU_ReadSR, OBWrite_SLOW); + } + else if(bank >= 0xE0 && bank <= 0xEF) + { + Set_A_Handlers((bank << 16) | 0x0000, (bank << 16) | 0x3FFF, MainCPU_ReadDR<-1>, MainCPU_WriteDR<-1>); + Set_A_Handlers((bank << 16) | 0x4000, (bank << 16) | 0x7FFF, MainCPU_ReadSR<-1>, OBWrite_VAR); + } + } + else + { + if(bank >= 0x30 && bank <= 0x3F) + { + Set_A_Handlers((bank << 16) | 0x8000, (bank << 16) | 0xBFFF, MainCPU_ReadDR, MainCPU_WriteDR); + Set_A_Handlers((bank << 16) | 0xC000, (bank << 16) | 0xFFFF, MainCPU_ReadSR, OBWrite_SLOW); + } + else if(bank >= 0xB0 && bank <= 0xBF) + { + Set_A_Handlers((bank << 16) | 0x8000, (bank << 16) | 0xBFFF, MainCPU_ReadDR<-1>, MainCPU_WriteDR<-1>); + Set_A_Handlers((bank << 16) | 0xC000, (bank << 16) | 0xFFFF, MainCPU_ReadSR<-1>, OBWrite_VAR); + } + } + } + } + // + // + // + last_master_timestamp = 0; + clock_multiplier = ((int64)65536 * 20000000 * 2 + master_clock) / (master_clock * 2); + // + // + // + Cart.AdjustTS = AdjustTS; + Cart.EventHandler = EventHandler; + Cart.Reset = Reset; + Cart.StateAction = StateAction; +} + +} diff --git a/mednafen/snes_faust/cart/dsp1.h b/mednafen/snes_faust/cart/dsp1.h new file mode 100644 index 0000000..9f92587 --- /dev/null +++ b/mednafen/snes_faust/cart/dsp1.h @@ -0,0 +1,31 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* dsp1.h: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __MDFN_SNES_FAUST_CART_DSP1_H +#define __MDFN_SNES_FAUST_CART_DSP1_H + +namespace MDFN_IEN_SNES_FAUST +{ + +void CART_DSP1_Init(const int32 master_clock) MDFN_COLD; + +} +#endif diff --git a/mednafen/snes_faust/cart/dsp1chip.h b/mednafen/snes_faust/cart/dsp1chip.h new file mode 100644 index 0000000..2b7dca0 --- /dev/null +++ b/mednafen/snes_faust/cart/dsp1chip.h @@ -0,0 +1,1000 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* dsp1chip.h: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +static const int16 DataROM[0x400] = +{ + #include "dsp1-datarom-synth.h" +}; + +/* +static const int16* DivTab = &DataROM[101]; +static const int16* SqrtTab = &DataROM[229]; +static const int16* SinTab = &DataROM[280]; +static const int16* CosTab = &DataROM[408]; +static const int16* ACosTab = &DataROM[542]; +*/ + +class DSP1Chip +{ + public: + DSP1Chip(); + ~DSP1Chip(); + + void Reset(bool powering_up); +#ifndef MDFN_SNES_FAUST_DSP1CHIP_TEST + void StateAction(StateMem* sm, const unsigned load, const bool data_only); +#endif + void Run(int32 cycles = 4); + + void WriteData(uint8 V); + uint8 ReadData(void); + uint8 ReadStatus(void); + + private: + + uint16 DataReg; + uint8 StatusReg; + // + uint8 Command; + int16 Args[16]; + int16 Results[16]; + uint32 Scratch[16]; + // + // + // + float cop_x; + float cop_y; + float cop_z; + int screen_cop_distance; + int azimuth_angle; + int zenith_angle; + int raster_vfudge; // Utilize the one weakness of infinitely large mode 7 center coordinates that are rumored to eat all of your almond shortbread cookies: fudge! + // + float obj_rot_matrix[3][3][3]; + // + // + // + uint32 CommandPhase; + int32 CycleCounter; + // + // + // + uint16 Revision; + + public: + enum : int { ANGLE_PI = 32768 }; + enum : int { ANGLE_HALF_PI = 16384 }; +}; + +#if 0 +static void SynthDataROM(void) +{ + FileStream fp("datarom-synth.bin", FileStream::MODE_WRITE); + FileStream fph("datarom-synth.h", FileStream::MODE_WRITE); + int16 tmp[0x400]; + + memset(tmp, 0, sizeof(tmp)); + + // 0 ... 97 + for(int i = 0; i < 98; i++) + { + int v = 0; + + if(i == 60) // bug? + v = 1; + else if(i >= 34 && i <= 64) + v = std::min(32767, 32768 >> abs(i - 49)); + + tmp[i] = v; + } + + // TODO: 98 ... 100 + + // 101...228 + // + // Inverse table + for(int i = 0; i < 128; i++) + { + int v = std::min(32767, floor(0.5 + 32768.0 / (1.0 + i / 128.0))); + + tmp[101 + i] = v; + } + + // 229...277 + // + // Square root table + for(int i = 0; i < 49; i++) + { + float fv = 32767.0 / 2.0 * sqrt(1.0 + i / 16.0); + int v = std::min(32767, floor(fv)); + + tmp[229 + i] = v; + } + + // 278...279 + for(int i = 0; i < 2; i++) + { + int v = 32 << i; + + tmp[278 + i] = v; + } + + // 280 ... 407 + // + // Sine table + for(int i = 0; i < 128; i++) + { + int v = std::min(32767, floor(32768 * sin(i * M_PI / 128.0))); + + tmp[280 + i] = v; + } + + // 408 ... 535 + // + // Cosine table + for(int i = 0; i < 128; i++) + { + float angle = i * M_PI / 128.0; + float fv = 32768.0 * cos(angle); + int v = std::min(32767, (int)fv); + + tmp[408 + i] = v; + } + + // TODO: 536 ... 541 + // pi, 2**7, (2**10)-1, ?, ?, 2**7 + + // 542 ... 797 + // + // Arc cosine table + for(int i = 0; i < 256; i++) + { + float fv = 32768.0 * acos(i / 256.0) / M_PI; + int v = std::min(32767, floor(0.5 + fv)); + + tmp[542 + i] = v; + } + + // TODO: 798 ... 808 + + // 809 + // + // tasty pie + { + int v = floor(0.5 + M_PI * 8192); + + tmp[809] = v; + } + + // TODO: 810 ... 816 + + // 817 ... 1023 + for(int i = 817; i < 1024; i++) + { + tmp[i] = -1; + } + + for(unsigned i = 0; i < 0x400; i++) + { + fp.put_LE(tmp[i]); + + fph.print_format("%d, ", tmp[i]); + + if((i & 0xF) == 0xF) + fph.print_format("\n"); + } +} +#endif +DSP1Chip::DSP1Chip() +{ + Revision = 0x0101; + // + // + // +#if 0 + SynthDataROM(); +#endif +} + +DSP1Chip::~DSP1Chip() +{ + + +} + +enum : int { CommandPhaseBias = __COUNTER__ + 1 }; + +#define WAIT_RQM() \ + { \ + case __COUNTER__: \ + if(StatusReg & 0x80) \ + { \ + CycleCounter = 0; \ + CommandPhase = __COUNTER__ - CommandPhaseBias - 1; \ + goto Breakout; \ + } \ + } + +#define EAT_CYCLES(n) \ + { \ + CycleCounter -= (n); \ + case __COUNTER__: \ + if(CycleCounter < 0) \ + { \ + CommandPhase = __COUNTER__ - CommandPhaseBias - 1; \ + goto Breakout; \ + } \ + } + + +#define READ8(v) \ + { \ + StatusReg |= 0x84; \ + WAIT_RQM() \ + (v) = (uint8)DataReg; \ + } + +#define READ16(v) \ + { \ + StatusReg = (StatusReg & ~0x04) | 0x80; \ + WAIT_RQM() \ + (v) = DataReg; \ + } + +#define WRITE8(v) \ + { \ + DataReg = (DataReg & 0xFF00) | (uint8)(v); \ + StatusReg |= 0x84; \ + WAIT_RQM() \ + } + +#define WRITE16(v) \ + { \ + DataReg = (v); \ + StatusReg = (StatusReg & ~0x04) | 0x80; \ + WAIT_RQM() \ + } + +#define WRITE32(v) \ + WRITE16((v) & 0xFFFF) \ + WRITE16((v) >> 16) + +void DSP1Chip::Reset(bool powering_up) +{ + DataReg = 0; + StatusReg = 0; + + CommandPhase = 0; + CycleCounter = 0; + // + // + Command = 0; + memset(Args, 0, sizeof(Args)); + memset(Results, 0, sizeof(Results)); + memset(Scratch, 0, sizeof(Scratch)); + + cop_x = 0; + cop_y = 0; + cop_z = 0; + screen_cop_distance = 0; + azimuth_angle = 0; + zenith_angle = 0; + raster_vfudge = 0; + + memset(obj_rot_matrix, 0, sizeof(obj_rot_matrix)); +} + +#ifndef MDFN_SNES_FAUST_DSP1CHIP_TEST +void DSP1Chip::StateAction(StateMem* sm, const unsigned load, const bool data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(DataReg), + SFVAR(StatusReg), + + SFVAR(Command), + SFVAR(Args), + SFVAR(Results), + SFVAR(Scratch), + + SFVAR(cop_x), + SFVAR(cop_y), + SFVAR(cop_z), + SFVAR(screen_cop_distance), + SFVAR(azimuth_angle), + SFVAR(zenith_angle), + SFVAR(raster_vfudge), + SFVAR(obj_rot_matrix), + + SFVAR(CommandPhase), + SFVAR(CycleCounter), + + SFEND + }; + + MDFNSS_StateAction(sm, load, data_only, StateRegs, "DSP1CHIP"); +} +#endif + +static INLINE int16 Saturate(float v) +{ + return (int)floorf(std::max(-32767, std::min(32767, v))); +} + +static INLINE float Inverse(float v) +{ + if(fabsf(v) < (1.0f / 4294967296.0f)) + return copysignf(4294967296.0f, v); + + return 1.0f / v; +} + +static float Cos(int16 angle) +{ +#if 0 + bool neg = false; + + if(angle >= 16384) + { + angle = 32768 - angle; + neg = true; + } + + if(angle <= -16384) + { + angle = -32768 - angle; + neg = true; + } + + int ret; + int x = (((int64)angle * 105414357) + 32768) >> 16; + int x_2 = ((int64)x*x + (1 << 23)) >> 24; + int x_4 = ((int64)x_2*x_2 + (1 << 23)) >> 24; + int x_6 = ((int64)x_4*x_2 + (1 << 23)) >> 24; + int x_8 = ((int64)x_4*x_4 + (1 << 23)) >> 24; + int x_10 = ((int64)x_6*x_4 + (1 << 23)) >> 24; + + //printf("%d %d %d %d %d %d\n", x, x_2, x_4, x_6, x_8, x_10); + + ret = 16777216 - ((x_2 + 1) >> 1); + ret += ((int64)x_4 * 178956971) >> 32; + ret -= x_6 / 720; + ret += ((int64)x_8 * 106522) >> 32; + ret -= ((int64)x_10 * 302996) >> 40; // / 3628800; + + if(neg) + ret = -ret; + + return ret * (1.0f / 16777216); +#else + return cosf(angle * M_PI * 2 / 65536); +#endif +} + +static INLINE float Sin(uint16 angle) +{ +#if 0 + return Cos(DSP1Chip::ANGLE_HALF_PI - angle); +#else + return sinf(angle * M_PI * 2 / 65536); +#endif +} + +static INLINE float Tan(uint16 angle) +{ + return Sin(angle) * Inverse(Cos(angle)); +} + +static INLINE uint16 ATan2(float y, float x) +{ + return (int)((65536.0f / (float)(M_PI * 2)) * atan2f(y, x)); +} + +NO_INLINE void DSP1Chip::Run(int32 cycles) +{ + CycleCounter += cycles; + // + // + // + switch(CommandPhase + CommandPhaseBias) + { + for(;;) + { + default: + case __COUNTER__: + // + // + ////// + READ8(Command) + + //printf("Command: %02x %u\n", Command, PPU_GetRegister(PPU_GSREG_SCANLINE, nullptr, 0)); + + if(Command == 0x00) + { + // 16-bit multiplication + // + // Two 16-bit args, one 16-bit result. + READ16(Args[0]) + READ16(Args[1]) + { + Results[0] = (Args[0] * Args[1]) >> 15; + } + WRITE16(Results[0]) + } + else if(Command == 0x10) + { + // Inverse? + // plot [x=101:229] "datarom.plot" with lines, 32767/(1.0 + (x-101)/128) + READ16(Args[0]) + READ16(Args[1]) + { + const bool neg = Args[0] < 0; + const int in_exp = Args[1]; + const int in_sig = neg ? -Args[0] : Args[0]; + + if(!in_sig) + { + Results[0] = 0x7FFF; + Results[1] = 0x002F; + } + else + { + // + // + // + //gnuplot> plot [x=0:32767] 32768 / (1 + x / 32768) + const int16* invtable = &DataROM[101]; + const unsigned l2 = log2(in_sig); + //const unsigned p2 = 1U << l2; + + //const int rawshift = 7 - l2; + //const unsigned lshift = std::max(0, rawshift); + const unsigned ipc_lshift = 14 - l2; + const size_t index = ((in_sig << 7) >> l2) & 0x7F; + const int s0 = invtable[index]; + const int s1 = invtable[index + 1]; + int sig, exp; + int ipc; + + //l = std::min(0x7FFF, 32768 * p2 / div); //((uint64)32768 * p2 * 2 + div) / (div * 2)); + ipc = (in_sig << ipc_lshift) & 0x7F; + + sig = 32768 / in_sig; + + sig = ((s0 * (0x80 - ipc)) + (s1 * ipc)) >> 7; + //sig = (sig + 1) & ~1; + exp = 15 - l2; + + if(neg && !index && !ipc) + { + sig >>= 1; + exp++; + } + exp -= in_exp; + + if(neg) + sig = -sig; + + Results[0] = sig; + Results[1] = exp; + } + } + WRITE16(Results[0]) + WRITE16(Results[1]) + } + else if(Command == 0x04) + { + // Trig calculation? + // + // gnuplot> plot [x=408:535] "datarom.plot" with lines, 32767*cos((x-408)*pi*2/256) + // + // Two 16-bit args, two 16-bit results + READ16(Args[0]); // Angle + READ16(Args[1]); // Scale + { + Results[0] = Saturate(Sin(Args[0]) * Args[1]); + Results[1] = Saturate(Cos(Args[0]) * Args[1]); + } + WRITE16(Results[0]) // sine result + WRITE16(Results[1]) // cosine result + } + else if(Command == 0x14) + { + // 3D angle rotation? + // + // Six 16-bit args, three 16-bit results? + READ16(Args[0]) + READ16(Args[1]) + READ16(Args[2]) + READ16(Args[3]) + READ16(Args[4]) + READ16(Args[5]) + + //printf("angle rot: %04x %04x %04x, %04x %04x %04x\n", Args[0], Args[1], Args[2], Args[3], Args[4], Args[5]); + { + float tmp[3]; + + tmp[0] = (Args[3] * Cos(Args[2]) - Args[4] * Sin(Args[2])) * Inverse(Cos(Args[1])); + tmp[1] = (Args[3] * Sin(Args[2]) + Args[4] * Cos(Args[2])); + tmp[2] = -Tan(Args[1]) * (Args[3] * Cos(Args[2]) + Args[4] * Sin(Args[2])) + Args[5]; + + Results[0] = Args[0] + Saturate(tmp[0]); + Results[1] = Args[1] + (int)floorf(tmp[1]); + Results[2] = Args[2] + Saturate(tmp[2]); + } + WRITE16(Results[0]) + WRITE16(Results[1]) + WRITE16(Results[2]) + } + else if(Command == 0x0C) + { + // 2D coordinate rotation? + // + // Three 16-bit args, two 16-bit results? + READ16(Args[0]) // Angle + READ16(Args[1]) // x (y?) + READ16(Args[2]) // y (x?) + { + Results[0] = Saturate(Args[1] * Cos(Args[0]) + Args[2] * Sin(Args[0])); + Results[1] = Saturate(Args[2] * Cos(Args[0]) - Args[1] * Sin(Args[0])); + } + WRITE16(Results[0]) + WRITE16(Results[1]) + } + else if(Command == 0x1C) + { + // 3D coordinate rotation? + // + // Six 16-bit args, three 16-bit results + READ16(Args[0]) // angle + READ16(Args[1]) // angle + READ16(Args[2]) // angle + + READ16(Args[3]) // coord + READ16(Args[4]) // coord + READ16(Args[5]) // coord + { + float simu[3]; + float ns[3]; + + simu[0] = Args[3]; + simu[1] = Args[4]; + simu[2] = Args[5]; + // + ns[0] = simu[0] * Cos(Args[0]) + simu[1] * Sin(Args[0]) ; + ns[1] = -simu[0] * Sin(Args[0]) + simu[1] * Cos(Args[0]) ; + simu[0] = ns[0]; + simu[1] = ns[1]; + // + ns[0] = simu[0] * Cos(Args[1]) - simu[2] * Sin(Args[1]); + ns[2] = simu[0] * Sin(Args[1]) + simu[2] * Cos(Args[1]); + simu[0] = ns[0]; + simu[2] = ns[2]; + // + // + ns[1] = simu[1] * Cos(Args[2]) + simu[2] * Sin(Args[2]); + ns[2] = -simu[1] * Sin(Args[2]) + simu[2] * Cos(Args[2]); + simu[1] = ns[1]; + simu[2] = ns[2]; + + Results[0] = simu[0]; + Results[1] = simu[1]; + Results[2] = simu[2]; + } + WRITE16(Results[0]) + WRITE16(Results[1]) + WRITE16(Results[2]) + } + else if(Command == 0x01 || Command == 0x11 || Command == 0x21) + { + // Set Attitude? + // + // Four 16-bit args, zero 16-bit results? + READ16(Args[0]) + READ16(Args[1]) + READ16(Args[2]) + READ16(Args[3]) + { + float (&matrix)[3][3] = obj_rot_matrix[(Command >> 4) % 3]; + + matrix[0][0] = Args[0] * (Cos(-Args[1]) * Cos(-Args[2])); + matrix[0][1] = Args[0] * (-Sin(-Args[1]) * Cos(-Args[3]) + Cos(-Args[1]) * Sin(-Args[2]) * Sin(-Args[3])); + matrix[0][2] = Args[0] * (Sin(-Args[1]) * Sin(-Args[3]) + Cos(-Args[1]) * Sin(-Args[2]) * Cos(-Args[3])); + + matrix[1][0] = Args[0] * (Sin(-Args[1]) * Cos(-Args[2])); + matrix[1][1] = Args[0] * (Cos(-Args[1]) * Cos(-Args[3]) + Sin(-Args[1]) * Sin(-Args[2]) * Sin(-Args[3])); + matrix[1][2] = Args[0] * (-Cos(-Args[1]) * Sin(-Args[3]) + Sin(-Args[1]) * Sin(-Args[2]) * Cos(-Args[3])); + + matrix[2][0] = Args[0] * (-Sin(-Args[2])); + matrix[2][1] = Args[0] * (Cos(-Args[2]) * Sin(-Args[3])); + matrix[2][2] = Args[0] * (Cos(-Args[2]) * Cos(-Args[3])); + } + } + else if(Command == 0x03 || Command == 0x13 || Command == 0x23) + { + // Object to Global Coordinate? + // + // Three 16-bit args, three 16-bit results? + Scratch[0] = Command >> 4; + READ16(Args[0]) + READ16(Args[1]) + READ16(Args[2]) + { + float (&matrix)[3][3] = obj_rot_matrix[(Command >> 4) % 3]; + + for(unsigned ri = 0; ri < 3; ri++) + { + Results[ri] = Saturate((matrix[ri][0] * Args[0] + matrix[ri][1] * Args[1] + matrix[ri][2] * Args[2]) / 65536); + } + } + WRITE16(Results[0]) + WRITE16(Results[1]) + WRITE16(Results[2]) + } + else if(Command == 0x0D || Command == 0x1D || Command == 0x2D) + { + // Global to Object Coordinate? + // + // Three 16-bit args, three 16-bit results? + READ16(Args[0]) + READ16(Args[1]) + READ16(Args[2]) + { + float (&matrix)[3][3] = obj_rot_matrix[(Command >> 4) % 3]; + + for(unsigned ri = 0; ri < 3; ri++) + { + Results[ri] = Saturate((matrix[0][ri] * Args[0] + matrix[1][ri] * Args[1] + matrix[2][ri] * Args[2]) / 65536); + } + } + WRITE16(Results[0]) + WRITE16(Results[1]) + WRITE16(Results[2]) + } + else if(Command == 0x0B || Command == 0x1B || Command == 0x2B) + { + // Inner Product with forward attitude and vector? + // + // Three 16-bit args, one 16-bit result? + READ16(Args[0]) + READ16(Args[1]) + READ16(Args[2]) + { + float (&matrix)[3][3] = obj_rot_matrix[(Command >> 4) % 3]; + Results[0] = Saturate((matrix[0][0] * Args[0] + matrix[1][0] * Args[1] + matrix[2][0] * Args[2]) / 65536); + } + WRITE16(Results[0]) + } + else if(Command == 0x02) + { + // Projection parameter settings? + // + // Seven 16-bit args, four 16-bit results? + READ16(Args[0]) + READ16(Args[1]) + READ16(Args[2]) + READ16(Args[3]) + READ16(Args[4]) + READ16(Args[5]) + READ16(Args[6]) + // + // + // + { + int base_x = Args[0]; // Base X + int base_y = Args[1]; // Base Y + int base_z = Args[2]; // Base Z + int base_cop_distance = Args[3]; // Distance between base point and center of projection + screen_cop_distance = Args[4]; // Distance between center of projection and screen. + azimuth_angle = Args[5]; // Azimuth angle. + zenith_angle = Args[6]; // Zenith angle. + // + // + // + cop_z = base_z - base_cop_distance * Sin(zenith_angle - ANGLE_HALF_PI); + cop_y = base_y + base_cop_distance * Cos(zenith_angle - ANGLE_HALF_PI) * Cos(azimuth_angle); + cop_x = base_x - base_cop_distance * Cos(zenith_angle - ANGLE_HALF_PI) * Sin(azimuth_angle); + + //printf("PROJPARAM; base_x=%d, base_y=%d, base_z=%d(cop_x=%d, cop_y=%d, cop_z=%d), base_cop_distance=%d, screen_cop_distance=%d, azimuth_angle=%d, zenith_angle=%d\n", base_x, base_y, base_z, cop_x, cop_y, cop_z, base_cop_distance, screen_cop_distance, azimuth_angle, zenith_angle); + { + raster_vfudge = 0; + + if(Args[6] >= 14515) + raster_vfudge = (int)floorf(0.5f + screen_cop_distance * 0.00009778887f * (Args[6] - 14515)); + + Results[0] = Saturate(raster_vfudge); + Results[1] = Saturate(floorf(screen_cop_distance * Tan(zenith_angle - ANGLE_HALF_PI)) - raster_vfudge); + // + // + float y = cop_z * Tan(ANGLE_PI - (zenith_angle - ATan2(raster_vfudge, screen_cop_distance))); + float new_x = -y * Sin(azimuth_angle); + float new_y = y * Cos(azimuth_angle); + + Results[2] = Saturate(cop_x + new_x); + Results[3] = Saturate(cop_y + new_y); + } + } + // + // + // + WRITE16(Results[0]) + WRITE16(Results[1]) + WRITE16(Results[2]) + WRITE16(Results[3]) + } + else if(Command == 0x06) + { + // Projection + // + // Three args, three results + READ16(Args[0]) + READ16(Args[1]) + READ16(Args[2]) + { + float x, y, z; + + x = Args[0] - cop_x; + y = Args[1] - cop_y; + z = Args[2] - cop_z; + // + { + float new_x = x * Cos(-azimuth_angle) - y * Sin(-azimuth_angle); + float new_y = x * Sin(-azimuth_angle) + y * Cos(-azimuth_angle); + + x = new_x; + y = new_y; + } + // + { + float new_y = y * Cos(-zenith_angle) + z * Sin(-zenith_angle); + float new_z = y * Sin(-zenith_angle) - z * Cos(-zenith_angle); + + y = new_y; + z = new_z; + } + // + float scale = screen_cop_distance * 256.0f * Inverse(z); + + x *= scale / 256.0f; + y *= scale / 256.0f; + + Results[0] = Saturate(x); + Results[1] = Saturate(y); + Results[2] = Saturate(scale); + } + WRITE16(Results[0]) + WRITE16(Results[1]) + WRITE16(Results[2]) + } + else if(Command == 0x0E) + { + // + // Converts screen coordinates to (mode 7) ground plane coordinates + // + READ16(Args[0]) + READ16(Args[1]) + { + float y = cop_z * Tan(ANGLE_PI - (zenith_angle - ATan2((int8)Args[1] + raster_vfudge, screen_cop_distance))); + float x = (int8)Args[0] * (y * Sin(-zenith_angle) + cop_z * Cos(-zenith_angle)) * Inverse(screen_cop_distance); + // + float new_x = x * Cos(azimuth_angle) - y * Sin(azimuth_angle); + float new_y = y * Cos(azimuth_angle) - x * Sin(azimuth_angle); + + Results[0] = Saturate(cop_x + 0.5f + new_x); + Results[1] = Saturate(cop_y + 0.5f + new_y); + } + WRITE16(Results[0]) + WRITE16(Results[1]) + } + else if(Command == 0x1A || Command == 0x0A) + { + assert(Command != 0x1A); + // Mode 7 matrix calculation + // + // One 16-bit args, variable results + READ16(Args[0]) + + Scratch[0] = Args[0]; + do + { + { + int16 screen_y = (int16)Scratch[0] + raster_vfudge; + { + float y = cop_z * Tan(ANGLE_PI - (zenith_angle - ATan2(screen_y, screen_cop_distance))); + float xs = (y * Sin(-zenith_angle) + cop_z * Cos(-zenith_angle)) * Inverse(screen_cop_distance); + //float ys = (y - centery) / screen_y; //xs / cos(ph)*1.1; //(y_diff / -sin(M_PI - ph_adj)) / new_screen_cop_distance; + float ys = xs * Inverse(Cos(zenith_angle - ATan2(raster_vfudge, screen_cop_distance))); + // + // + Results[0] = Saturate(0x100 * Cos(azimuth_angle) * xs); + Results[1] = Saturate(-0x100 * Sin(azimuth_angle) * ys); + Results[2] = Saturate(0x100 * Sin(azimuth_angle) * xs); + Results[3] = Saturate(0x100 * Cos(azimuth_angle) * ys); + } + } + Scratch[0]++; + // + // + WRITE16(Results[0]) + WRITE16(Results[1]) + WRITE16(Results[2]) + WRITE16(Results[3]) + } while(DataReg == (uint16)Results[3]); + } + else if(Command == 0x08) + { + // Vector size calculation? + // + // Three 16-bit args, two 16-bit results + READ16(Args[0]) + READ16(Args[1]) + READ16(Args[2]) + { + uint32 tmp = ((uint32)(Args[0] * Args[0]) + (Args[1] * Args[1]) + (Args[2] * Args[2])) << 1; + + Results[0] = tmp; + Results[1] = tmp >> 16; + } + WRITE16(Results[0]) + WRITE16(Results[1]) + } + else if(Command == 0x18 || Command == 0x38) + { + // Vector size comparison + // + // Four 16-bit args, one 16-bit result + READ16(Args[0]) + READ16(Args[1]) + READ16(Args[2]) + READ16(Args[3]) + + Scratch[0] = (uint32)(Args[0] * Args[0]) + (Args[1] * Args[1]) + (Args[2] * Args[2]); + + if(Command == 0x38) + Scratch[0] += 128 * 256; // FIXME ? ? ? + else + Scratch[0] -= Args[3] * Args[3]; + + Scratch[0] <<= 1; + Scratch[0] >>= 16; + + WRITE16(Scratch[0]) + } + else if(Command == 0x28) + { + // Vector absolute value? + // + // plot [x=229:277] "datarom.plot" with lines, 16384*sqrt(1.0 + (x-229)/16) + // + // Craps out around an input value of 64 with others 0(value to take square root of == 8192)) + // Also around: + // (18919 * 18919) * 3 * 2 + // (25027*25027)*3*2 + // (26755*26755)*3*2 + // + // Three 16-bit args, one 16-bit result + READ16(Args[0]) + READ16(Args[1]) + READ16(Args[2]) + + { + int64 ss = (int64)(Args[0] * Args[0]) + (Args[1] * Args[1]) + (Args[2] * Args[2]); + + Results[0] = (uint16)(int)floor(0.5 + sqrt(ss)); + } + WRITE16(Results[0]); + } + else if(Command == 0x0F) + { + // + // Test data RAM? + // + READ16(Args[0]) + + // TODO: wait + + WRITE16(0x0000); + } + else if(Command == 0x1F) + { + // + // Get data ROM + // + READ16(Args[0]) // ? + + for(Scratch[0] = 0; Scratch[0] < 0x400; Scratch[0]++) + { + WRITE16(DataROM[Scratch[0] & 0x3FF]) + } + } + else if(Command == 0x2F) + { + // + // Get version + // + READ16(Args[0]) // ? + + WRITE16(Revision) + } + else + { + if(Command != 0x80) + { + SNES_DBG("[DSP1] Unknown command: %02x\n", Command); + } + Command = 0x80; + } + + if(Command != 0x80) + DataReg = 0x80; + ////// + // + // + } + } + Breakout:; + // +} + +#undef WAIT_RQM +#undef EAT_CYCLES +#undef READ8 +#undef READ16 +#undef WRITE8 +#undef WRITE16 +#undef WRITE32 + +INLINE void DSP1Chip::WriteData(uint8 V) +{ + Run(); + // + // + const unsigned shift = ((StatusReg >> 1) & 0x8); + DataReg &= ~(0xFF << shift); + DataReg |= V << shift; + StatusReg ^= (~StatusReg & 0x4) << 2; + StatusReg &= ~((~StatusReg & 0x10) << 3); + //StatusReg &= (StatusReg >> 5) & 0x4; + + //printf("WriteDR: %02x\n", V); +} + +INLINE uint8 DSP1Chip::ReadData(void) +{ + Run(); + // + // + uint8 ret = DataReg >> ((StatusReg >> 1) & 0x8); + StatusReg ^= (~StatusReg & 0x4) << 2; + StatusReg &= ~((~StatusReg & 0x10) << 3); + + //printf("ReadDR: %02x\n", ret); + + return ret; +} + +INLINE uint8 DSP1Chip::ReadStatus(void) +{ + Run(); + // + // + return StatusReg; +} diff --git a/mednafen/snes_faust/cart/dsp2.cpp b/mednafen/snes_faust/cart/dsp2.cpp new file mode 100644 index 0000000..2fd519d --- /dev/null +++ b/mednafen/snes_faust/cart/dsp2.cpp @@ -0,0 +1,74 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* dsp2.cpp: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "common.h" +#include "dsp2.h" + +namespace MDFN_IEN_SNES_FAUST +{ + +template +static DEFREAD(MainCPU_ReadDR) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += (cyc >= 0) ? cyc : (MemSelect ? MEMCYC_FAST : MEMCYC_SLOW); + } + // + // + return 0; +} + +template +static DEFWRITE(MainCPU_WriteDR) +{ + CPUM.timestamp += (cyc >= 0) ? cyc : (MemSelect ? MEMCYC_FAST : MEMCYC_SLOW); + // + // + SNES_DBG("[DSP2] WriteDR: %02x\n", V); +} + +template +static DEFREAD(MainCPU_ReadSR) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += (cyc >= 0) ? cyc : (MemSelect ? MEMCYC_FAST : MEMCYC_SLOW); + } + // + // + //abort(); + return 0x80; +} + +void CART_DSP2_Init(const int32 master_clock) +{ + for(unsigned bank = 0x00; bank < 0x100; bank++) + { + if(bank >= 0x20 && bank <= 0x3F) + { + Set_A_Handlers((bank << 16) | 0x8000, (bank << 16) | 0xBFFF, MainCPU_ReadDR, MainCPU_WriteDR); + Set_A_Handlers((bank << 16) | 0xC000, (bank << 16) | 0xFFFF, MainCPU_ReadSR, OBWrite_SLOW); + } + } +} + +} diff --git a/mednafen/snes_faust/cart/dsp2.h b/mednafen/snes_faust/cart/dsp2.h new file mode 100644 index 0000000..ec28b40 --- /dev/null +++ b/mednafen/snes_faust/cart/dsp2.h @@ -0,0 +1,31 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* dsp2.h: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __MDFN_SNES_FAUST_CART_DSP2_H +#define __MDFN_SNES_FAUST_CART_DSP2_H + +namespace MDFN_IEN_SNES_FAUST +{ + +void CART_DSP2_Init(const int32 master_clock) MDFN_COLD; + +} +#endif diff --git a/mednafen/snes_faust/cart/sa1.cpp b/mednafen/snes_faust/cart/sa1.cpp new file mode 100644 index 0000000..8e625fa --- /dev/null +++ b/mednafen/snes_faust/cart/sa1.cpp @@ -0,0 +1,1355 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* sa1.cpp: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* Much guesswork */ + +#include "common.h" +#include "sa1.h" +#include "sa1cpu.h" + +namespace MDFN_IEN_SNES_FAUST +{ +static uint8 SA1VectorSpace[0x10]; +static uint8 SA1VectorMask[0x10]; +static uint8 MainVectors[4]; + +static uint8 SA1CPUControl; +static uint8 SA1CPUIRQEnable; +static uint8 SA1CPUIRQPending; + +static uint8 MainCPUControl; +static uint8 MainCPUIRQEnable; +static uint8 MainCPUIRQPending; + +static uint8 DMAControl; +static uint8 DMACharConvParam; +static uint32 DMASourceAddr; +static uint32 DMADestAddr; +static uint32 DMALength; +static uint32 DMAFinishTS; + +static bool DMACharConvAutoActive; +static uint32 DMACharConvSourceXTile; +static uint32 DMACharConvSourceYTile; +static uint32 DMACharConvCCVBWRAMCounter; +static uint8 CharConvBMRegs[0x10]; +static unsigned CharConvTileY; + + +static uint8 ROMBank[4]; +static uintptr_t ROMPtr[8]; +static INLINE void RecalcROMPtr(unsigned w) +{ + ROMPtr[0 + w] = (uintptr_t)&Cart.ROM[(ROMBank[w] & 0x80) ? ((ROMBank[w] & 0x7) << 20) : (w << 20)]; + ROMPtr[4 + w] = (uintptr_t)&Cart.ROM[(ROMBank[w] & 0x7) << 20] - ((0xC0 + (w << 4)) << 16); +} + +static uint8 MainBWRAMBank; // $2224 +static uint8 SA1BWRAMBank; // $2225 +static bool BWRAMWriteEnable[2]; // [0]=$2226(main), [1]=$2227(SA1 CPU side) +static uint8 BWRAMWriteProtectSize; // $2228 +static uint8 IWRAMWriteEnable[2]; // [0]=$2229(main), [1]=$222A(SA1 CPU side) + +static bool BWRAMBitmapFormat; // $223F(SA1 CPU) + +// +static uint8 MathControl; // $2250(SA1 CPU) +static uint16 MathParam[2]; // $2251...$2254 +static uint64 MathResult; + +static uint8 VarLenControl; // $2258 (SA1 CPU) +static uint32 VarLenAddr; +static uint32 VarLenCurAddr; +static uint32 VarLenCurBitOffs; +static uint32 VarLenBuffer; + +static uint8 IRAM[0x800]; +// +// +// +static void AdjustTS(int32 delta) +{ + SA1CPU::CPUM.timestamp += delta; + if(DMAFinishTS != 0x7FFFFFFF) + DMAFinishTS = std::max(0, (int64)DMAFinishTS + delta); +} + +static uint32 SA1CPUBoundTS; + +static NO_INLINE void Update(uint32 timestamp) +{ + SA1CPUBoundTS = timestamp; + SA1CPU::CPUM.next_event_ts = std::min(DMAFinishTS, SA1CPUBoundTS); + SA1CPU::CPU_Run(); +} + +static uint32 EventHandler(uint32 timestamp) +{ + Update(timestamp); + + return timestamp + 256; +} +// +// +// +void SA1CPU::CPU_Misc::RunDMA(void) +{ + //puts("HAH"); + SA1CPU::CPUM.timestamp = SA1CPU::CPUM.next_event_ts; +} + +void SA1CPU::CPU_Misc::EventHandler(void) +{ + if(MDFN_UNLIKELY(timestamp >= DMAFinishTS)) + { + if(SA1CPUIRQEnable & 0x20) + { + SA1CPUIRQPending |= 0x20; + SA1CPU::CPU_SetIRQ(SA1CPUIRQPending & 0xE0); + } + // + DMAFinishTS = 0x7FFFFFFF; + } + + SA1CPU::CPUM.next_event_ts = std::min(DMAFinishTS, SA1CPUBoundTS); + + if(timestamp >= SA1CPUBoundTS) + SA1CPU::CPU_Exit(); +} + + +template +static DEFWRITE(WriteIRAM) +{ + if(SA1Side) + SA1CPU::CPUM.timestamp += 2; + else + { + CPUM.timestamp += MEMCYC_FAST; + // + Update(CPUM.timestamp); + } + // + A &= 0x7FF; + if((IWRAMWriteEnable[SA1Side] >> (A >> 8)) & 1) + IRAM[A] = V; + else + SNES_DBG("[%s] IRAM write blocked; 0x%06x 0x%02x\n", SA1Side ? "SA1CPU" : "SA1", A, V); +} + +template +static DEFREAD(ReadIRAM) +{ + if(SA1Side) + SA1CPU::CPUM.timestamp += 2; + else + { + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += MEMCYC_FAST; + // + Update(CPUM.timestamp); + } + } + // + return IRAM[A & 0x7FF]; +} + +static INLINE uint8 ReadROM(size_t region, uint32 A) +{ + if(region < 0x4) + return *(uint8*)(ROMPtr[region] + (A & 0x7FFF) + ((A >> 1) & 0xF8000)); + else + return *(uint8*)(ROMPtr[region] + A); +} + +static INLINE uint8 DMA_ReadROM(uint32 A) +{ + size_t region; + + if(A >= 0xC00000) + region = (A >> 20) & 0x7; + else + { + //assert(!(A & 0x400000) && (A & 0x8000)); + region = ((A >> 22) & 0x2) + ((A >> 21) & 0x1); + } + + return ReadROM(region, A); +} + +static NO_INLINE void DMA_RunNormal(const uint32 timestamp) +{ + SNES_DBG("[SA1] DMA: 0x%06x->0x%06x * 0x%04x, Control=0x%02x\n", DMASourceAddr, DMADestAddr, DMALength, DMAControl); + + uint32 DMACurSourceAddr = DMASourceAddr; + uint32 DMACurDestAddr = DMADestAddr; + uint32 DMACurCount = DMALength; + const unsigned DMASourceMem = DMAControl & 0x3; + const bool DMADestMem = (bool)(DMAControl & 0x4); + + DMAFinishTS = timestamp + (DMALength << (DMASourceMem == 1 || DMADestMem == 1)); + + if(((DMASourceMem & 2) && DMADestMem == 0) || (DMASourceMem == 1 && DMADestMem == 1)) + SNES_DBG("[SA1] Attempted to start illegal DMA."); + else if(!DMACurCount) + SNES_DBG("[SA1] Attempted to start 0-length DMA."); + else while(MDFN_LIKELY(DMACurCount)) + { + uint8 tmp = 0xFF; + + if(DMASourceMem & 2) + tmp = IRAM[DMACurSourceAddr & 0x7FF]; + else if(DMASourceMem == 1 && Cart.RAM_Mask != SIZE_MAX) + tmp = Cart.RAM[DMACurSourceAddr & Cart.RAM_Mask]; + else if(DMASourceMem == 0) + tmp = DMA_ReadROM(DMACurSourceAddr & 0xFFFFFF); + + if(DMADestMem == 1 && Cart.RAM_Mask != SIZE_MAX) + Cart.RAM[DMACurDestAddr & Cart.RAM_Mask] = tmp; + else if(DMADestMem == 0) + IRAM[DMACurDestAddr & 0x7FF] = tmp; + // + DMACurCount--; + DMACurSourceAddr++; + DMACurDestAddr++; + } +} + +static INLINE void WriteCharConvBMReg(unsigned which, uint8 V) +{ + CharConvBMRegs[which] = V; + // + // + // + const unsigned depth = DMACharConvParam & 0x3; + const unsigned bpp = 8 >> depth; + + if(which == 0x7 || which == 0xF) + { + uint8 tmp[8] = { 0 }; + + for(unsigned x = 0; x < 8; x++) + { + const unsigned pix = CharConvBMRegs[x + (which & 8)]; + // printf("Charconv %08x %08x %zu:%zu %08zx --- %02x\n", DMASourceAddr, DMADestAddr, source_x, source_y, bwoffs, Cart.RAM[bwoffs & Cart.RAM_Mask]); + + for(unsigned i = 0; i < bpp; i++) + tmp[i] |= ((pix >> i) & 0x1) << (7 - x); + } + + size_t iro = DMADestAddr + ((CharConvTileY & 0x7) << 1) + ((bool)(CharConvTileY & 8) << (6 - depth)); + + for(unsigned i = 0; i < bpp; i++) + IRAM[(iro + (i & 0x1) + ((i >> 1) << 4)) & 0x7FF] = tmp[i]; + + CharConvTileY = (CharConvTileY + 1) & 0xF; + } +} + +static void DMA_RunCharConvIter(void) +{ + const unsigned depth = DMACharConvParam & 0x3; // 8bpp, 4bpp, 2bpp + const unsigned vw = (DMACharConvParam >> 2) & 0x7; // 1, 2, 4, 8, 16, 32, ?, ? characters + + if(MDFN_UNLIKELY(Cart.RAM_Mask == SIZE_MAX)) + { + for(unsigned i = 0; i < 64; i++) + WriteCharConvBMReg(i & 0xF, 0xFF); + } + else + { + for(unsigned y = 0; y < 8; y++) + { + for(unsigned x = 0; x < 8; x++) + { + const size_t source_x = x + (DMACharConvSourceXTile << 3); + const size_t source_y = y + (DMACharConvSourceYTile << 3); + const size_t bwoffs = DMASourceAddr + (((source_y << (3 + vw)) + source_x) >> depth); + const unsigned src_shift = ((x & ((1 << depth) - 1)) << (3 - depth)); + const unsigned pix = Cart.RAM[bwoffs & Cart.RAM_Mask] >> src_shift; + + // printf("Charconv %08x %08x %zu:%zu %08zx --- %02x\n", DMASourceAddr, DMADestAddr, source_x, source_y, bwoffs, Cart.RAM[bwoffs & Cart.RAM_Mask]); + + WriteCharConvBMReg(((y & 1) << 3) + x, pix); + } + } + } + + DMACharConvSourceXTile = (DMACharConvSourceXTile + 1) & ((1 << vw) - 1); + if(!DMACharConvSourceXTile) + { + DMACharConvSourceYTile++; + } +} + +static INLINE uint8 DMA_ReadCCVBWRAM(void) +{ + const unsigned depth = DMACharConvParam & 0x3; // 8bpp, 4bpp, 2bpp + uint8 ret; + + if(MDFN_LIKELY(!DBG_InHLRead)) + { + if(!(DMACharConvCCVBWRAMCounter & (0x3F >> depth))) + DMA_RunCharConvIter(); + } + + ret = IRAM[(DMADestAddr + (DMACharConvCCVBWRAMCounter & (0x7F >> depth))) & 0x7FF]; + + if(MDFN_LIKELY(!DBG_InHLRead)) + { + DMACharConvCCVBWRAMCounter++; + } + + return ret; +} + +template +static INLINE void WriteSharedDMAReg(const uint32 timestamp, uint32 A, uint8 V) +{ + //printf("SharedDMA: %08x %02x\n", A, V); + + if(T_A == 0x2231) + { + DMACharConvParam = V & 0x1F; + //printf("CharConv: %02x\n", V); + if(V & 0x80) + { + DMACharConvAutoActive = false; + } + } + else if(T_A >= 0x2232 && T_A <= 0x2234) + { + const unsigned shift = ((T_A - 0x2232) & 0x3) << 3; + + DMASourceAddr = (DMASourceAddr & ~(0xFF << shift)) | (V << shift); + } + else if(T_A >= 0x2235 && T_A <= 0x2237) + { + const unsigned offs = (T_A - 0x2235) & 0x3; + const unsigned shift = offs << 3; + + DMADestAddr = (DMADestAddr & ~(0xFF << shift)) | (V << shift); + + if(((DMAControl & 0xA0) == 0x80) && offs == (1 + (bool)(DMAControl & 0x4))) + { + DMA_RunNormal(timestamp); + } + else if(((DMAControl & 0xA0) == 0xA0) && offs == 1) + { + CharConvTileY = 0; + if(DMAControl & 0x10) + { + DMACharConvAutoActive = true; + DMACharConvSourceXTile = 0; + DMACharConvSourceYTile = 0; + DMACharConvCCVBWRAMCounter = 0; + //DMA_RunCharConvIter(); + if(MainCPUIRQEnable & 0x20) + { + MainCPUIRQPending |= 0x20; + CPU_SetIRQ(MainCPUIRQPending, CPU_IRQSOURCE_CART); + } + } + //else + // assert(0); + } + } +} + +template +static DEFWRITE(MainCPU_WriteIO) +{ + CPUM.timestamp += MEMCYC_FAST; + // + Update(CPUM.timestamp); + // + SNES_DBG("[SA1] IO Write 0x%06x 0x%02x\n", T_A, V); + assert((A & 0xFFFF) == T_A); + + switch(T_A) + { + default: + SNES_DBG("[SA1] Unknown Write: $%02x:%04x $%02x\n", A >> 16, A & 0xFFFF, V); + break; + + case 0x2200: +/* + // SA-1 CPU control + Message[1] = V & 0xF; + if(V & 0x10) + { + SA1CPU::CPU_SetNMI(true); + SA1CPU::CPU_SetNMI(false); + } + + if(V & 0x20) + { + SA1CPU::CPU_Reset(false); + } + + Wait = (bool)(V & 0x20); +*/ + { + const uint8 old_SA1CPUControl = SA1CPUControl; + + if(V & SA1CPUIRQEnable & 0x10) + { + SA1CPUIRQPending |= 0x10; + SA1CPU::CPU_SetNMI(SA1CPUIRQPending & 0x10); + } + + if(V & SA1CPUIRQEnable & 0x80) + { + SA1CPUIRQPending |= 0x80; + SA1CPU::CPU_SetIRQ(SA1CPUIRQPending & 0xE0); + } + + SA1CPUControl = V; + + if((old_SA1CPUControl ^ SA1CPUControl) & old_SA1CPUControl & 0x20) + { + SA1CPU::CPUM.halted = SA1CPU::CPU_Misc::HALTED_NOT; + SA1CPU::CPU_Reset(false); // TODO: don't clear IRQ pending in 65816 core. + SA1CPU::CPU_SetIRQ(SA1CPUIRQPending & 0xE0); + } + else if(SA1CPUControl & 0x20) + { + SA1CPU::CPUM.halted = SA1CPU::CPU_Misc::HALTED_DMA; + } + } + break; + + case 0x2201: + MainCPUIRQEnable = V & 0xA0; + //MainCPUIRQPending &= ~MainCPUIRQEnable; + break; + + case 0x2202: + MainCPUIRQPending &= ~V; + CPU_SetIRQ(MainCPUIRQPending, CPU_IRQSOURCE_CART); + break; + + // + // SA-1 CPU Vectors + // + case 0x2203: + case 0x2204: + case 0x2205: + case 0x2206: + case 0x2207: + case 0x2208: + { + static const size_t tl[6] = { /*Reset:*/ 0xFFEC, 0xFFED, /*NMI*/0xFFEA, 0xFFEB, /*IRQ*/0xFFEE, 0xFFEF }; + const size_t t = tl[T_A - 0x2203]; + + SA1VectorSpace[t & 0xF] = V; + } + break; + + case 0x2220: + case 0x2221: + case 0x2222: + case 0x2223: + ROMBank[T_A & 0x3] = V & 0x87; + RecalcROMPtr(T_A & 0x3); + break; + + case 0x2224: + MainBWRAMBank = V & 0x1F; + break; + + case 0x2226: + BWRAMWriteEnable[0] = V >> 7; + break; + + case 0x2228: + BWRAMWriteProtectSize = V & 0xF; + break; + + case 0x2229: + IWRAMWriteEnable[0] = V; + break; + + case 0x2231: + case 0x2232: + case 0x2233: + case 0x2234: + case 0x2235: + case 0x2236: + case 0x2237: + WriteSharedDMAReg(CPUM.timestamp, A, V); + break; + } +} + +template +static DEFREAD(MainCPU_ReadIO) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += MEMCYC_FAST; + Update(CPUM.timestamp); + } + // + uint8 ret = 0x00; + + SNES_DBG("[SA1] IO Read 0x%06x\n", A); + assert((A & 0xFFFF) == T_A); + switch(T_A) + { + default: + SNES_DBG("[SA1CPU] Unknown Read: $%02x:%04x\n", A >> 16, A & 0xFFFF); + break; + + case 0x2300: + ret = MainCPUControl | MainCPUIRQPending; + break; + + case 0x230E: + ret = 0x23; + break; + } + + return ret; +} + +template +static DEFREAD(MainCPU_ReadVector) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += MEMCYC_SLOW; + } + // + if(MainCPUControl & (w ? 0x40 : 0x10)) + return *(MainVectors + (w << 1) + (A & 1)); + + return ReadROM(0, A); +} + +template +static DEFREAD(ReadROM) +{ + if(SA1Side) + SA1CPU::CPUM.timestamp += 2; + else + { + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += (T_Region >= 2) ? (MemSelect ? MEMCYC_FAST : MEMCYC_SLOW) : MEMCYC_SLOW; + } + } + // + uint8 ret = ReadROM(T_Region, A);; + + if(SA1Side && T_Region == 0 && (uint16)A >= 0xFFE0) + ret = (ret & SA1VectorMask[A & 0xF]) | SA1VectorSpace[A & 0xF]; + + return ret; +} + +template +static DEFREAD(ReadBWRAM_40_43) +{ + if(SA1Side) + SA1CPU::CPUM.timestamp += 4; + else + { + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += MEMCYC_SLOW; + // + Update(CPUM.timestamp); + } + } + // + if(!SA1Side && DMACharConvAutoActive) + return DMA_ReadCCVBWRAM(); + // + return Cart.RAM[A & Cart.RAM_Mask]; +} + +template +static DEFWRITE(WriteBWRAM_40_43) +{ + if(SA1Side) + SA1CPU::CPUM.timestamp += 4; + else + { + CPUM.timestamp += MEMCYC_SLOW; + // + Update(CPUM.timestamp); + } + // + if(!BWRAMWriteEnable[SA1Side] && (A & 0x3FFFF) < (256U << BWRAMWriteProtectSize)) + { + SNES_DBG("[SA1] %d, BWRAM write blocked; 0x%06x 0x%02x\n", SA1Side, A, V); + //return; + } + + //printf("SA1CPU BWRAM write %08x %02x\n", A, V); + + Cart.RAM[A & Cart.RAM_Mask] = V; +} + +static DEFREAD(MainCPU_ReadBWRAM_Banked) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += MEMCYC_SLOW; + // + Update(CPUM.timestamp); + } + // + return Cart.RAM[((A & 0x1FFF) + (MainBWRAMBank << 13)) & Cart.RAM_Mask]; +} + +static DEFWRITE(MainCPU_WriteBWRAM_Banked) +{ + CPUM.timestamp += MEMCYC_SLOW; + // + Update(CPUM.timestamp); + // + //if(!BWRAMWriteEnable[0]) + //{ + // SNES_DBG("[SA1] BWRAM write blocked; 0x%06x 0x%02x\n", A, V); + // return; + //} + + Cart.RAM[((A & 0x1FFF) + (MainBWRAMBank << 13)) & Cart.RAM_Mask] = V; +} + +static INLINE uint8 ReadBWBitmap(uint32 A) +{ + uint8 ret; + + if(BWRAMBitmapFormat) + { + ret = (Cart.RAM[(A >> 2) & Cart.RAM_Mask] >> ((A & 3) << 1)) & 0x3; + //ret |= ret << 2; + //ret |= ret << 4; + } + else + { + ret = (Cart.RAM[(A >> 1) & Cart.RAM_Mask] >> ((A & 1) << 2)) & 0xF; + //ret ^= rand() & 0xF0; + } + + return ret; +} + + +static INLINE void WriteBWBitmap(uint32 A, uint8 V) +{ + if(BWRAMBitmapFormat) // 2-bit + { + //printf("Awesomewrite: %08x %02x --- %08x\n", A, V, (A >> 2) & Cart.RAM_Mask); + const unsigned shift = (A & 3) << 1; + uint8* const p = &Cart.RAM[(A >> 2) & Cart.RAM_Mask]; + + *p = (*p & ~(0x3 << shift)) | ((V & 0x3) << shift); + } + else // 4-bit + { + const unsigned shift = (A & 1) << 2; + uint8* const p = &Cart.RAM[(A >> 1) & Cart.RAM_Mask]; + + *p = (*p & (0xF0 >> shift)) | ((V & 0xF) << shift); + } +} + +static DEFREAD(SA1CPU_ReadBWRAM_Banked) +{ + SA1CPU::CPUM.timestamp += 4; + // + //if(SA1BWRAMBank & 0x80) + // return rand(); + const size_t bwram_index = (A & 0x1FFF) + ((SA1BWRAMBank & 0x7F) << 13); + + if(SA1BWRAMBank & 0x80) + return ReadBWBitmap(bwram_index); + else + return Cart.RAM[bwram_index & Cart.RAM_Mask]; +} + +static DEFWRITE(SA1CPU_WriteBWRAM_Banked) +{ + SA1CPU::CPUM.timestamp += 4; + // + //if(!BWRAMWriteEnable[1]) + //{ + // SNES_DBG("[SA1CPU] BWRAM write blocked; 0x%06x 0x%02x\n", A, V); + // return; + //} + + const size_t bwram_index = (A & 0x1FFF) + ((SA1BWRAMBank & 0x7F) << 13); + + //printf("MOO: %08x %zu %02x\n", A, bwram_index, V); + + //WriteBWBitmap(A, V); + if(SA1BWRAMBank & 0x80) + WriteBWBitmap(bwram_index, V); + else + Cart.RAM[bwram_index & Cart.RAM_Mask] = V; +} + +static DEFREAD(SA1CPU_ReadBWRAM_Bitmap) +{ + SA1CPU::CPUM.timestamp += 4; + // + return ReadBWBitmap(A); +} + +static DEFWRITE(SA1CPU_WriteBWRAM_Bitmap) +{ + SA1CPU::CPUM.timestamp += 4; + // + if(!BWRAMWriteEnable[1]) + { + SNES_DBG("[SA1CPU] BWRAM write blocked; 0x%06x 0x%02x\n", A, V); + return; + } + + //printf("awesome BORP: %08x %02x\n", A, V); + + WriteBWBitmap(A, V); +} + +static DEFWRITE(SA1CPU_OBWrite) +{ + SA1CPU::CPUM.timestamp += 2; + // + SNES_DBG("[SA1CPU] Unknown Write: $%02x:%04x $%02x\n", A >> 16, A & 0xFFFF, V); +} + +static DEFREAD(SA1CPU_OBRead) +{ + SA1CPU::CPUM.timestamp += 2; + // + SNES_DBG("[SA1CPU] Unknown Read: $%02x:%04x\n", A >> 16, A & 0xFFFF); + return CPUM.mdr; +} + +static void VarLen_Start(void) +{ + VarLenCurBitOffs = 0; + VarLenCurAddr = VarLenAddr; + VarLenBuffer = 0; + for(unsigned i = 0; i < 3; i++) + { + uint8 tmp = DMA_ReadROM(VarLenCurAddr & 0xFFFFFF); + //printf("VARLEN Buffer: %02x\n", tmp); + VarLenBuffer |= tmp << (i << 3); + VarLenCurAddr++; + } +} +static void VarLen_Advance(void) +{ + VarLenCurBitOffs += ((VarLenControl - 1) & 0xF) + 1; + while(VarLenCurBitOffs >= 8) + { + VarLenCurBitOffs -= 8; + VarLenBuffer >>= 8; + uint8 tmp = DMA_ReadROM(VarLenCurAddr & 0xFFFFFF); + //printf("VARLEN Buffer: %02x\n", tmp); + VarLenBuffer |= tmp << 16; + VarLenCurAddr++; + } +} + +template +static DEFWRITE(SA1CPU_WriteIO) +{ + SA1CPU::CPUM.timestamp += 2; + // + SNES_DBG("[SA1CPU] IO Write 0x%06x 0x%02x\n", T_A, V); + switch(T_A) + { + default: + SNES_DBG("[SA1CPU] Unknown Write: $%02x:%04x $%02x\n", A >> 16, A & 0xFFFF, V); + break; + + case 0x2209: + { + //const uint8 old_MainCPUControl = MainCPUControl; + + if(V & MainCPUIRQEnable & 0x80) + { + MainCPUIRQPending |= 0x80; + CPU_SetIRQ(MainCPUIRQPending, CPU_IRQSOURCE_CART); + } + MainCPUControl = V & 0x5F; + } + break; + + case 0x220A: + SA1CPUIRQEnable = V & 0xF0; + break; + + case 0x220B: + SA1CPUIRQPending &= ~V; + SA1CPU::CPU_SetNMI(SA1CPUIRQPending & 0x10); + SA1CPU::CPU_SetIRQ(SA1CPUIRQPending & 0xE0); + break; + + case 0x220C: + case 0x220D: + case 0x220E: + case 0x220F: + MainVectors[T_A & 0x3] = V; + break; + + case 0x2225: + SA1BWRAMBank = V; + break; + + case 0x2227: + BWRAMWriteEnable[1] = V >> 7; + break; + + case 0x222A: + IWRAMWriteEnable[1] = V; + break; + + case 0x2230: + DMAControl = V & 0xF7; + //printf("CharConv DMAControl=%02x\n", DMAControl); + break; + + case 0x2231: + case 0x2232: + case 0x2233: + case 0x2234: + case 0x2235: + case 0x2236: + case 0x2237: + WriteSharedDMAReg(SA1CPU::CPUM.timestamp, A, V); + break; + + case 0x2238: + DMALength = (DMALength & 0xFF00) | (V << 0); + break; + + case 0x2239: + DMALength = (DMALength & 0x00FF) | (V << 8); + break; + + case 0x223F: + BWRAMBitmapFormat = V >> 7; + break; + + case 0x2240: + case 0x2241: + case 0x2242: + case 0x2243: + case 0x2244: + case 0x2245: + case 0x2246: + case 0x2247: + case 0x2248: + case 0x2249: + case 0x224A: + case 0x224B: + case 0x224C: + case 0x224D: + case 0x224E: + case 0x224F: + WriteCharConvBMReg(T_A & 0xF, V); + break; + + case 0x2250: + MathControl = V & 0x3; + if(V & 2) + MathResult = 0; + break; + + case 0x2251: MathParam[0] = (MathParam[0] & 0xFF00) | (V << 0); break; + case 0x2252: MathParam[0] = (MathParam[0] & 0x00FF) | (V << 8); break; + case 0x2253: MathParam[1] = (MathParam[1] & 0xFF00) | (V << 0); break; + case 0x2254: + MathParam[1] = (MathParam[1] & 0x00FF) | (V << 8); + switch(MathControl) + { + case 0: + MathResult = (int16)MathParam[0] * (int16)MathParam[1]; + break; + + case 1: + if(!MathParam[1]) + MathResult = 0; + else + { + uint16 a = (int16)MathParam[0] / (uint16)MathParam[1]; + uint16 b = (int16)MathParam[0] % (uint16)MathParam[1]; + + MathResult = a | ((uint32)b << 16); + } + break; + + case 2: + MathResult = MathResult + (int16)MathParam[0] * (int16)MathParam[1]; + //if((int64)MathResult < + // TODO/FIXME: overflow + break; + + case 3: + assert(0); + break; + + } + break; + + case 0x2258: + //printf("VARLEN Write: %08x %02x\n", A, V); + VarLenControl = V & 0x8F; + VarLen_Advance(); + break; + + case 0x2259: + //printf("VARLEN Write: %08x %02x\n", A, V); + VarLenAddr = (VarLenAddr & 0xFFFF00) | (V << 0); + break; + + case 0x225A: + //printf("VARLEN Write: %08x %02x\n", A, V); + VarLenAddr = (VarLenAddr & 0xFF00FF) | (V << 8); + break; + + case 0x225B: + //printf("VARLEN Write: %08x %02x\n", A, V); + VarLenAddr = (VarLenAddr & 0x00FFFF) | (V << 16); + VarLen_Start(); + break; + + } +} + +template +static DEFREAD(SA1CPU_ReadIO) +{ + SA1CPU::CPUM.timestamp += 2; + // + uint8 ret = 0x00; + + SNES_DBG("[SA1CPU] IO Read 0x%06x\n", A); + switch(T_A) + { + default: + SNES_DBG("[SA1CPU] Unknown Read: $%02x:%04x\n", A >> 16, A & 0xFFFF); + break; + + case 0x2301: + ret = (SA1CPUControl & 0x0F) | SA1CPUIRQPending; + break; + + case 0x2306: + case 0x2307: + case 0x2308: + case 0x2309: + case 0x230A: + ret = MathResult >> (((T_A - 0x2306) & 0x7) << 3); + break; + // + // + case 0x230C: + ret = VarLenBuffer >> VarLenCurBitOffs; + //printf("VARLEN Read: %08x %02x\n", A, ret); + break; + + case 0x230D: + ret = VarLenBuffer >> (8 + VarLenCurBitOffs); + if(VarLenControl & 0x80) + VarLen_Advance(); + + //printf("VARLEN Read: %08x %02x\n", A, ret); + break; + + } + + return ret; +} + +static void Reset(bool powering_up) +{ + if(powering_up) + SA1CPU::CPU_Reset(true); + // + // + memset(SA1VectorSpace, 0, sizeof(SA1VectorSpace)); + memset(MainVectors, 0, sizeof(MainVectors)); + + SA1CPUControl = 0x20; + SA1CPU::CPUM.halted = SA1CPU::CPU_Misc::HALTED_DMA; + SA1CPUIRQEnable = 0; + SA1CPUIRQPending = 0; + + MainCPUControl = 0; + MainCPUIRQEnable = 0; + MainCPUIRQPending = 0; + CPU_SetIRQ(MainCPUIRQPending, CPU_IRQSOURCE_CART); + + DMAControl = 0; + DMACharConvParam = 0; + DMASourceAddr = 0; + DMADestAddr = 0; + DMALength = 0; + DMAFinishTS = 0x7FFFFFFF; + + DMACharConvAutoActive = false; + DMACharConvSourceXTile = 0; + DMACharConvSourceYTile = 0; + DMACharConvCCVBWRAMCounter = 0; + memset(CharConvBMRegs, 0, sizeof(CharConvBMRegs)); + CharConvTileY = 0; + + for(unsigned i = 0; i < 4; i++) + { + ROMBank[i] = i; + RecalcROMPtr(i); + } + + MainBWRAMBank = 0; + SA1BWRAMBank = 0; + for(unsigned i = 0; i < 2; i++) + { + BWRAMWriteEnable[i] = false; + IWRAMWriteEnable[i] = 0x00; + } + BWRAMWriteProtectSize = 0; // ? + + BWRAMBitmapFormat = 0; + + MathControl = 0; + for(unsigned i = 0; i < 2; i++) + MathParam[i] = 0; + MathResult = 0; + + VarLenControl = 0; + VarLenAddr = 0; + VarLenCurAddr = 0; + VarLenCurBitOffs = 0; + VarLenBuffer = 0; + + if(powering_up) + memset(IRAM, 0, sizeof(IRAM)); +} + +static void StateAction(StateMem* sm, const unsigned load, const bool data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(SA1VectorSpace), // FIXME/TODO: cleaner + SFVAR(MainVectors), + + SFVAR(SA1CPUControl), + SFVAR(SA1CPUIRQEnable), + SFVAR(SA1CPUIRQPending), + + SFVAR(MainCPUControl), + SFVAR(MainCPUIRQEnable), + SFVAR(MainCPUIRQPending), + + SFVAR(DMAControl), + SFVAR(DMACharConvParam), + SFVAR(DMASourceAddr), + SFVAR(DMADestAddr), + SFVAR(DMALength), + SFVAR(DMAFinishTS), + + SFVAR(DMACharConvAutoActive), + SFVAR(DMACharConvSourceXTile), + SFVAR(DMACharConvSourceYTile), + SFVAR(DMACharConvCCVBWRAMCounter), + SFVAR(CharConvBMRegs), + SFVAR(CharConvTileY), + + SFVAR(ROMBank), + + SFVAR(MainBWRAMBank), + SFVAR(SA1BWRAMBank), + SFVAR(BWRAMWriteEnable), + SFVAR(BWRAMWriteProtectSize), + SFVAR(IWRAMWriteEnable), + + SFVAR(BWRAMBitmapFormat), + +// + SFVAR(MathControl), + SFVAR(MathParam), + SFVAR(MathResult), + + SFVAR(VarLenControl), + SFVAR(VarLenAddr), + SFVAR(VarLenCurAddr), + SFVAR(VarLenCurBitOffs), + SFVAR(VarLenBuffer), + + SFVAR(IRAM), +// + SFVAR(SA1CPU::CPUM.timestamp), + + SFEND + }; + + MDFNSS_StateAction(sm, load, data_only, StateRegs, "SA1"); + + SA1CPU::CPU_StateAction(sm, load, data_only, "SA1CPU", "SA1CPUCORE"); + + if(load) + { + for(unsigned w = 0; w < 4; w++) + RecalcROMPtr(w); + } +} + + +void CART_SA1_Init(const int32 master_clock) +{ + for(unsigned i = 0; i < 0x10; i++) + { + SA1VectorMask[i] = (i >= 0xA) ? 0x00 : 0xFF; + SA1VectorSpace[i] = 0; + } + + SA1CPU::CPU_Init(); + SA1CPU::CPU_ClearRWFuncs(); + SA1CPU::CPU_SetRWHandlers(0x000000, 0xFFFFFF, SA1CPU_OBRead, SA1CPU_OBWrite); + + Set_A_Handlers((0x40 << 16) | 0x0000, (0x7D << 16) | 0xFFFF, OBRead_SLOW, OBWrite_SLOW); + + for(unsigned bank = 0x00; bank < 0x100; bank++) + { + if(bank >= 0x40 && bank <= 0x4F) + { + if(Cart.RAM_Mask != SIZE_MAX) + { + Set_A_Handlers((bank << 16) | 0x0000, (bank << 16) | 0xFFFF, ReadBWRAM_40_43, WriteBWRAM_40_43); + SA1CPU::CPU_SetRWHandlers((bank << 16) | 0x0000, (bank << 16) | 0xFFFF, ReadBWRAM_40_43, WriteBWRAM_40_43); + } + } + else if(!(bank & 0x40)) + { + readfunc rf; + readfunc sa1cpu_rf; + + if(bank < 0x20) + { + rf = ReadROM<0, false>; + sa1cpu_rf = ReadROM<0, true>; + } + else if(bank < 0x40) + { + rf = ReadROM<1, false>; + sa1cpu_rf = ReadROM<1, true>; + } + else if(bank < 0xA0) + { + rf = ReadROM<2, false>; + sa1cpu_rf = ReadROM<2, true>; + } + else if(bank < 0xC0) + { + rf = ReadROM<3, false>; + sa1cpu_rf = ReadROM<3, true>; + } + + Set_A_Handlers((bank << 16) | 0x8000, (bank << 16) | 0xFFFF, rf, OBWrite_SLOW); + SA1CPU::CPU_SetRWHandlers((bank << 16) | 0x8000, (bank << 16) | 0xFFFF, sa1cpu_rf, SA1CPU_OBWrite); + + if(!bank) + { + for(unsigned i = 0; i < 4; i++) + { + const unsigned offs = (i & 1) + ((i & 2) << 3); + Set_A_Handlers(0xFFEA + offs, MainCPU_ReadVector<0>, OBWrite_SLOW); + Set_A_Handlers(0xFFEE + offs, MainCPU_ReadVector<1>, OBWrite_SLOW); + } + } + } + else if(bank >= 0xC0) + { + readfunc rf; + readfunc sa1cpu_rf; + + if(bank < 0xD0) + { + rf = ReadROM<4, false>; + sa1cpu_rf = ReadROM<4, true>; + } + else if(bank < 0xE0) + { + rf = ReadROM<5, false>; + sa1cpu_rf = ReadROM<5, true>; + } + else if(bank < 0xF0) + { + rf = ReadROM<6, false>; + sa1cpu_rf = ReadROM<6, true>; + } + else + { + rf = ReadROM<7, false>; + sa1cpu_rf = ReadROM<7, true>; + } + + Set_A_Handlers((bank << 16) | 0x0000, (bank << 16) | 0xFFFF, rf, OBWrite_VAR); + SA1CPU::CPU_SetRWHandlers((bank << 16) | 0x0000, (bank << 16) | 0xFFFF, sa1cpu_rf, SA1CPU_OBWrite); + } + // + // + // + if(bank >= 0x60 && bank <= 0x6F) + { + SA1CPU::CPU_SetRWHandlers((bank << 16) | 0x0000, (bank << 16) | 0xFFFF, SA1CPU_ReadBWRAM_Bitmap, SA1CPU_WriteBWRAM_Bitmap); + } + + // + // + // + if(!(bank & 0x40)) + { + Set_A_Handlers((bank << 16) | 0x3000, (bank << 16) | 0x37FF, ReadIRAM, WriteIRAM); + SA1CPU::CPU_SetRWHandlers((bank << 16) | 0x3000, (bank << 16) | 0x37FF, ReadIRAM, WriteIRAM); + SA1CPU::CPU_SetRWHandlers((bank << 16) | 0x0000, (bank << 16) | 0x07FF, ReadIRAM, WriteIRAM); + + if(Cart.RAM_Mask != SIZE_MAX) + { + Set_A_Handlers((bank << 16) | 0x6000, (bank << 16) | 0x7FFF, MainCPU_ReadBWRAM_Banked, MainCPU_WriteBWRAM_Banked); + SA1CPU::CPU_SetRWHandlers((bank << 16) | 0x6000, (bank << 16) | 0x7FFF, SA1CPU_ReadBWRAM_Banked, SA1CPU_WriteBWRAM_Banked); + } + + SA1CPU::CPU_SetRWHandlers((bank << 16) | 0x2200, (bank << 16) | 0x23FF, SA1CPU_OBRead, SA1CPU_OBWrite, true); + + #define MHW(a) Set_A_Handlers((bank << 16) | a, OBRead_FAST, MainCPU_WriteIO); + MHW(0x2200) + MHW(0x2201) + MHW(0x2202) + MHW(0x2203) + MHW(0x2204) + MHW(0x2205) + MHW(0x2206) + MHW(0x2207) + MHW(0x2208) + MHW(0x2220) + MHW(0x2221) + MHW(0x2222) + MHW(0x2223) + MHW(0x2224) + MHW(0x2226) + MHW(0x2228) + MHW(0x2229) + MHW(0x2231) + MHW(0x2232) + MHW(0x2233) + MHW(0x2234) + MHW(0x2235) + MHW(0x2236) + MHW(0x2237) + #undef MHW + + #define MHR(a) Set_A_Handlers((bank << 16) | a, MainCPU_ReadIO, OBWrite_FAST); + MHR(0x2300) + MHR(0x230E) + #undef MHR + + #define SHW(a) SA1CPU::CPU_SetRWHandlers((bank << 16) | a, (bank << 16) | a, SA1CPU_OBRead, SA1CPU_WriteIO, true); + SHW(0x2209) + SHW(0x220A) + SHW(0x220B) + SHW(0x220C) + SHW(0x220D) + SHW(0x220E) + SHW(0x220F) + SHW(0x2210) + SHW(0x2211) + SHW(0x2212) + SHW(0x2213) + SHW(0x2214) + SHW(0x2215) + SHW(0x2225) + SHW(0x2227) + SHW(0x222A) + SHW(0x2230) + SHW(0x2231) + SHW(0x2232) + SHW(0x2233) + SHW(0x2234) + SHW(0x2235) + SHW(0x2236) + SHW(0x2237) + SHW(0x2238) + SHW(0x2239) + SHW(0x223F) + SHW(0x2240) + SHW(0x2241) + SHW(0x2242) + SHW(0x2243) + SHW(0x2244) + SHW(0x2245) + SHW(0x2246) + SHW(0x2247) + SHW(0x2248) + SHW(0x2249) + SHW(0x224A) + SHW(0x224B) + SHW(0x224C) + SHW(0x224D) + SHW(0x224E) + SHW(0x224F) + SHW(0x2250) + SHW(0x2251) + SHW(0x2252) + SHW(0x2253) + SHW(0x2254) + SHW(0x2258) + SHW(0x2259) + SHW(0x225A) + SHW(0x225B) + #undef SHW + + #define SHR(a) SA1CPU::CPU_SetRWHandlers((bank << 16) | a, (bank << 16) | a, SA1CPU_ReadIO, SA1CPU_OBWrite, true); + SHR(0x2301) + SHR(0x2302) + SHR(0x2303) + SHR(0x2304) + SHR(0x2305) + SHR(0x2306) + SHR(0x2307) + SHR(0x2308) + SHR(0x2309) + SHR(0x230A) + SHR(0x230B) + SHR(0x230C) + SHR(0x230D) + #undef SHR + } + } + // + // + // + Cart.Reset = Reset; + Cart.EventHandler = EventHandler; + Cart.AdjustTS = AdjustTS; + Cart.StateAction = StateAction; +} + +} diff --git a/mednafen/snes_faust/cart/sa1.h b/mednafen/snes_faust/cart/sa1.h new file mode 100644 index 0000000..908d56d --- /dev/null +++ b/mednafen/snes_faust/cart/sa1.h @@ -0,0 +1,31 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* sa1.h: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __MDFN_SNES_FAUST_CART_SA1_H +#define __MDFN_SNES_FAUST_CART_SA1_H + +namespace MDFN_IEN_SNES_FAUST +{ + +void CART_SA1_Init(const int32 master_clock) MDFN_COLD; + +} +#endif diff --git a/mednafen/snes_faust/cart/sa1cpu.cpp b/mednafen/snes_faust/cart/sa1cpu.cpp new file mode 100644 index 0000000..4d30ea2 --- /dev/null +++ b/mednafen/snes_faust/cart/sa1cpu.cpp @@ -0,0 +1,91 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* sa1.cpp: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "common.h" +#include "sa1.h" +#include "sa1cpu.h" + +namespace MDFN_IEN_SNES_FAUST +{ +namespace SA1CPU +{ +// +// +#ifdef SNES_DBG_ENABLE +static INLINE void DBG_CPUHook(uint32 PCPBR, uint8 P) +{ + +} +#endif + +#include "../cpu_hlif.inc" +// +// +void CPU_ClearRWFuncs(void) +{ + memset(CPUM.ReadFuncs, 0, sizeof(CPUM.ReadFuncs)); + memset(CPUM.WriteFuncs, 0, sizeof(CPUM.WriteFuncs)); +} + +void CPU_SetRWHandlers(uint32 A1, uint32 A2, readfunc read_handler, writefunc write_handler, bool special) +{ + if(special) + { + assert(!((A1 ^ A2) >> 9)); + + CPUM.RWIndex[A1 >> 9] = 0; + + for(uint32 A = A1; A <= A2; A++) + { + const size_t am = A & 0x1FF; + + //assert((!CPUM.ReadFuncs[am] && !CPUM.WriteFuncs[am]) || (CPUM.ReadFuncs[am] == read_handler && CPUM.WriteFuncs[am] == write_handler)); + + CPUM.ReadFuncs[am] = read_handler; + CPUM.WriteFuncs[am] = write_handler; + } + } + else + { + assert(!(A1 & 0x1FF) && (A2 & 0x1FF) == 0x1FF); + assert(A1 <= A2); + assert((A2 >> 9) < 0x8000); + + size_t index = 512; + + while(index < (512 + 256) && CPUM.ReadFuncs[index] && CPUM.WriteFuncs[index] && (CPUM.ReadFuncs[index] != read_handler || CPUM.WriteFuncs[index] != write_handler)) + index++; + + assert(index < (512 + 256)); + + CPUM.ReadFuncs[index] = read_handler; + CPUM.WriteFuncs[index] = write_handler; + + for(uint32 A = A1; A <= A2; A += 512) + CPUM.RWIndex[A >> 9] = index; + + CPUM.RWIndex[0x8000] = CPUM.RWIndex[0x7FFF]; + } +} +// +// +} +} diff --git a/mednafen/snes_faust/cart/sa1cpu.h b/mednafen/snes_faust/cart/sa1cpu.h new file mode 100644 index 0000000..3b86d9b --- /dev/null +++ b/mednafen/snes_faust/cart/sa1cpu.h @@ -0,0 +1,132 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* sa1cpu.h: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __MDFN_SNES_FAUST_CART_SA1CPU_H +#define __MDFN_SNES_FAUST_CART_SA1CPU_H + +namespace MDFN_IEN_SNES_FAUST +{ +namespace SA1CPU +{ +// +// +class CPU65816; + +struct CPU_Misc +{ + uint32 timestamp; + uint32 next_event_ts; + uint32 running_mask; + uint32 PIN_Delay; + + enum + { + HALTED_NOT = 0, + HALTED_WAI = 1 << 0, + HALTED_STP = 1 << 1, + HALTED_DMA = 1 << 2 + }; + + uint8 halted; + uint8 mdr; + + uint8 CombinedNIState; + bool NMILineState; + bool PrevNMILineState; + uint8 MultiIRQState; + enum { IRQNMISuppress = false }; + + readfunc ReadFuncs[512 + 256]; + writefunc WriteFuncs[512 + 256]; + + // +1 so we can avoid a masking for 16-bit reads/writes(note that this + // may result in the address passed to the read/write handlers being + // 0x1000000 instead of 0x000000 in some cases, so code with that in mind. + uint16 RWIndex[0x8000 + 1]; // (2**24 / 512) + // + // + // + void RunDMA(void) MDFN_HOT; + void EventHandler(void) MDFN_HOT; +}; + +extern CPU_Misc CPUM; + +INLINE uint8 CPU_Read(uint32 A) +{ + const size_t i = CPUM.RWIndex[A >> 9]; + uint8 ret = CPUM.ReadFuncs[i ? i : (A & 0x1FF)](A); + + CPUM.mdr = ret; + + return ret; +} + +INLINE void CPU_Write(uint32 A, uint8 V) +{ + const size_t i = CPUM.RWIndex[A >> 9]; + CPUM.mdr = V; + CPUM.WriteFuncs[i ? i : (A & 0x1FF)](A, V); +} + +INLINE void CPU_IO(void) +{ + CPUM.timestamp += 2; +} + +INLINE void CPU_SetIRQ(bool active) +{ + CPUM.CombinedNIState &= ~0x04; + CPUM.CombinedNIState |= active ? 0x04 : 0x00; +} + +INLINE void CPU_SetNMI(bool active) +{ + if((CPUM.NMILineState ^ active) & active) + CPUM.CombinedNIState |= 0x01; + + CPUM.NMILineState = active; +} + +INLINE void CPU_SetIRQNMISuppress(bool active) +{ + CPUM.CombinedNIState &= ~0x80; + CPUM.CombinedNIState |= active ? 0x80 : 0x00; +} + +void CPU_Init(void) MDFN_COLD; +void CPU_Reset(bool powering_up) MDFN_COLD; +void CPU_StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname, const char* sname_core); +void CPU_Run(void) MDFN_HOT; + +void CPU_ClearRWFuncs(void) MDFN_COLD; +void CPU_SetRWHandlers(uint32 A1, uint32 A2, readfunc read_handler, writefunc write_handler, bool special = false) MDFN_COLD; + +INLINE void CPU_Exit(void) +{ + CPUM.running_mask = 0; + CPUM.next_event_ts = 0; +} +// +// +} +} +#endif diff --git a/mednafen/snes_faust/cart/sdd1.cpp b/mednafen/snes_faust/cart/sdd1.cpp new file mode 100644 index 0000000..192871b --- /dev/null +++ b/mednafen/snes_faust/cart/sdd1.cpp @@ -0,0 +1,164 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* sdd1.cpp: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "common.h" +#include "sdd1.h" + +namespace MDFN_IEN_SNES_FAUST +{ + +static uint8 ROMBank[4]; +static uintptr_t ROMBankPtr[4]; + +static INLINE void RecalcROMBankPtr(size_t rbi) +{ + ROMBankPtr[rbi] = (uintptr_t)&Cart.ROM[(ROMBank[rbi] & 0x7) << 20] - (0xC00000 + (rbi << 20)); +} + +template +static DEFREAD(MainCPU_ReadFixedROM) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += (cyc >= 0) ? cyc : (MemSelect ? MEMCYC_FAST : MEMCYC_SLOW); + } + // + // + return Cart.ROM[A & 0x7FFF]; +} + +template +static DEFREAD(MainCPU_ReadBankedROM) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += (cyc >= 0) ? cyc : (MemSelect ? MEMCYC_FAST : MEMCYC_SLOW); + } + // + // + return *(uint8*)(ROMBankPtr[(A >> 20) & 0x3] + A); +} + +template +static DEFWRITE(MainCPU_WriteIO) +{ + CPUM.timestamp += (cyc >= 0) ? cyc : (MemSelect ? MEMCYC_FAST : MEMCYC_SLOW); + // + // + SNES_DBG("[SDD1] IO write 0x%06x 0x%02x\n", A, V); + + switch(w) + { + case 0x4: + case 0x5: + case 0x6: + case 0x7: + { + size_t rbi = w & 0x3; + ROMBank[rbi] = V; + RecalcROMBankPtr(rbi); + } + break; + } +} + +template +static DEFREAD(MainCPU_ReadIO) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + { + CPUM.timestamp += (cyc >= 0) ? cyc : (MemSelect ? MEMCYC_FAST : MEMCYC_SLOW); + } + // + // + uint8 ret = 0; + + SNES_DBG("[SDD1] IO read 0x%06x\n", A); + + switch(w) + { + case 0x4: + case 0x5: + case 0x6: + case 0x7: + ret = ROMBank[w & 0x3]; + break; + } + + return ret; +} + +static MDFN_COLD void Reset(bool powering_up) +{ + for(size_t rbi = 0; rbi < 4; rbi++) + { + ROMBank[rbi] = 0; + RecalcROMBankPtr(rbi); + } +} + +static void StateAction(StateMem* sm, const unsigned load, const bool data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(ROMBank), + SFEND + }; + + MDFNSS_StateAction(sm, load, data_only, StateRegs, "SDD1"); + + if(load) + { + for(size_t rbi = 0; rbi < 4; rbi++) + RecalcROMBankPtr(rbi); + } +} + +void CART_SDD1_Init(const int32 master_clock) +{ + puts("SDD1"); + Set_A_Handlers(0x008000, 0x00FFFF, MainCPU_ReadFixedROM, OBWrite_SLOW); + Set_A_Handlers(0xC00000, 0xFFFFFF, MainCPU_ReadBankedROM<-1>, OBWrite_VAR); + + for(unsigned bank = 0x00; bank < 0x100; bank++) + { + if(!(bank & 0x40)) + { + #define SHP(ta) Set_A_Handlers((bank << 16) | (0x4800 + ta), MainCPU_ReadIO, MainCPU_WriteIO); + SHP(0x0) + SHP(0x1) + SHP(0x2) + SHP(0x3) + SHP(0x4) + SHP(0x5) + SHP(0x6) + SHP(0x7) + #undef SHP + } + } + // + // + // + Cart.Reset = Reset; + Cart.StateAction = StateAction; +} + +} diff --git a/mednafen/snes_faust/cart/sdd1.h b/mednafen/snes_faust/cart/sdd1.h new file mode 100644 index 0000000..a8f4504 --- /dev/null +++ b/mednafen/snes_faust/cart/sdd1.h @@ -0,0 +1,31 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* sdd1.h: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __MDFN_SNES_FAUST_CART_SDD1_H +#define __MDFN_SNES_FAUST_CART_SDD1_H + +namespace MDFN_IEN_SNES_FAUST +{ + +void CART_SDD1_Init(const int32 master_clock) MDFN_COLD; + +} +#endif diff --git a/mednafen/snes_faust/cart/superfx.cpp b/mednafen/snes_faust/cart/superfx.cpp new file mode 100644 index 0000000..ea9a008 --- /dev/null +++ b/mednafen/snes_faust/cart/superfx.cpp @@ -0,0 +1,1849 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* superfx.cpp: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* + TODO: + Correctly handle differences between MC1, GSU1, GSU2(especially in regards to memory maps). + + Correct timings(also clock source vs NTSC/PAL vs MC1/GSUn). + + Test multiplication performance when running from uncached ROM/RAM. + + Correct handling of Rd == 4 in FMULT and LMULT(run tests). + + Test SBK behavior when immediately after each of the various RAM access instructions. + + +*/ + +#include "common.h" +#include "superfx.h" + +namespace MDFN_IEN_SNES_FAUST +{ + +static uint16 R[16 + 1]; +static uint8 Prefetch; +static size_t PrefixSL8; // 0, 1, 2, 3; << 8 +static bool PrefixB; + +static uint8 Rs; +static uint8 Rd; + +static const uint8* ProgMemMap[0x80]; +static size_t ProgMemMapMask[0x80]; +static const uint8* PBR_Ptr; +static size_t PBR_Ptr_Mask; +static uint8 PBR; +static uint16 CBR; +static uint8 ROMBR; +static uint8 RAMBR; +static uint8 VCR; +static bool ClockSelect; +static bool MultSpeed; + +static uint8 SCBR; +static uint8 SCMR; +static uint8 POR; +static uint8 ColorData; + +static struct +{ + uint8 TagX; + uint8 TagY; + uint8 data[8]; + uint8 opaque; +} PixelCache; +// +// +// +static uint8 CacheData[0x200]; +static bool CacheValid[0x20]; + +static uint8 ROMBuffer; + +static uint16 LastRAMOffset; + +static bool FlagV, FlagS, FlagC, FlagZ; +static bool Running; +static bool IRQPending; +static bool IRQMask; + +static uint8 GPRWriteLatch; + +static uint32 superfx_timestamp; +static uint32 rom_read_finish_ts; +static uint32 ram_write_finish_ts; +static uint32 pixcache_write_finish_ts; + +static uint32 cycles_per_op; +static uint32 cycles_per_rom_read; +static uint32 cycles_per_ram; +static uint32 cycles_per_8x8mult; +static uint32 cycles_per_16x16mult; +// +// +// +static void RecalcMultTiming(void) +{ + SNES_DBG("[SuperFX] Clock speed: %d, mult speed: %d\n", ClockSelect, MultSpeed); + + // FIXME: timings + if(ClockSelect | MultSpeed) + { + cycles_per_16x16mult = 6; + cycles_per_8x8mult = 0; + } + else + { + cycles_per_16x16mult = 14; + cycles_per_8x8mult = 2; + } +} + +static INLINE void SetCFGR(uint8 val) +{ + MultSpeed = (val >> 5) & 1; + IRQMask = val >> 7; + CPU_SetIRQ(IRQPending & !IRQMask, CPU_IRQSOURCE_CART); + // + RecalcMultTiming(); +} + +static INLINE void SetCLSR(uint8 val) +{ + ClockSelect = val & 0x1; + // + if(ClockSelect) + { + cycles_per_op = 1; + cycles_per_rom_read = 5; + cycles_per_ram = 3; + } + else + { + cycles_per_op = 2; + cycles_per_rom_read = 6; + cycles_per_ram = 3; + } + // + RecalcMultTiming(); +} + +static INLINE void SetPBR(uint8 val) +{ + PBR = val; + PBR_Ptr = ProgMemMap[val & 0x7F]; + PBR_Ptr_Mask = ProgMemMapMask[val & 0x7F]; +} + +static void DoROMRead(void) +{ + if(superfx_timestamp < rom_read_finish_ts) + { + //printf("DoROMRead() delay: %d\n", rom_read_finish_ts - superfx_timestamp); + } + superfx_timestamp = std::max(superfx_timestamp, rom_read_finish_ts); + ROMBuffer = ProgMemMap[ROMBR & 0x7F][R[14] & ProgMemMapMask[ROMBR & 0x7F]]; + rom_read_finish_ts = superfx_timestamp + cycles_per_rom_read; +} + +static uint8 GetROMBuffer(void) +{ + if(superfx_timestamp < rom_read_finish_ts) + { + //printf("GetROMBuffer() delay: %d\n", rom_read_finish_ts - superfx_timestamp); + } + superfx_timestamp = std::max(superfx_timestamp, rom_read_finish_ts); + + return ROMBuffer; +} + +static INLINE void WriteR(size_t w, uint16 val) +{ + R[w] = val; + + if(w == 14) + DoROMRead(); +} + +// Only needed to be used when reg might == 15 +static INLINE uint16 ReadR(size_t w) +{ + return R[w + (w == 15)]; +} + +static INLINE void CMODE(void) +{ + POR = ReadR(Rs) & 0x1F; +} + +static INLINE void WriteColorData(uint8 tmp) +{ + tmp = (tmp & 0xF0) + ((tmp >> (POR & 0x4)) & 0x0F); + + if(POR & 0x8) + tmp = (ColorData & 0xF0) + (tmp & 0x0F); + + ColorData = tmp; +} + +static INLINE void COLOR(void) +{ + WriteColorData(ReadR(Rs)); +} + +static INLINE void GETC(void) +{ + uint8 tmp = GetROMBuffer(); + + WriteColorData(tmp); +} + +static INLINE void CalcSZ(uint16 v) +{ + FlagS = v >> 15; + FlagZ = !v; +} + +static INLINE unsigned CalcTNO(unsigned x, unsigned y) +{ + unsigned tno; + const unsigned shs = ((SCMR >> 2) & 0x1) | ((SCMR >> 4) & 0x2); + + if(shs == 0x3 || (POR & 0x10)) + { + tno = ((y >> 7) << 9) + ((x >> 7) << 8) + (((y >> 3) & 0xF) << 4) + ((x >> 3) & 0xF); + } + else switch(shs) + { + case 0: tno = (x >> 3) * 0x10 + (y >> 3); break; + case 1: tno = (x >> 3) * 0x14 + (y >> 3); break; + case 2: tno = (x >> 3) * 0x18 + (y >> 3); break; + } + + tno &= 0x3FF; + + return tno; +} + +static void FlushPixelCache(void) +{ + if(!PixelCache.opaque) // FIXME: correct? + return; + + superfx_timestamp = std::max(superfx_timestamp, pixcache_write_finish_ts); + pixcache_write_finish_ts = std::max(superfx_timestamp, ram_write_finish_ts); + // + // + // + const unsigned bpp = SCMR & 0x3; + static const unsigned tnoshtab[4] = { 4, 5, 6, 6 }; + const unsigned x = PixelCache.TagX; + const unsigned y = PixelCache.TagY; + const unsigned finey = y & 7; + unsigned tno = CalcTNO(x, y); + unsigned tra = (tno << tnoshtab[bpp]) + (SCBR << 10) + (finey << 1); + uint8* p = &Cart.RAM[tra & Cart.RAM_Mask]; + + if(PixelCache.opaque != 0xFF) + { + // FIXME: time + static const uint8 wtt[4] = { 2 * 3, 4 * 3, 8 * 3, 8 * 3}; + pixcache_write_finish_ts += wtt[bpp]; + } + // + // + // + { + const unsigned mask = ~PixelCache.opaque; + + p[0x00] &= mask; + p[0x01] &= mask; + if(bpp >= 1) + { + p[0x10] &= mask; + p[0x11] &= mask; + + if(bpp >= 2) + { + p[0x20] &= mask; + p[0x21] &= mask; + p[0x30] &= mask; + p[0x31] &= mask; + } + } + } + // + // + // + for(int i = 0; i < 8; i++) + { + if(PixelCache.opaque & 0x01) + { + const unsigned color = PixelCache.data[i]; + + p[0x00] |= ((color >> 0) & 1) << i; + p[0x01] |= ((color >> 1) & 1) << i; + if(bpp >= 1) + { + p[0x10] |= ((color >> 2) & 1) << i; + p[0x11] |= ((color >> 3) & 1) << i; + + if(bpp >= 2) + { + p[0x20] |= ((color >> 4) & 1) << i; + p[0x21] |= ((color >> 5) & 1) << i; + p[0x30] |= ((color >> 6) & 1) << i; + p[0x31] |= ((color >> 7) & 1) << i; + } + } + } + // + PixelCache.opaque >>= 1; + } + // FIXME: time + static const uint8 wtt[4] = { 2 * 3, 4 * 3, 8 * 3, 8 * 3}; + pixcache_write_finish_ts += wtt[bpp]; + // + // + // + ram_write_finish_ts = pixcache_write_finish_ts; +} + +static INLINE void PLOT(void) +{ + const unsigned x = (uint8)R[1]; + const unsigned y = (uint8)R[2]; + + if(PixelCache.TagX != (x & 0xF8) || PixelCache.TagY != y) + { + FlushPixelCache(); + PixelCache.TagX = x & 0xF8; + PixelCache.TagY = y; + } + + const unsigned finex = x & 7; + const unsigned bpp = SCMR & 0x3; + + uint8 color = ColorData; + bool visible = true; + // + color >>= ((((x ^ y) & 1) << 1) & POR & ~bpp) << 1; + if(!(POR & 0x1)) + { + static const unsigned masktab[4] = { 0x3, 0xF, 0xFF, 0xFF }; + + if(!(color & masktab[bpp] & ((POR & 8) ? 0xF : 0xFF))) + visible = false; + } + + PixelCache.data[7 - finex] = color; + PixelCache.opaque |= visible << (7 - finex); + + if(PixelCache.opaque == 0xFF) // Set to 1, or set? + FlushPixelCache(); + // + WriteR(1, R[1] + 1); +} + +static INLINE void RPIX(void) +{ + FlushPixelCache(); + // + // + // + const unsigned x = (uint8)R[1]; + const unsigned y = (uint8)R[2]; + const unsigned finex = x & 7; + const unsigned finey = y & 7; + unsigned tno = CalcTNO(x, y); + unsigned tra; + + const unsigned bpp = SCMR & 0x3; + static const unsigned tnoshtab[4] = { 4, 5, 6, 6 }; + + tra = (tno << tnoshtab[bpp]) + (SCBR << 10) + (finey << 1); + uint8* p = &Cart.RAM[tra & Cart.RAM_Mask]; + uint8 color = 0; + const unsigned shift = 7 - finex; + + color |= ((p[0x00] >> shift) & 1) << 0; + color |= ((p[0x01] >> shift) & 1) << 1; + if(bpp >= 1) + { + color |= ((p[0x10] >> shift) & 1) << 2; + color |= ((p[0x11] >> shift) & 1) << 3; + + if(bpp >= 2) + { + color |= ((p[0x20] >> shift) & 1) << 4; + color |= ((p[0x21] >> shift) & 1) << 5; + color |= ((p[0x30] >> shift) & 1) << 6; + color |= ((p[0x31] >> shift) & 1) << 7; + } + } + + CalcSZ(color); // FIXME? + WriteR(Rd, color); +} + +static INLINE void STOP(void) +{ + Running = false; + IRQPending = true; + //CPU_SetIRQ(IRQPending & !IRQMask, CPU_IRQSOURCE_CART); +} + +static INLINE void SetCBR(uint16 val) +{ + CBR = val; + memset(CacheValid, 0, sizeof(CacheValid)); +} + +static INLINE void CACHE(void) +{ + SetCBR(ReadR(15) & 0xFFF0); +} + +static INLINE void ADD(uint16 arg) +{ + const uint32 tmp = ReadR(Rs) + arg; + + FlagV = (int16)((ReadR(Rs) ^ ~arg) & (ReadR(Rs) ^ tmp)) < 0; + FlagC = tmp >> 16; + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void ADC(uint16 arg) +{ + const uint32 tmp = ReadR(Rs) + arg + FlagC; + + FlagV = (int16)((ReadR(Rs) ^ ~arg) & (ReadR(Rs) ^ tmp)) < 0; + FlagC = tmp >> 16; + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void SUB(uint16 arg) +{ + const uint32 tmp = ReadR(Rs) - arg; + + FlagV = (int16)((ReadR(Rs) ^ arg) & (ReadR(Rs) ^ tmp)) < 0; + FlagC = ((tmp >> 16) ^ 1) & 1; + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void SBC(uint16 arg) +{ + const uint32 tmp = ReadR(Rs) - arg - !FlagC; + + FlagV = (int16)((ReadR(Rs) ^ arg) & (ReadR(Rs) ^ tmp)) < 0; + FlagC = ((tmp >> 16) ^ 1) & 1; + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void CMP(uint16 arg) +{ + const uint32 tmp = ReadR(Rs) - arg; + + FlagV = (int16)((ReadR(Rs) ^ arg) & (ReadR(Rs) ^ tmp)) < 0; + FlagC = ((tmp >> 16) ^ 1) & 1; + CalcSZ(tmp); +} + +static INLINE void AND(uint16 arg) +{ + const uint16 tmp = ReadR(Rs) & arg; + + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void BIC(uint16 arg) +{ + const uint16 tmp = ReadR(Rs) & ~arg; + + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void OR(uint16 arg) +{ + const uint16 tmp = ReadR(Rs) | arg; + + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void XOR(uint16 arg) +{ + const uint16 tmp = ReadR(Rs) ^ arg; + + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void NOT(void) +{ + const uint16 tmp = ~ReadR(Rs); + + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void LSR(void) +{ + const uint16 tmp = ReadR(Rs) >> 1; + + FlagC = ReadR(Rs) & 1; + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void ASR(void) +{ + const uint16 tmp = (int16)ReadR(Rs) >> 1; + + FlagC = ReadR(Rs) & 1; + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void ROL(void) +{ + const bool NewFlagC = ReadR(Rs) >> 15; + const uint16 tmp = (ReadR(Rs) << 1) | FlagC; + + FlagC = NewFlagC; + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void ROR(void) +{ + const bool NewFlagC = ReadR(Rs) & 1; + const uint16 tmp = (ReadR(Rs) >> 1) | (FlagC << 15); + + FlagC = NewFlagC; + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void DIV2(void) +{ + //const uint16 tmp = ((int16)ReadR(Rs) + (ReadR(Rs) >> 15)) >> 1; + uint16 tmp = ((int16)ReadR(Rs) >> 1); // + (ReadR(Rs) == 0xFFFF); + + if(tmp == 0xFFFF) + tmp = 0; + + FlagC = ReadR(Rs) & 1; + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void INC(uint8 w) +{ + const uint16 tmp = R[w] + 1; + + CalcSZ(tmp); + + WriteR(w, tmp); +} + +static INLINE void DEC(uint8 w) +{ + const uint16 tmp = R[w] - 1; + + CalcSZ(tmp); + + WriteR(w, tmp); +} + +static INLINE void SWAP(void) +{ + const uint16 tmp = (ReadR(Rs) >> 8) | (ReadR(Rs) << 8); + + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void SEX(void) +{ + const uint16 tmp = (int8)ReadR(Rs); + + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void LOB(void) +{ + const uint16 tmp = (uint8)ReadR(Rs); + + FlagS = tmp >> 7; + FlagZ = !tmp; + + WriteR(Rd, tmp); +} + +static INLINE void HIB(void) +{ + const uint16 tmp = ReadR(Rs) >> 8; + + FlagS = ReadR(Rs) >> 15; + FlagZ = !tmp; + + WriteR(Rd, tmp); +} + +static INLINE void MERGE(void) +{ + const uint16 tmp = (R[7] & 0xFF00) + (R[8] >> 8); + + FlagS = (bool)(tmp & 0x8080); + FlagV = (bool)(tmp & 0xC0C0); + FlagC = (bool)(tmp & 0xE0E0); + FlagZ = (bool)(tmp & 0xF0F0); + + WriteR(Rd, tmp); +} + +static INLINE void FMULT(void) +{ + superfx_timestamp += cycles_per_16x16mult; + // + if(Rd == 4) + SNES_DBG("[SuperFX] FMULT with Rd=4\n"); + + const uint32 tmp = (int16)ReadR(Rs) * (int16)R[6]; + + // FIXME? + FlagS = tmp >> 31; + FlagZ = !tmp; + FlagC = (tmp >> 15) & 1; + + WriteR(Rd, tmp >> 16); +} + +static INLINE void LMULT(void) +{ + superfx_timestamp += cycles_per_16x16mult; + // + if(Rd == 4) + SNES_DBG("[SuperFX] LMULT with Rd=4\n"); + + const uint32 tmp = (int16)ReadR(Rs) * (int16)R[6]; + + // FIXME? + FlagS = tmp >> 31; + FlagZ = !tmp; + FlagC = (tmp >> 15) & 1; + + WriteR(Rd, tmp >> 16); + WriteR(4, tmp); +} + +static INLINE void MULT(uint16 arg) +{ + superfx_timestamp += cycles_per_8x8mult; + // + const uint16 tmp = (int8)ReadR(Rs) * (int8)arg; + + CalcSZ(tmp); + + WriteR(Rd, tmp); +} + +static INLINE void UMULT(uint16 arg) +{ + superfx_timestamp += cycles_per_8x8mult; + // + const uint16 tmp = (uint8)ReadR(Rs) * (uint8)arg; + + CalcSZ(tmp); + + WriteR(Rd, tmp); +} +// +// +// +static INLINE void JMP(uint8 Rn) +{ + WriteR(15, R[Rn]); +} + +static INLINE void LJMP(uint8 Rn) +{ + const uint16 target = ReadR(Rs); + + WriteR(15, target); + SetPBR(R[Rn]); + SetCBR(target & 0xFFF0); +} + +static INLINE void LOOP(void) +{ + const uint16 result = R[12] - 1; + + CalcSZ(result); + WriteR(12, result); + + if(!FlagZ) + WriteR(15, R[13]); +} + +static INLINE void LINK(uint8 arg) +{ + WriteR(11, ReadR(15) + arg); +} +// +// +// +static uint8 ReadOp(void) +{ + uint8 ret = Prefetch; + +#if 1 + Prefetch = PBR_Ptr[R[15] & PBR_Ptr_Mask]; + size_t cindex = R[15] - CBR; + if(MDFN_UNLIKELY(cindex >= 0x200)) + { + if(MDFN_LIKELY((PBR & 0x7F) < 0x60)) + { + superfx_timestamp = std::max(superfx_timestamp, rom_read_finish_ts); + superfx_timestamp += cycles_per_rom_read; + } + else + { + superfx_timestamp = std::max(superfx_timestamp, ram_write_finish_ts); + superfx_timestamp += 3; + } + } +#else + uint16 addr = R[15]; + size_t cindex = addr - CBR; + if(MDFN_UNLIKELY(cindex >= 0x200)) + { + Prefetch = PBR_Ptr[addr & PBR_Ptr_Mask]; + + if(MDFN_LIKELY((PBR & 0x7F) < 0x60)) + { + superfx_timestamp = std::max(superfx_timestamp, rom_read_finish_ts); + superfx_timestamp += cycles_per_rom_read; + } + else + { + superfx_timestamp = std::max(superfx_timestamp, ram_write_finish_ts); + superfx_timestamp += 3; + } + } + else + { + const size_t cvi = cindex >> 4; + + if(MDFN_UNLIKELY(!CacheValid[cvi])) + { + uint8* d = &CacheData[cindex & ~0xF]; + + CacheValid[cvi] = true; + + if(MDFN_LIKELY((PBR & 0x7F) < 0x60)) + { + superfx_timestamp = std::max(superfx_timestamp, rom_read_finish_ts); + rom_read_finish_ts = superfx_timestamp; + } + + for(unsigned i = 0; i < 0x10; i++) + { + const uint32 ra = (addr & 0xFFF0) + i; + + if(MDFN_LIKELY((PBR & 0x7F) < 0x60)) + { + rom_read_finish_ts += cycles_per_rom_read; + + if(ra == addr) + superfx_timestamp = rom_read_finish_ts; + } + + d[i] = PBR_Ptr[ra & PBR_Ptr_Mask]; + } + } + Prefetch = CacheData[cindex]; + } +#endif + + R[16] = R[15]; + R[15]++; + superfx_timestamp += cycles_per_op; + + return ret; +} + +static uint16 ReadOp16(void) +{ + uint16 ret; + + ret = ReadOp(); + ret |= ReadOp() << 8; + + return ret; +} + +static INLINE void RelBranch(bool cond) +{ + int8 disp = ReadOp(); + + if(cond) + WriteR(15, ReadR(15) + disp); +} + +static INLINE uint8 ReadRAM8(uint16 offs) +{ + superfx_timestamp = std::max(superfx_timestamp, ram_write_finish_ts); + superfx_timestamp += 4; // FIXME + // + // + uint8 ret; + + //LastRAMOffset = offs; + + ret = Cart.RAM[((RAMBR << 16) + offs) & Cart.RAM_Mask]; + + return ret; +} + +static INLINE uint16 ReadRAM16(uint16 offs) +{ + superfx_timestamp = std::max(superfx_timestamp, ram_write_finish_ts); + superfx_timestamp += 6; // FIXME + // + // + uint16 ret; + +// assert(!(offs & 1)); + + //LastRAMOffset = offs; + + ret = Cart.RAM[((RAMBR << 16) + (offs ^ 0)) & Cart.RAM_Mask] << 0; + ret |= Cart.RAM[((RAMBR << 16) + (offs ^ 1)) & Cart.RAM_Mask] << 8; + + return ret; +} + +static INLINE void WriteRAM8(uint16 offs, uint8 val) +{ + superfx_timestamp = std::max(superfx_timestamp, ram_write_finish_ts); + ram_write_finish_ts = superfx_timestamp + 3; // FIXME + // + // + //LastRAMOffset = offs; + + Cart.RAM[((RAMBR << 16) + (offs ^ 0)) & Cart.RAM_Mask] = val; +} + +static INLINE void WriteRAM16(uint16 offs, uint16 val) +{ + superfx_timestamp = std::max(superfx_timestamp, ram_write_finish_ts); + //superfx_timestamp += whatever; // FIXME? + ram_write_finish_ts = superfx_timestamp + 5; // FIXME + // + // +// assert(!(offs & 1)); + + //LastRAMOffset = offs; + + Cart.RAM[((RAMBR << 16) + (offs ^ 0)) & Cart.RAM_Mask] = val >> 0; + Cart.RAM[((RAMBR << 16) + (offs ^ 1)) & Cart.RAM_Mask] = val >> 8; +} + +static void Update(uint32 timestamp) +{ + if(MDFN_UNLIKELY(!Running)) + superfx_timestamp = timestamp; + + if((SCMR & 0x18) != 0x18) + superfx_timestamp = timestamp; + + while(superfx_timestamp < timestamp) + { + uint8 opcode; + + opcode = ReadOp(); + + #define OPCASE_PFX(pfx, o) case ((pfx) << 8) + (o) + #define OPCASE(o) OPCASE_PFX(0, o): OPCASE_PFX(1, o): OPCASE_PFX(2, o): OPCASE_PFX(3, o) + + #define OPCASE_NP(o) OPCASE_PFX(0, o) + #define OPCASE_3D(o) OPCASE_PFX(1, o) + #define OPCASE_3E(o) OPCASE_PFX(2, o) + #define OPCASE_3F(o) OPCASE_PFX(3, o) + + #define OPCASE_PFX_Xn(pfx, o) \ + OPCASE_PFX(pfx, (o) + 0x0): OPCASE_PFX(pfx, (o) + 0x1): OPCASE_PFX(pfx, (o) + 0x2): OPCASE_PFX(pfx, (o) + 0x3): OPCASE_PFX(pfx, (o) + 0x4): OPCASE_PFX(pfx, (o) + 0x5): OPCASE_PFX(pfx, (o) + 0x6): OPCASE_PFX(pfx, (o) + 0x7): \ + OPCASE_PFX(pfx, (o) + 0x8): OPCASE_PFX(pfx, (o) + 0x9): OPCASE_PFX(pfx, (o) + 0xA): OPCASE_PFX(pfx, (o) + 0xB): OPCASE_PFX(pfx, (o) + 0xC): OPCASE_PFX(pfx, (o) + 0xD): OPCASE_PFX(pfx, (o) + 0xE): OPCASE_PFX(pfx, (o) + 0xF) + + #define OPCASE_Xn(o) OPCASE_PFX_Xn(0, o): OPCASE_PFX_Xn(1, o): OPCASE_PFX_Xn(2, o): OPCASE_PFX_Xn(3, o) + + #define OPCASE_NP_Xn(o) OPCASE_PFX_Xn(0, o) + #define OPCASE_3D_Xn(o) OPCASE_PFX_Xn(1, o) + #define OPCASE_3E_Xn(o) OPCASE_PFX_Xn(2, o) + #define OPCASE_3F_Xn(o) OPCASE_PFX_Xn(3, o) + + // 1?, 2?, 5?, 6?, 7?, 8?, 9?, C?, +#if 0 + printf("Op: %03x --- ", (unsigned)(PrefixSL8 + opcode)); + for(unsigned i = 0; i < 16; i++) + printf("%04x ", R[i]); + + printf(" ROMBR=%02x", ROMBR); + printf("\n"); +#endif + switch(PrefixSL8 + opcode) + { + default: + SNES_DBG("[SuperFX] Unknown op 0x%03x\n", (unsigned)(PrefixSL8 + opcode)); + break; + + // + // GETB + // + OPCASE_NP(0xEF): + { + uint8 tmp = GetROMBuffer(); + + WriteR(Rd, tmp); + } + break; + + // + // GETBH + // + OPCASE_3D(0xEF): + { + uint8 tmp = GetROMBuffer(); + + WriteR(Rd, (ReadR(Rs) & 0x00FF) + (tmp << 8)); + } + break; + + // + // GETBL + // + OPCASE_3E(0xEF): + { + uint8 tmp = GetROMBuffer(); + + WriteR(Rd, (ReadR(Rs) & 0xFF00) + (tmp << 0)); + } + break; + + // + // GETBS + // + OPCASE_3F(0xEF): + { + uint8 tmp = GetROMBuffer(); + + WriteR(Rd, (int8)tmp); + } + break; + + // + // LDB + // + OPCASE_3D(0x40): OPCASE_3D(0x41): OPCASE_3D(0x42): OPCASE_3D(0x43): OPCASE_3D(0x44): OPCASE_3D(0x45): OPCASE_3D(0x46): OPCASE_3D(0x47): + OPCASE_3D(0x48): OPCASE_3D(0x49): OPCASE_3D(0x4A): OPCASE_3D(0x4B): + { + uint16 offs = R[opcode & 0xF]; + uint8 tmp; + + tmp = ReadRAM8(offs); + LastRAMOffset = offs; + + WriteR(Rd, tmp); + } + break; + + // + // LDW + // + OPCASE_NP(0x40): OPCASE_NP(0x41): OPCASE_NP(0x42): OPCASE_NP(0x43): OPCASE_NP(0x44): OPCASE_NP(0x45): OPCASE_NP(0x46): OPCASE_NP(0x47): + OPCASE_NP(0x48): OPCASE_NP(0x49): OPCASE_NP(0x4A): OPCASE_NP(0x4B): + { + uint16 offs = R[opcode & 0xF]; + uint16 tmp; + + tmp = ReadRAM16(offs); + LastRAMOffset = offs; + + WriteR(Rd, tmp); + } + break; + + // + // LM + // + OPCASE_3D_Xn(0xF0): + { + const uint16 offs = ReadOp16(); + const uint16 tmp = ReadRAM16(offs); + + LastRAMOffset = offs; + + WriteR(opcode & 0xF, tmp); + } + break; + + // + // LMS + // + OPCASE_3D_Xn(0xA0): + { + const uint16 offs = ReadOp() << 1; + const uint16 tmp = ReadRAM16(offs); + + //printf("%04x\n", offs); + + LastRAMOffset = offs; + + WriteR(opcode & 0xF, tmp); + } + break; + + // + // STB + // + OPCASE_3D(0x30): OPCASE_3D(0x31): OPCASE_3D(0x32): OPCASE_3D(0x33): OPCASE_3D(0x34): OPCASE_3D(0x35): OPCASE_3D(0x36): OPCASE_3D(0x37): + OPCASE_3D(0x38): OPCASE_3D(0x39): OPCASE_3D(0x3A): OPCASE_3D(0x3B): + { + WriteRAM8(R[opcode & 0xF], ReadR(Rs)); + } + break; + + // + // STW + // + OPCASE_NP(0x30): OPCASE_NP(0x31): OPCASE_NP(0x32): OPCASE_NP(0x33): OPCASE_NP(0x34): OPCASE_NP(0x35): OPCASE_NP(0x36): OPCASE_NP(0x37): + OPCASE_NP(0x38): OPCASE_NP(0x39): OPCASE_NP(0x3A): OPCASE_NP(0x3B): + { + WriteRAM16(R[opcode & 0xF], ReadR(Rs)); + } + break; + + // + // SM + // + OPCASE_3E_Xn(0xF0): + { + const uint16 offs = ReadOp16(); + + WriteRAM16(offs, ReadR(opcode & 0xF)); + } + break; + + // + // SMS + // + OPCASE_3E_Xn(0xA0): + { + const uint16 offs = ReadOp() << 1; + + WriteRAM16(offs, ReadR(opcode & 0xF)); + } + break; + + // + // SBK + // + OPCASE(0x90): + { + WriteRAM16(LastRAMOffset, ReadR(Rs)); + } + break; + + // + // IBT + // + OPCASE_NP_Xn(0xA0): + { + const uint8 imm = ReadOp(); + + WriteR(opcode & 0xF, (int8)imm); + } + break; + + // + // IWT + // + OPCASE_NP_Xn(0xF0): + { + const uint16 imm = ReadOp16(); + + WriteR(opcode & 0xF, imm); + } + break; + + // + // RAMB + // + OPCASE_3E(0xDF): + { + RAMBR = ReadR(Rs) & 0x1; + } + break; + + // + // ROMB + // + OPCASE_3F(0xDF): + { + ROMBR = ReadR(Rs) & 0xFF; +// assert(!(ROMBR & 0x80)); + } + break; + + OPCASE_3D(0x4E): CMODE(); break; + OPCASE_NP(0x4E): COLOR(); break; + OPCASE_NP(0xDF): GETC(); break; + OPCASE_NP(0x4C): PLOT(); break; + OPCASE_3D(0x4C): RPIX(); break; + + // + // + // + // + // + + OPCASE(0x00): STOP(); superfx_timestamp = timestamp; break; // STOP + OPCASE(0x01): break; // NOP + OPCASE(0x02): CACHE(); break; // CACHE + + OPCASE_NP_Xn(0x50): ADD(ReadR(opcode & 0xF)); break; + OPCASE_3E_Xn(0x50): ADD(opcode & 0xF); break; + + OPCASE_3D_Xn(0x50): ADC(ReadR(opcode & 0xF)); break; + OPCASE_3F_Xn(0x50): ADC(opcode & 0xF); break; + + OPCASE_NP_Xn(0x60): SUB(ReadR(opcode & 0xF)); break; + OPCASE_3E_Xn(0x60): SUB(opcode & 0xF); break; + + OPCASE_3D_Xn(0x60): SBC(ReadR(opcode & 0xF)); break; + OPCASE_3F_Xn(0x60): CMP(ReadR(opcode & 0xF)); break; + + /* AND Rn */ OPCASE_NP(0x71): OPCASE_NP(0x72): OPCASE_NP(0x73): OPCASE_NP(0x74): OPCASE_NP(0x75): OPCASE_NP(0x76): OPCASE_NP(0x77): + OPCASE_NP(0x78): OPCASE_NP(0x79): OPCASE_NP(0x7A): OPCASE_NP(0x7B): OPCASE_NP(0x7C): OPCASE_NP(0x7D): OPCASE_NP(0x7E): OPCASE_NP(0x7F): + AND(ReadR(opcode & 0xF)); + break; + + /* AND #n */ OPCASE_3E(0x71): OPCASE_3E(0x72): OPCASE_3E(0x73): OPCASE_3E(0x74): OPCASE_3E(0x75): OPCASE_3E(0x76): OPCASE_3E(0x77): + OPCASE_3E(0x78): OPCASE_3E(0x79): OPCASE_3E(0x7A): OPCASE_3E(0x7B): OPCASE_3E(0x7C): OPCASE_3E(0x7D): OPCASE_3E(0x7E): OPCASE_3E(0x7F): + AND(opcode & 0xF); + break; + + /* BIC Rn */ OPCASE_3D(0x71): OPCASE_3D(0x72): OPCASE_3D(0x73): OPCASE_3D(0x74): OPCASE_3D(0x75): OPCASE_3D(0x76): OPCASE_3D(0x77): + OPCASE_3D(0x78): OPCASE_3D(0x79): OPCASE_3D(0x7A): OPCASE_3D(0x7B): OPCASE_3D(0x7C): OPCASE_3D(0x7D): OPCASE_3D(0x7E): OPCASE_3D(0x7F): + BIC(ReadR(opcode & 0xF)); + break; + + /* BIC #n */ OPCASE_3F(0x71): OPCASE_3F(0x72): OPCASE_3F(0x73): OPCASE_3F(0x74): OPCASE_3F(0x75): OPCASE_3F(0x76): OPCASE_3F(0x77): + OPCASE_3F(0x78): OPCASE_3F(0x79): OPCASE_3F(0x7A): OPCASE_3F(0x7B): OPCASE_3F(0x7C): OPCASE_3F(0x7D): OPCASE_3F(0x7E): OPCASE_3F(0x7F): + BIC(opcode & 0xF); + break; + + /* OR Rn */ OPCASE_NP(0xC1): OPCASE_NP(0xC2): OPCASE_NP(0xC3): OPCASE_NP(0xC4): OPCASE_NP(0xC5): OPCASE_NP(0xC6): OPCASE_NP(0xC7): + OPCASE_NP(0xC8): OPCASE_NP(0xC9): OPCASE_NP(0xCA): OPCASE_NP(0xCB): OPCASE_NP(0xCC): OPCASE_NP(0xCD): OPCASE_NP(0xCE): OPCASE_NP(0xCF): + OR(ReadR(opcode & 0xF)); + break; + + /* OR #n */ OPCASE_3E(0xC1): OPCASE_3E(0xC2): OPCASE_3E(0xC3): OPCASE_3E(0xC4): OPCASE_3E(0xC5): OPCASE_3E(0xC6): OPCASE_3E(0xC7): + OPCASE_3E(0xC8): OPCASE_3E(0xC9): OPCASE_3E(0xCA): OPCASE_3E(0xCB): OPCASE_3E(0xCC): OPCASE_3E(0xCD): OPCASE_3E(0xCE): OPCASE_3E(0xCF): + OR(opcode & 0xF); + break; + + /* XOR Rn */ OPCASE_3D(0xC1): OPCASE_3D(0xC2): OPCASE_3D(0xC3): OPCASE_3D(0xC4): OPCASE_3D(0xC5): OPCASE_3D(0xC6): OPCASE_3D(0xC7): + OPCASE_3D(0xC8): OPCASE_3D(0xC9): OPCASE_3D(0xCA): OPCASE_3D(0xCB): OPCASE_3D(0xCC): OPCASE_3D(0xCD): OPCASE_3D(0xCE): OPCASE_3D(0xCF): + XOR(ReadR(opcode & 0xF)); + break; + + /* XOR #n */ OPCASE_3F(0xC1): OPCASE_3F(0xC2): OPCASE_3F(0xC3): OPCASE_3F(0xC4): OPCASE_3F(0xC5): OPCASE_3F(0xC6): OPCASE_3F(0xC7): + OPCASE_3F(0xC8): OPCASE_3F(0xC9): OPCASE_3F(0xCA): OPCASE_3F(0xCB): OPCASE_3F(0xCC): OPCASE_3F(0xCD): OPCASE_3F(0xCE): OPCASE_3F(0xCF): + XOR(opcode & 0xF); + break; + + OPCASE(0x4F): NOT(); break; + + OPCASE(0x03): LSR(); break; // LSR + OPCASE_NP(0x96): ASR(); break; // ASR + OPCASE(0x04): ROL(); break; // ROL + OPCASE(0x97): ROR(); break; // ROR + OPCASE_3D(0x96): DIV2(); break; // DIV2 (TODO: semantics!) + + // + // INC + // + OPCASE(0xD0): OPCASE(0xD1): OPCASE(0xD2): OPCASE(0xD3): OPCASE(0xD4): OPCASE(0xD5): OPCASE(0xD6): OPCASE(0xD7): + OPCASE(0xD8): OPCASE(0xD9): OPCASE(0xDA): OPCASE(0xDB): OPCASE(0xDC): OPCASE(0xDD): OPCASE(0xDE): // + { + INC(opcode & 0xF); + } + break; + + // + // DEC + // + OPCASE(0xE0): OPCASE(0xE1): OPCASE(0xE2): OPCASE(0xE3): OPCASE(0xE4): OPCASE(0xE5): OPCASE(0xE6): OPCASE(0xE7): + OPCASE(0xE8): OPCASE(0xE9): OPCASE(0xEA): OPCASE(0xEB): OPCASE(0xEC): OPCASE(0xED): OPCASE(0xEE): // + { + DEC(opcode & 0xF); + } + break; + + OPCASE(0x4D): SWAP(); break; // SWAP + OPCASE(0x95): SEX(); break; // SEX + OPCASE(0x9E): LOB(); break; // LOB + OPCASE(0xC0): HIB(); break; // HIB + OPCASE(0x70): MERGE(); break; // MERGE + + OPCASE_NP(0x9F): FMULT(); break; // FMULT + OPCASE_3D(0x9F): LMULT(); break; // LMULT + + OPCASE_NP_Xn(0x80): MULT(ReadR(opcode & 0xF)); break; // MULT Rn + OPCASE_3E_Xn(0x80): MULT(opcode & 0xF); break; // MULT #n + + OPCASE_3D_Xn(0x80): UMULT(ReadR(opcode & 0xF)); break; // UMULT Rn + OPCASE_3F_Xn(0x80): UMULT(opcode & 0xF); break; // UMULT #n + + // + // Relative branching + // + OPCASE(0x05): RelBranch(true); goto SkipPrefixReset; // BRA + OPCASE(0x06): RelBranch(FlagS == FlagV); goto SkipPrefixReset; // BGE + OPCASE(0x07): RelBranch(FlagS != FlagV); goto SkipPrefixReset; // BLT + OPCASE(0x08): RelBranch(!FlagZ); goto SkipPrefixReset; // BNE + OPCASE(0x09): RelBranch( FlagZ); goto SkipPrefixReset; // BEQ + OPCASE(0x0A): RelBranch(!FlagS); goto SkipPrefixReset; // BPL + OPCASE(0x0B): RelBranch( FlagS); goto SkipPrefixReset; // BMI + OPCASE(0x0C): RelBranch(!FlagC); goto SkipPrefixReset; // BCC + OPCASE(0x0D): RelBranch( FlagC); goto SkipPrefixReset; // BCS + OPCASE(0x0E): RelBranch(!FlagV); goto SkipPrefixReset; // BVC + OPCASE(0x0F): RelBranch( FlagV); goto SkipPrefixReset; // BVS + + OPCASE_NP(0x98): OPCASE_NP(0x99): OPCASE_NP(0x9A): OPCASE_NP(0x9B): OPCASE_NP(0x9C): OPCASE_NP(0x9D): JMP(opcode & 0xF); break; // JMP + OPCASE_3D(0x98): OPCASE_3D(0x99): OPCASE_3D(0x9A): OPCASE_3D(0x9B): OPCASE_3D(0x9C): OPCASE_3D(0x9D): LJMP(opcode & 0xF); break; // LJMP + + OPCASE(0x3C): LOOP(); break; // LOOP + OPCASE(0x91): OPCASE(0x92): OPCASE(0x93): OPCASE(0x94): LINK(opcode & 0xF); break; // LINK + + OPCASE(0x3D): PrefixSL8 |= 0x1 << 8; goto SkipPrefixReset; // ALT1 + OPCASE(0x3E): PrefixSL8 |= 0x2 << 8; goto SkipPrefixReset; // ALT2 + OPCASE(0x3F): PrefixSL8 |= 0x3 << 8; goto SkipPrefixReset; // ALT3 + + // + // TO/MOVE + // + OPCASE_Xn(0x10): + { + if(PrefixB) + { + // + // MOVE + // + const uint16 tmp = ReadR(Rs); + WriteR(opcode & 0xF, tmp); + } + else + { + // + // TO + // + Rd = opcode & 0xF; + goto SkipPrefixReset; // TO + } + } + break; + + // + // WITH + // + OPCASE_Xn(0x20): + { + Rs = Rd = opcode & 0xF; + PrefixB = true; + } + goto SkipPrefixReset; + + // + // FROM/MOVES + // + OPCASE_Xn(0xB0): + { + if(PrefixB) + { + // + // MOVES + // + const uint16 tmp = ReadR(opcode & 0xF); + + FlagV = (bool)(tmp & 0x80); + CalcSZ(tmp); + + WriteR(Rd, tmp); + } + else + { + // + // FROM + // + Rs = opcode & 0xF; + goto SkipPrefixReset; + } + } + break; + } + // + Rs = 0; + Rd = 0; + PrefixSL8 = 0; + PrefixB = false; + // + SkipPrefixReset:; + } +} + +static uint32 EventHandler(uint32 timestamp) +{ + Update(timestamp); + + return timestamp + 128; //SNES_EVENT_MAXTS; +} + +static void AdjustTS(int32 delta) +{ + superfx_timestamp += delta; + + pixcache_write_finish_ts = std::max(0, (int64)pixcache_write_finish_ts + delta); + rom_read_finish_ts = std::max(0, (int64)rom_read_finish_ts + delta); + ram_write_finish_ts = std::max(0, (int64)ram_write_finish_ts + delta); +} + +static MDFN_COLD void Reset(bool powering_up) +{ + Running = false; + + memset(R, 0, sizeof(R)); + Prefetch = 0; + PrefixSL8 = 0; + PrefixB = false; + Rs = 0; + Rd = 0; + + SetPBR(0x00); //PBR = 0; + SetCBR(0x0000); //CBR = 0; + ROMBR = 0; + RAMBR = 0; + + SetCLSR(0x00); //ClockSelect = false; + SetCFGR(0x00); //MultSpeed = false; + //IRQMask = false; + + + SCBR = 0; + SCMR = 0; + POR = 0; + ColorData = 0; + + memset(&PixelCache, 0, sizeof(PixelCache)); + + memset(CacheData, 0, sizeof(CacheData)); + memset(CacheValid, 0, sizeof(CacheValid)); + + ROMBuffer = 0; + LastRAMOffset = 0; + + FlagV = false; + FlagS = false; + FlagC = false; + FlagZ = false; + + Running = false; + IRQPending = false; + + GPRWriteLatch = 0; + // + // + superfx_timestamp = CPUM.timestamp; + rom_read_finish_ts = superfx_timestamp; + ram_write_finish_ts = superfx_timestamp; + pixcache_write_finish_ts = superfx_timestamp; +} + +template +static DEFREAD(MainCPU_ReadLoROM) +{ + //if(MDFN_UNLIKELY(DBG_InHLRead)) + //{ + // return (Cart.ROM + rom_offset)[(A & 0x7FFF) | ((A >> 1) & 0x3F8000)]; + //} + if(MDFN_LIKELY(!DBG_InHLRead)) + { + if(cyc >= 0) + CPUM.timestamp += cyc; + else + CPUM.timestamp += MemSelect ? MEMCYC_FAST : MEMCYC_SLOW; + } + + return (Cart.ROM + rom_offset)[(A & 0x7FFF) | ((A >> 1) & 0x3F8000)]; +} + +template +static DEFREAD(MainCPU_ReadHiROM) +{ + //if(MDFN_UNLIKELY(DBG_InHLRead)) + //{ + //return (Cart.ROM + rom_offset)[A & 0x3FFFFF]; + //} + + if(MDFN_LIKELY(!DBG_InHLRead)) + { + if(cyc >= 0) + CPUM.timestamp += cyc; + else + CPUM.timestamp += MemSelect ? MEMCYC_FAST : MEMCYC_SLOW; + } + + return (Cart.ROM + rom_offset)[A & 0x3FFFFF]; +} + +static DEFREAD(MainCPU_ReadRAM8K) +{ + if(Running && (SCMR & 0x18) == 0x18) + SNES_DBG("[SuperFX] RAM read while SuperFX is running: %06x\n", A); + + if(MDFN_LIKELY(!DBG_InHLRead)) + CPUM.timestamp += MEMCYC_SLOW; + // + // + const size_t raw_sram_index = (A & 0x1FFF); + + return Cart.RAM[raw_sram_index & Cart.RAM_Mask]; +} + +static DEFWRITE(MainCPU_WriteRAM8K) +{ + if(Running && (SCMR & 0x18) == 0x18) + SNES_DBG("[SuperFX] RAM write while SuperFX is running: %06x %02x\n", A, V); + + CPUM.timestamp += MEMCYC_SLOW; + // + // + const size_t raw_sram_index = (A & 0x1FFF); + + Cart.RAM[raw_sram_index & Cart.RAM_Mask] = V; +} + +static DEFREAD(MainCPU_ReadRAM) +{ + if(Running && (SCMR & 0x18) == 0x18) + SNES_DBG("[SuperFX] RAM read while SuperFX is running: %06x\n", A); + + if(MDFN_LIKELY(!DBG_InHLRead)) + CPUM.timestamp += MEMCYC_SLOW; + // + // + const size_t raw_sram_index = A & 0x1FFFF; + + return Cart.RAM[raw_sram_index & Cart.RAM_Mask]; +} + +static DEFWRITE(MainCPU_WriteRAM) +{ + if(Running && (SCMR & 0x18) == 0x18) + SNES_DBG("[SuperFX] RAM write while SuperFX is running: %06x %02x\n", A, V); + + CPUM.timestamp += MEMCYC_SLOW; + // + // + const size_t raw_sram_index = A & 0x1FFFF; + + Cart.RAM[raw_sram_index & Cart.RAM_Mask] = V; +} + + +static DEFREAD(MainCPU_ReadGPR) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + CPUM.timestamp += MEMCYC_FAST; + // + // + return ne16_rbo_le(R, A & 0x1F); +} + +static DEFWRITE(MainCPU_WriteGPR) +{ + if(Running && (SCMR & 0x18) == 0x18) + SNES_DBG("[SuperFX] GPR write while SuperFX is running: %06x %02x\n", A, V); + + CPUM.timestamp += MEMCYC_FAST; + // + // + //SNES_DBG("[SuperFX] Write GPR 0x%06x 0x%02x\n", A, V); + if(A & 0x1) + { + const size_t index = (A >> 1) & 0xF; + const uint16 tmp = (V << 8) + GPRWriteLatch; + + R[index] = tmp; + + if(index == 0xF) + { + Prefetch = 0x01; + Running = true; + PrefixSL8 = 0; + PrefixB = 0; + Rs = 0; + Rd = 0; + //assert((bool)tmp == (bool)(SCMR & 0x10)); + } + } + else + GPRWriteLatch = V; +} + +template +static DEFREAD(MainCPU_ReadIO) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + CPUM.timestamp += MEMCYC_FAST; + // + // + uint8 ret = 0; + + switch(T_A & 0xF) + { + default: + SNES_DBG("[SuperFX] Unknown read 0x%06x\n", A); + break; + + case 0x0: + ret = (FlagZ << 1) | (FlagC << 2) | (FlagS << 3) | (FlagV << 4) | (Running << 5); + break; + + case 0x1: + ret = ((PrefixSL8 >> 8) & 0x3) | (PrefixB << 4) | (IRQPending << 7); + if(MDFN_LIKELY(!DBG_InHLRead)) + { + IRQPending = false; + CPU_SetIRQ(false, CPU_IRQSOURCE_CART); + } + break; + + case 0x4: + ret = PBR; + break; + + case 0x6: + ret = ROMBR; + break; + + case 0xB: + ret = VCR; + break; + + case 0xC: + ret = RAMBR; + break; + + case 0xE: + ret = CBR; + break; + + case 0xF: + ret = CBR >> 8; + break; + } + + return ret; +} + +template +static DEFWRITE(MainCPU_WriteIO) +{ + CPUM.timestamp += MEMCYC_FAST; + // + // + //SNES_DBG("[SuperFX] IO write 0x%06x 0x%02x\n", A, V); + + switch(T_A & 0xF) + { + default: + SNES_DBG("[SuperFX] Unknown write 0x%06x 0x%02x\n", A, V); + break; + + case 0x0: + FlagZ = (bool)(V & 0x02); + FlagC = (bool)(V & 0x04); + FlagS = (bool)(V & 0x08); + FlagV = (bool)(V & 0x10); + Running = (bool)(V & 0x20); + if(!Running) + SetCBR(0x0000); + break; +/* + case 0x1: + PrefixSL8 = (V & 0x03) << 8; + PrefixB = (V >> 4) & 1; + break; +*/ + case 0x4: + SetPBR(V); + break; + + case 0x7: + SetCFGR(V); + break; + + case 0x8: + SCBR = V & 0x3F; + break; + + case 0x9: + SetCLSR(V); + break; + + case 0xA: + SCMR = V; + break; + } +} + +static DEFREAD(MainCPU_ReadCache) +{ + if(MDFN_LIKELY(!DBG_InHLRead)) + CPUM.timestamp += MEMCYC_FAST; + // + // + SNES_DBG("[SuperFX] Cache read %06x\n", A); + return CacheData[A & 0x1FF]; +} + +static DEFWRITE(MainCPU_WriteCache) +{ + CPUM.timestamp += MEMCYC_FAST; + // + // + SNES_DBG("[SuperFX] Cache write %06x %02x\n", A, V); + const size_t index = A & 0x1FF; + + CacheData[index] = V; + CacheValid[index >> 4] |= ((A & 0xF) == 0xF); +} + +static void StateAction(StateMem* sm, const unsigned load, const bool data_only) +{ + SFORMAT StateRegs[] = + { + SFVAR(R), + SFVAR(Prefetch), + SFVAR(PrefixSL8), + SFVAR(PrefixB), + + SFVAR(Rs), + SFVAR(Rd), + + SFVAR(PBR), + SFVAR(CBR), + SFVAR(ROMBR), + SFVAR(RAMBR), + SFVAR(ClockSelect), + SFVAR(MultSpeed), + + SFVAR(SCBR), + SFVAR(SCMR), + SFVAR(POR), + SFVAR(ColorData), + + SFVAR(PixelCache.TagX), + SFVAR(PixelCache.TagY), + SFVAR(PixelCache.data), + SFVAR(PixelCache.opaque), + + SFVAR(CacheData), + SFVAR(CacheValid), + + SFVAR(ROMBuffer), + + SFVAR(LastRAMOffset), + + SFVAR(FlagV), + SFVAR(FlagS), + SFVAR(FlagC), + SFVAR(FlagZ), + SFVAR(Running), + SFVAR(IRQPending), + SFVAR(IRQMask), + + SFVAR(GPRWriteLatch), + // + // FIXME: save states in debugger:? + SFVAR(superfx_timestamp), + SFVAR(rom_read_finish_ts), + SFVAR(ram_write_finish_ts), + SFVAR(pixcache_write_finish_ts), + + SFEND + }; + + MDFNSS_StateAction(sm, load, data_only, StateRegs, "SuperFX"); + + if(load) + { + SetCLSR(ClockSelect); + SetPBR(PBR); + } +} + +void CART_SuperFX_Init(const int32 master_clock, const int32 ocmultiplier) +{ + assert(Cart.RAM_Size); + + superfx_timestamp = 0; + rom_read_finish_ts = 0; + ram_write_finish_ts = 0; + pixcache_write_finish_ts = 0; + + VCR = 0x04; + + for(unsigned bank = 0x00; bank < 0x100; bank++) + { + if(!(bank & 0x40)) + { + Set_A_Handlers((bank << 16) | 0x3000, (bank << 16) | 0x301F, MainCPU_ReadGPR, MainCPU_WriteGPR); + + #define SHP(a, ta) Set_A_Handlers((bank << 16) | a, MainCPU_ReadIO, MainCPU_WriteIO); + SHP(0x3030, 0x0) + SHP(0x3031, 0x1) + SHP(0x3032, 0x2) + SHP(0x3033, 0x3) + SHP(0x3034, 0x4) + SHP(0x3035, 0x5) + SHP(0x3036, 0x6) + SHP(0x3037, 0x7) + SHP(0x3038, 0x8) + SHP(0x3039, 0x9) + SHP(0x303A, 0xA) + SHP(0x303B, 0xB) + SHP(0x303C, 0xC) + SHP(0x303D, 0xD) + SHP(0x303E, 0xE) + SHP(0x303F, 0xF) + #undef SHP + + Set_A_Handlers((bank << 16) | 0x3100, (bank << 16) | 0x32FF, MainCPU_ReadCache, MainCPU_WriteCache); + Set_A_Handlers((bank << 16) | 0x3300, (bank << 16) | 0x34FF, MainCPU_ReadCache, MainCPU_WriteCache); + + Set_A_Handlers((bank << 16) | 0x6000, (bank << 16) | 0x7FFF, MainCPU_ReadRAM8K, MainCPU_WriteRAM8K); + } + + if(bank < 0x40) + { + Set_A_Handlers((bank << 16) | 0x8000, (bank << 16) | 0xFFFF, MainCPU_ReadLoROM, OBWrite_SLOW); + } + else if(bank < 0x60) + { + Set_A_Handlers((bank << 16) | 0x0000, (bank << 16) | 0xFFFF, MainCPU_ReadHiROM, OBWrite_SLOW); + } + else if(bank < 0x70) + { + //Set_A_Handlers((bank << 16) | 0x0000, (bank << 16) | 0xFFFF, MainCPU_ReadHiROM, OBWrite_SLOW); + } + else if(bank == 0x70 || bank == 0x71) + { + Set_A_Handlers((bank << 16) | 0x0000, (bank << 16) | 0xFFFF, MainCPU_ReadRAM, MainCPU_WriteRAM); + } + else if(bank >= 0x80 && bank < 0xC0) + { + Set_A_Handlers((bank << 16) | 0x8000, (bank << 16) | 0xFFFF, MainCPU_ReadLoROM<-1, 0x200000>, OBWrite_SLOW); + } + else if(bank >= 0xC0) + { + Set_A_Handlers((bank << 16) | 0x0000, (bank << 16) | 0xFFFF, MainCPU_ReadHiROM<-1, 0x200000>, OBWrite_SLOW); + } + } + // + // + // + for(unsigned bank = 0x00; bank < 0x80; bank++) + { + static const uint8 dummy = 0xFF; + const uint8* p = &dummy; + size_t m = 0; + + if(bank < 0x40) + { + p = &Cart.ROM[bank << 15]; + m = 0x7FFF; + } + else if(bank < 0x60) + { + p = &Cart.ROM[((bank - 0x40) & 0x1F) << 16]; + m = 0xFFFF; + } + else if(bank < 0x80) + { + if(Cart.RAM) + { + p = &Cart.RAM[(bank << 16) & Cart.RAM_Mask]; + m = 0xFFFF & Cart.RAM_Mask; + } + } + ProgMemMap[bank] = p; + ProgMemMapMask[bank] = m; + } + // + // + // + Cart.AdjustTS = AdjustTS; + Cart.EventHandler = EventHandler; + Cart.Reset = Reset; + Cart.StateAction = StateAction; +} + +} diff --git a/mednafen/snes_faust/cart/superfx.h b/mednafen/snes_faust/cart/superfx.h new file mode 100644 index 0000000..1583122 --- /dev/null +++ b/mednafen/snes_faust/cart/superfx.h @@ -0,0 +1,31 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* superfx.h: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __MDFN_SNES_FAUST_CART_SUPERFX_H +#define __MDFN_SNES_FAUST_CART_SUPERFX_H + +namespace MDFN_IEN_SNES_FAUST +{ + +void CART_SuperFX_Init(const int32 master_clock, const int32 ocmultiplier) MDFN_COLD; + +} +#endif diff --git a/mednafen/snes_faust/cpu.cpp b/mednafen/snes_faust/cpu.cpp index 53c90ea..58b7d6b 100644 --- a/mednafen/snes_faust/cpu.cpp +++ b/mednafen/snes_faust/cpu.cpp @@ -2,7 +2,7 @@ /* Mednafen Fast SNES Emulation Module */ /******************************************************************************/ /* cpu.cpp: -** Copyright (C) 2015-2016 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -56,2115 +56,9 @@ namespace MDFN_IEN_SNES_FAUST { -class Core65816 -{ - public: - Core65816() MDFN_COLD; - ~Core65816() MDFN_COLD; - - void Reset(bool powering_up) MDFN_COLD; - - void StateAction(StateMem* sm, const unsigned load, const bool data_only); - - //private: - - enum - { - N_FLAG = 0x80, - V_FLAG = 0x40, - - M_FLAG = 0x20, // Memory/Accumulator(0=16-bit) - X_FLAG = 0x10, // Index(0=16-bit) - - D_FLAG = 0x08, - I_FLAG = 0x04, - Z_FLAG = 0x02, - C_FLAG = 0x01, - }; - - union - { - struct - { -#ifdef MSB_FIRST - uint8 PCPBRDummy; - uint8 PBR; - uint16 PC; -#else - uint16 PC; - uint8 PBR; - uint8 PCPBRDummy; -#endif - }; - uint32 PCPBR; - }; - uint32 DBRSL16; - - uint16 S; - uint16 D; - - union - { - uint16 C; - struct - { -#ifdef MSB_FIRST - uint8 B; - uint8 A; -#else - uint8 A; - uint8 B; -#endif - }; - }; - - template - INLINE T& AC(void) // Clever and/or horrible. - { -/* - if(sizeof(T) == 2) - return (T&)C; - else - return (T&)A; -*/ - return *(T*)((sizeof(T) == 2) ? (void*)&C : (void*)&A); - } - - uint16 X, Y; - uint8 P; - bool E; - - unsigned PIN_Delay; - INLINE void SampleIRQ(void) - { - PIN_Delay = ((P ^ I_FLAG) | 0x01) & CPUM.CombinedNIState; - } - - template - void RunInstruction(void); - - template - void MemWrite(uint32 addr, T val); - - template - T MemRead(uint32 addr); - - void IO(void); - - //private: - - uint8 OpRead(uint32 addr); - - template void SetZN(const T arg); - template void Push(T arg); - template T Pull(void); - - enum - { - ISEQ_COP, - ISEQ_BRK, - ISEQ_ABORT, - ISEQ_NMI, - ISEQ_IRQ - }; - - void ISequence(unsigned which); - - template void Op_ADC(T arg); - template void Op_AND(T arg); - template void Op_BIT(T arg); - template void Op_Compare(T rv, T arg); - template void Op_CMP(T arg); - template void Op_CPX(T arg); - template void Op_CPY(T arg); - template void Op_EOR(T arg); - template void Op_LDA(T arg); - template void Op_LDX(T arg); - template void Op_LDY(T arg); - template void Op_ORA(T arg); - template void Op_SBC(T arg); - - template void Op_ASL(T& arg); - template void Op_DEC(T& arg); - template void Op_INC(T& arg); - template void Op_LSR(T& arg); - template void Op_ROL(T& arg); - template void Op_ROR(T& arg); - template void Op_TRB(T& arg); - template void Op_TSB(T& arg); - - template INLINE T Op_STA(void) { return C; } - template INLINE T Op_STX(void) { return X; } - template INLINE T Op_STY(void) { return Y; } - template INLINE T Op_STZ(void) { return 0; } - - uint32 GetEA_AB(void); - template uint32 GetEA_ABI(uint16 index); - template uint32 GetEA_ABX(void); - template uint32 GetEA_ABY(void); - uint32 GetEA_ABL(void); - uint32 GetEA_ABLX(void); - - uint16 GetEA_DP(void); - uint16 GetEA_DPI(uint16 index); - uint16 GetEA_DPX(void); - uint16 GetEA_DPY(void); - uint32 GetEA_IND(void); - uint32 GetEA_INDL(void); - uint32 GetEA_IX(void); - template uint32 GetEA_IY(void); - uint32 GetEA_ILY(void); - - uint16 GetEA_SR(void); - uint32 GetEA_SRIY(void); - - template void Instr_LD_IM(void (Core65816::*op)(T)); - template void Instr_LD(EAT (Core65816::*eafn)(void), void (Core65816::*op)(T)); - - template void Instr_RMW_A (void (Core65816::*op)(T&)); - template void Instr_RMW(EAT (Core65816::*eafn)(void), void (Core65816::*op)(T&)); - - template void Instr_ST(EAT (Core65816::*eafn)(void), T (Core65816::*op)(void)); - - void Instr_BRK(void); - void Instr_COP(void); - void Instr_NOP(void); - void Instr_STP(void); - void Instr_WAI(void); - void Instr_WDM(void); - - void Instr_Bxx(bool cond); - void Instr_BRL(void); - - void Instr_PEA(void); - void Instr_PEI(void); - void Instr_PER(void); - template void Instr_PHA(void); - void Instr_PHB(void); - void Instr_PHD(void); - void Instr_PHK(void); - void Instr_PHP(void); - template void Instr_PHX(void); - template void Instr_PHY(void); - - template void Instr_PLA(void); - void Instr_PLB(void); - void Instr_PLD(void); - void Instr_PLP(void); - template void Instr_PLX(void); - template void Instr_PLY(void); - - void Instr_REP(void); - void Instr_SEP(void); - - void Instr_JMP(void); - void Instr_JMP_I(void); - void Instr_JMP_II(void); - void Instr_JML(void); - void Instr_JML_I(void); - - void Instr_JSL(void); - void Instr_JSR(void); - void Instr_JSR_II(void); - - void Instr_RTI(void); - void Instr_RTL(void); - void Instr_RTS(void); - - template void Instr_INX(void); - template void Instr_INY(void); - - template void Instr_DEX(void); - template void Instr_DEY(void); - - template void Instr_TAX(void); - template void Instr_TAY(void); - void Instr_TCD(void); - void Instr_TCS(void); - void Instr_TDC(void); - void Instr_TSC(void); - template void Instr_TSX(void); - template void Instr_TXA(void); - void Instr_TXS(void); - template void Instr_TXY(void); - template void Instr_TYA(void); - template void Instr_TYX(void); - void Instr_XBA(void); - void Instr_XCE(void); - template void Instr_CLx(void); - template void Instr_SEx(void); - template void Instr_MVx(void); -}; - -Core65816::Core65816() -{ - PCPBRDummy = 0x00; -} - -Core65816::~Core65816() -{ - - -} - - -template -INLINE void Core65816::MemWrite(uint32 addr, T val) -{ - CPU_Write(addr, val); - - if(sizeof(T) == 2) - { - addr++; - CPU_Write(addr, val >> 8); - } -} - -template -INLINE T Core65816::MemRead(uint32 addr) -{ - T ret; - - ret = CPU_Read(addr); - - if(sizeof(T) == 2) - { - addr++; - ret |= CPU_Read(addr) << 8; - } - - return ret; -} -//static bool popread = false; -INLINE uint8 Core65816::OpRead(uint32 addr) -{ - uint8 ret = MemRead(addr); - - //if(popread) - // SNES_DBG(" %02x\n", ret); - - return ret; -} - -INLINE void Core65816::IO(void) -{ - CPU_IO(); -} - -// -// -// -template -INLINE void Core65816::SetZN(T arg) -{ - P &= ~(Z_FLAG | N_FLAG); - - if(!arg) - P |= Z_FLAG; - - P |= (arg >> ((sizeof(T) - 1) * 8)) & N_FLAG; -} - -template -INLINE void Core65816::Push(T arg) -{ - if(sizeof(T) == 2) - { - MemWrite(S, arg >> 8); - S--; - } - - MemWrite(S, arg); - S--; -} - -template -INLINE T Core65816::Pull(void) -{ - T ret = 0; - - S++; - ret |= MemRead(S); - - if(sizeof(T) == 2) - { - S++; - ret |= MemRead(S) << 8; - } - - return ret; -} - -// ABORT not fully implemented/tested. -INLINE void Core65816::ISequence(unsigned which) -{ - uint16 vecaddr; - - switch(which) - { - case ISEQ_COP: vecaddr = 0xFFE4; break; - case ISEQ_BRK: vecaddr = 0xFFE6; break; - case ISEQ_ABORT: vecaddr = 0xFFE8; break; - case ISEQ_NMI: vecaddr = 0xFFEA; break; - case ISEQ_IRQ: vecaddr = 0xFFEE; break; - } - - Push(PBR); - Push(PC); - Push(P); - - P = (P & ~D_FLAG) | I_FLAG; - PBR = 0x00; - PC = MemRead(vecaddr); - - SNES_DBG("[CPU] ISeq %u: %04x\n", which, PC); -} - -// -// -// - -INLINE void Core65816::Instr_BRK(void) -{ - OpRead(PCPBR); - PC++; - OpRead(PCPBR); - - ISequence(ISEQ_BRK); - SampleIRQ(); -} - -INLINE void Core65816::Instr_COP(void) -{ - OpRead(PCPBR); - PC++; - OpRead(PCPBR); - - ISequence(ISEQ_COP); - SampleIRQ(); -} - -INLINE void Core65816::Instr_NOP(void) -{ - IO(); -} - -INLINE void Core65816::Instr_STP(void) -{ - SNES_DBG("[CPU] STP\n"); - CPUM.halted = CPU_Misc::HALTED_STP; - - if(CPUM.timestamp < CPUM.next_event_ts) - CPUM.timestamp = CPUM.next_event_ts; -} - -INLINE void Core65816::Instr_WAI(void) -{ - SampleIRQ(); // Important(to match games' expectations). - - if(!CPUM.CombinedNIState) - { - CPUM.halted = CPU_Misc::HALTED_WAI; - - if(CPUM.timestamp < CPUM.next_event_ts) - CPUM.timestamp = CPUM.next_event_ts; - } -} - -INLINE void Core65816::Instr_WDM(void) -{ - OpRead(PCPBR); - PC++; -} - -// -// -// -template -INLINE void Core65816::Op_ADC(T arg) -{ - T& AA = AC(); - uint32 tmp; - - if(P & D_FLAG) - { - uint32 a, b, c, d; - - a = (AA & 0x000F) + (arg & 0x000F) + (P & 1); - b = (AA & 0x00F0) + (arg & 0x00F0); - - P &= ~(C_FLAG | V_FLAG); - - if(sizeof(T) == 2) - { - c = (AA & 0x0F00) + (arg & 0x0F00); - d = (AA & 0xF000) + (arg & 0xF000); - - if(a > 0x0009) { b += 0x0010; a += 0x0006; } - if(b > 0x0090) { c += 0x0100; b += 0x0060; } - if(c > 0x0900) { d += 0x1000; c += 0x0600; } - P |= ((~(AA ^ arg) & (AA ^ d)) >> (sizeof(T) * 8 - 7)) & 0x40; // V flag - if(d > 0x9000) { P |= C_FLAG; d += 0x6000; } - - tmp = (a & 0x000F) | (b & 0x00F0) | (c & 0x0F00) | (d & 0xF000); - } - else - { - if(a > 0x0009) { b += 0x0010; a += 0x0006; } - P |= ((~(AA ^ arg) & (AA ^ b)) >> (sizeof(T) * 8 - 7)) & 0x40; // V flag - if(b > 0x0090) { P |= C_FLAG; b += 0x0060; } - - tmp = (a & 0x000F) | (b & 0x00F0); - } - } - else - { - tmp = AA + arg + (P & 1); - - P &= ~(C_FLAG | V_FLAG); - P |= (tmp >> (sizeof(T) * 8)) & 1; // C flag - P |= ((~(AA ^ arg) & (AA ^ tmp)) >> (sizeof(T) * 8 - 7)) & 0x40; // V flag - } - - AA = tmp; - SetZN(AA); -} - -template -INLINE void Core65816::Op_AND(T arg) -{ - T& AA = AC(); - - AA &= arg; - - SetZN(AA); -} - -template -INLINE void Core65816::Op_BIT(T arg) // N and V flags are not modified in the immediate addressing form of BIT. -{ - T& AA = AC(); - - P &= ~Z_FLAG; - - if(!(AA & arg)) - P |= Z_FLAG; - - if(!immediate) - { - P &= ~(N_FLAG | V_FLAG); - P |= (arg >> ((sizeof(T) - 1) * 8)) & (N_FLAG | V_FLAG); - } -} - -template -INLINE void Core65816::Op_Compare(T rv, T arg) -{ - uint32 tmp = rv - arg; - - SetZN(tmp); - - P &= ~C_FLAG; - P |= ((tmp >> (sizeof(T) * 8)) & 1) ^ 1; -} - -template -INLINE void Core65816::Op_CMP(T arg) -{ - Op_Compare(C, arg); -} - -template -INLINE void Core65816::Op_CPX(T arg) -{ - Op_Compare(X, arg); -} - -template -INLINE void Core65816::Op_CPY(T arg) -{ - Op_Compare(Y, arg); -} - -template -INLINE void Core65816::Op_EOR(T arg) -{ - T& AA = AC(); - - AA ^= arg; - - SetZN(AA); -} - -template -INLINE void Core65816::Op_LDA(T arg) -{ - T& AA = AC(); - - AA = arg; - - SetZN(AA); -} - -template -INLINE void Core65816::Op_LDX(T arg) -{ - X = arg; - - SetZN(X); -} - -template -INLINE void Core65816::Op_LDY(T arg) -{ - Y = arg; - - SetZN(Y); -} - -template -INLINE void Core65816::Op_ORA(T arg) -{ - T& AA = AC(); - - AA |= arg; - - SetZN(AA); -} - -template -INLINE void Core65816::Op_SBC(T arg) -{ - T& AA = AC(); - uint32 tmp; - - arg = ~arg; - - if(P & D_FLAG) - { - uint32 a, b, c, d; - - a = (AA & 0x000F) + (arg & 0x000F) + (P & 1); - b = (AA & 0x00F0) + (arg & 0x00F0) + (a & 0x0010); - - P &= ~(C_FLAG | V_FLAG); - - if(sizeof(T) == 2) - { - c = (AA & 0x0F00) + (arg & 0x0F00) + (b & 0x0100); - d = (AA & 0xF000) + (arg & 0xF000) + (c & 0x1000); - - P |= ((d >> (sizeof(T) * 8)) & 1); // C flag - - if(a < 0x00010) { a -= 0x0006; } - if(b < 0x00100) { b -= 0x0060; } - if(c < 0x01000) { c -= 0x0600; } - P |= ((~(AA ^ arg) & (AA ^ d)) >> (sizeof(T) * 8 - 7)) & 0x40; // V flag - if(d < 0x10000) { d -= 0x6000; } - - tmp = (a & 0x000F) | (b & 0x00F0) | (c & 0x0F00) | (d & 0xF000); - } - else - { - P |= ((b >> (sizeof(T) * 8)) & 1); // C flag - - if(a < 0x0010) { a -= 0x0006; } - P |= ((~(AA ^ arg) & (AA ^ b)) >> (sizeof(T) * 8 - 7)) & 0x40; // V flag - if(b < 0x0100) { b -= 0x0060; } - - tmp = (a & 0x000F) | (b & 0x00F0); - } - } - else - { - tmp = AA + arg + (P & 1); - - P &= ~(C_FLAG | V_FLAG); - P |= ((tmp >> (sizeof(T) * 8)) & 1); // C flag - P |= ((~(AA ^ arg) & (AA ^ tmp)) >> (sizeof(T) * 8 - 7)) & 0x40; // V flag - } - - AA = tmp; - SetZN(AA); -} - - -// -// -// -template -INLINE void Core65816::Op_ASL(T& arg) -{ - P &= ~C_FLAG; - P |= arg >> (8 * sizeof(T) - 1); - - arg <<= 1; - - SetZN(arg); -} - -template -INLINE void Core65816::Op_DEC(T& arg) -{ - arg--; - - SetZN(arg); -} - -template -INLINE void Core65816::Op_INC(T& arg) -{ - arg++; - - SetZN(arg); -} - -template -INLINE void Core65816::Op_LSR(T& arg) -{ - P &= ~C_FLAG; - P |= arg & 1; - - arg >>= 1; - - SetZN(arg); -} - -template -INLINE void Core65816::Op_ROL(T& arg) -{ - const bool new_CF = arg >> (sizeof(T) * 8 - 1); - - arg <<= 1; - - arg |= (P & 1); - P &= ~C_FLAG; - P |= new_CF; - - SetZN(arg); -} - -template -INLINE void Core65816::Op_ROR(T& arg) -{ - const bool new_CF = arg & 1; - - arg >>= 1; - - arg |= (P & 1) << (sizeof(T) * 8 - 1); - P &= ~C_FLAG; - P |= new_CF; - - SetZN(arg); -} - -template -INLINE void Core65816::Op_TRB(T& arg) -{ - T& AA = AC(); - - P &= ~Z_FLAG; - if(!(arg & AA)) - P |= Z_FLAG; - - arg &= ~AA; -} - -template -INLINE void Core65816::Op_TSB(T& arg) -{ - T& AA = AC(); - - P &= ~Z_FLAG; - if(!(arg & AA)) - P |= Z_FLAG; - - arg |= AA; -} - -// -// -// -// NOTE: Since we're hardcoding in DBR in GetEA_AB(), don't use it -// to implement JSR/JMP/whatever(at least not without modification). -INLINE uint32 Core65816::GetEA_AB(void) -{ - uint32 ea = DBRSL16; - - ea |= OpRead(PCPBR); - PC++; - - ea |= OpRead(PCPBR) << 8; - PC++; - - return ea; -} - -template -INLINE uint32 Core65816::GetEA_ABI(uint16 index) -{ - uint32 ea; - - ea = GetEA_AB(); - - if(UncondEC || (((ea + index) ^ ea) & 0x100)) - IO(); - - ea = (ea + index) & 0xFFFFFF; - - return ea; -} - -template -INLINE uint32 Core65816::GetEA_ABX(void) -{ - return GetEA_ABI(X); -} - -template -INLINE uint32 Core65816::GetEA_ABY(void) -{ - return GetEA_ABI(Y); -} - -INLINE uint32 Core65816::GetEA_ABL(void) -{ - uint32 ea; - - ea = OpRead(PCPBR); - PC++; - - ea |= OpRead(PCPBR) << 8; - PC++; - - ea |= OpRead(PCPBR) << 16; - PC++; - - return ea; -} - -INLINE uint32 Core65816::GetEA_ABLX(void) -{ - uint32 ea; - - ea = GetEA_ABL(); - ea = (ea + X) & 0xFFFFFF; - - return ea; -} - -INLINE uint16 Core65816::GetEA_DP(void) // d -{ - uint16 ea; - - ea = OpRead(PCPBR); - PC++; - - if(D & 0xFF) - IO(); - - ea = (ea + D); - - return ea; -} - -INLINE uint16 Core65816::GetEA_DPI(uint16 index) -{ - uint16 ea; - - ea = GetEA_DP(); - - IO(); - ea = (ea + index); - - return ea; -} - -INLINE uint16 Core65816::GetEA_DPX(void) // d, X -{ - return GetEA_DPI(X); -} - -INLINE uint16 Core65816::GetEA_DPY(void) // d, Y -{ - return GetEA_DPI(Y); -} - -INLINE uint32 Core65816::GetEA_IND(void) // (d) -{ - uint16 eadp; - uint32 ea = DBRSL16; - - eadp = GetEA_DP(); - - ea |= MemRead(eadp); - eadp++; - - ea |= MemRead(eadp) << 8; - - return ea; -} - -INLINE uint32 Core65816::GetEA_INDL(void) // [d] -{ - uint16 eadp; - uint32 ea; - - eadp = GetEA_DP(); - - ea = MemRead(eadp); - eadp++; - - ea |= MemRead(eadp) << 8; - eadp++; - - ea |= MemRead(eadp) << 16; - - return ea; -} - -INLINE uint32 Core65816::GetEA_IX(void) // (d, X) -{ - uint16 eadp; - uint32 ea = DBRSL16; - - eadp = GetEA_DPX(); - - ea |= MemRead(eadp); - eadp++; - - ea |= MemRead(eadp) << 8; - - return ea; -} - -template -INLINE uint32 Core65816::GetEA_IY(void) // (d), Y -{ - uint32 ea; - - ea = GetEA_IND(); - - if(UncondEC || (((ea + Y) ^ ea) & 0x100)) - IO(); - - ea = (ea + Y) & 0xFFFFFF; - - return ea; -} - -INLINE uint32 Core65816::GetEA_ILY(void) // [d], Y -{ - uint32 ea; - - ea = GetEA_INDL(); - - ea = (ea + Y) & 0xFFFFFF; - - return ea; -} - -INLINE uint16 Core65816::GetEA_SR(void) -{ - uint16 ea; - - ea = OpRead(PCPBR); - PC++; - - IO(); - ea = (ea + S); - - return ea; -} - -INLINE uint32 Core65816::GetEA_SRIY(void) // (whatever, S), Y -{ - uint16 easp; - uint32 ea = DBRSL16; - - easp = GetEA_SR(); - - ea |= MemRead(easp); - easp++; - - ea |= MemRead(easp) << 8; - - IO(); - ea = (ea + Y) & 0xFFFFFF; - - return ea; -} - -// -// -// -template -INLINE void Core65816::Instr_LD_IM(void (Core65816::*op)(T)) -{ - T tmp; - - tmp = OpRead(PCPBR); - PC++; - - if(sizeof(T) == 2) - { - tmp |= OpRead(PCPBR) << 8; - PC++; - } - - (this->*op)(tmp); -} - -template -INLINE void Core65816::Instr_LD(EAT (Core65816::*eafn)(void), void (Core65816::*op)(T)) -{ - EAT ea = (this->*eafn)(); - T tmp = MemRead(ea); - - (this->*op)(tmp); -} - -template -INLINE void Core65816::Instr_RMW_A(void (Core65816::*op)(T&)) -{ - IO(); - (this->*op)(AC()); -} - -template -INLINE void Core65816::Instr_RMW(EAT (Core65816::*eafn)(void), void (Core65816::*op)(T&)) -{ - // For 16-bit: L, H, H, L - EAT ea = (this->*eafn)(); - T tmp = MemRead(ea); - - IO(); - (this->*op)(tmp); - - if(sizeof(T) == 2) - MemWrite(ea + 1, tmp >> 8); - - MemWrite(ea, tmp); -} - -template -INLINE void Core65816::Instr_ST(EAT (Core65816::*eafn)(void), T (Core65816::*op)(void)) -{ - EAT ea = (this->*eafn)(); - T tmp = (this->*op)(); - - MemWrite(ea, tmp); -} - -// -// -// - -// -// -// - -INLINE void Core65816::Instr_Bxx(bool cond) -{ - int8 disp; - - disp = OpRead(PCPBR); - PC++; - - if(cond) - { - IO(); - PC += disp; - } -} - -INLINE void Core65816::Instr_BRL(void) -{ - uint16 disp; - - disp = OpRead(PCPBR); - PC++; - - disp |= OpRead(PCPBR) << 8; - PC++; - - IO(); - PC += disp; -} - -INLINE void Core65816::Instr_JML(void) -{ - uint16 npc; - - npc = OpRead(PCPBR); - PC++; - - npc |= OpRead(PCPBR) << 8; - PC++; - - PBR = OpRead(PCPBR); - - PC = npc; -} - -INLINE void Core65816::Instr_JML_I(void) -{ - uint32 ea = 0; // Bank 0, not DBR! - - ea |= OpRead(PCPBR); - PC++; - - ea |= OpRead(PCPBR) << 8; - - PC = MemRead(ea); - PBR = MemRead((ea + 2) & 0xFFFFFF); -} - -INLINE void Core65816::Instr_JMP(void) -{ - uint16 npc; - - npc = OpRead(PCPBR); - PC++; - - npc |= OpRead(PCPBR) << 8; - - PC = npc; -} - -INLINE void Core65816::Instr_JMP_I(void) -{ - uint32 ea = 0; // Bank 0, not DBR! - - ea |= OpRead(PCPBR); - PC++; - - ea |= OpRead(PCPBR) << 8; - - PC = MemRead(ea); -} - -INLINE void Core65816::Instr_JMP_II(void) -{ - uint32 ea = PBR << 16; // PBR, not DBR! - - ea |= OpRead(PCPBR); - PC++; - - ea |= OpRead(PCPBR) << 8; - IO(); - ea = (ea + X) & 0xFFFFFF; - - PC = MemRead(ea); -} - -INLINE void Core65816::Instr_JSL(void) -{ - uint16 npc; - - npc = OpRead(PCPBR); - PC++; - npc |= OpRead(PCPBR) << 8; - PC++; - - Push(PBR); - - IO(); - - PBR = OpRead(PCPBR); - - Push(PC); - - PC = npc; -} - -INLINE void Core65816::Instr_JSR(void) // Different memory access order from 6502... -{ - uint16 npc; - - npc = OpRead(PCPBR); - PC++; - npc |= OpRead(PCPBR) << 8; - - IO(); - - Push(PC); - PC = npc; -} - -// -// PBR not DBR, and wrap within bank for both + X and reading high byte of PC. -// -INLINE void Core65816::Instr_JSR_II(void) -{ - uint16 ea; - - ea = OpRead(PCPBR); - PC++; - - Push(PC); - - ea |= OpRead(PCPBR) << 8; - IO(); - ea += X; - - PC = MemRead((PBR << 16) | ea); - ea++; - PC |= MemRead((PBR << 16) | ea) << 8; -} - - -INLINE void Core65816::Instr_RTI(void) -{ - IO(); - IO(); - - P = Pull(); - PC = Pull(); - PBR = Pull(); - - if(P & X_FLAG) - { - X = (uint8)X; - Y = (uint8)Y; - } - - SampleIRQ(); -} - -INLINE void Core65816::Instr_RTL(void) -{ - IO(); - IO(); - - PC = Pull() + 1; - PBR = Pull(); -} - -INLINE void Core65816::Instr_RTS(void) -{ - IO(); - IO(); - - PC = Pull() + 1; - - IO(); -} - -// -// -// - -template -INLINE void Core65816::Instr_INX(void) -{ - IO(); - X = (T)(X + 1); - SetZN(X); -} - -template -INLINE void Core65816::Instr_INY(void) -{ - IO(); - Y = (T)(Y + 1); - SetZN(Y); -} - -template -INLINE void Core65816::Instr_DEX(void) -{ - IO(); - X = (T)(X - 1); - SetZN(X); -} - -template -INLINE void Core65816::Instr_DEY(void) -{ - IO(); - Y = (T)(Y - 1); - SetZN(Y); -} - -// -// -// - -template -INLINE void Core65816::Instr_TAX(void) -{ - IO(); - - X = (T)C; - - SetZN(X); -} - -template -INLINE void Core65816::Instr_TAY(void) -{ - IO(); - - Y = (T)C; - - SetZN(Y); -} - -INLINE void Core65816::Instr_TCD(void) -{ - IO(); - - D = C; - - SetZN(D); -} - -INLINE void Core65816::Instr_TCS(void) -{ - IO(); - S = C; -} - -INLINE void Core65816::Instr_TDC(void) -{ - IO(); - C = D; - - SetZN(C); -} - -INLINE void Core65816::Instr_TSC(void) -{ - IO(); - C = S; - - SetZN(C); -} - -template -INLINE void Core65816::Instr_TSX(void) -{ - IO(); - X = (T)S; - - SetZN(X); -} - -template -INLINE void Core65816::Instr_TXA(void) -{ - IO(); - AC() = X; - - SetZN(C); -} - -INLINE void Core65816::Instr_TXS(void) -{ - IO(); - S = X; -} - -template -INLINE void Core65816::Instr_TXY(void) -{ - IO(); - Y = X; - - SetZN(Y); -} - -template -INLINE void Core65816::Instr_TYA(void) -{ - IO(); - AC() = Y; - - SetZN(C); -} - -template -INLINE void Core65816::Instr_TYX(void) -{ - IO(); - X = Y; - - SetZN(X); -} - -INLINE void Core65816::Instr_XBA(void) -{ - uint8 tmp = B; - - IO(); - IO(); - - B = A; - A = tmp; - - SetZN(A); -} - -INLINE void Core65816::Instr_XCE(void) -{ - bool new_E = P & C_FLAG; - - P &= ~C_FLAG; - P |= E; - - E = new_E; - - IO(); - SNES_DBG("[CPU] XCE: %u\n", E); -} - -// -// -// - -template -INLINE void Core65816::Instr_CLx(void) -{ - IO(); - P &= ~TA_Mask; -} - -template -INLINE void Core65816::Instr_SEx(void) -{ - IO(); - P |= TA_Mask; -} - -// -// -// - -template -INLINE void Core65816::Instr_MVx(void) -{ - // opcode, dstbank, srcbank - // - // dstbank is loaded into DBR. - // - // source addr: srcbank, X reg - // dest addr, dstbank, Y reg - // - // Respects X flag, seems to ignore M flag. - uint8 SB; - uint8 tmp; - - DBRSL16 = OpRead(PCPBR) << 16; - PC++; - - SB = OpRead(PCPBR); - PC++; - - // - // - tmp = MemRead((SB << 16) | X); - MemWrite((DBRSL16) | Y, tmp); - // - // - - X = (X_type)(X + increment); - Y = (X_type)(Y + increment); - - IO(); - IO(); - - C--; - if(C != 0xFFFF) - PC -= 3; -} - -INLINE void Core65816::Instr_PEA(void) // Push Effective Absolute Address -{ - uint16 ea = GetEA_AB(); - - Push(ea); -} - -INLINE void Core65816::Instr_PEI(void) // Push Effective Indirect Address -{ - uint16 ea = GetEA_IND(); - - Push(ea); -} - -INLINE void Core65816::Instr_PER(void) // Push Effective PC Relative Indirect Address -{ - uint16 ea = GetEA_AB(); - - IO(); - ea += PC; - - Push(ea); -} - -template -INLINE void Core65816::Instr_PHA(void) -{ - IO(); - Push(AC()); -} - -INLINE void Core65816::Instr_PHB(void) -{ - IO(); - Push(DBRSL16 >> 16); -} - -INLINE void Core65816::Instr_PHD(void) -{ - IO(); - Push(D); -} - -INLINE void Core65816::Instr_PHK(void) -{ - IO(); - Push(PBR); -} - -INLINE void Core65816::Instr_PHP(void) -{ - IO(); - Push(P); -} - -template -INLINE void Core65816::Instr_PHX(void) -{ - IO(); - Push(X); -} - -template -INLINE void Core65816::Instr_PHY(void) -{ - IO(); - Push(Y); -} - -template -INLINE void Core65816::Instr_PLA(void) -{ - IO(); - IO(); - - AC() = Pull(); - SetZN(AC()); -} - -INLINE void Core65816::Instr_PLB(void) -{ - IO(); - IO(); - - uint8 tmp = Pull(); - - SetZN(tmp); - DBRSL16 = tmp << 16; -} - -INLINE void Core65816::Instr_PLD(void) -{ - IO(); - IO(); - - D = Pull(); - SetZN(D); -} - -INLINE void Core65816::Instr_PLP(void) -{ - IO(); - IO(); - - P = Pull(); - - if(P & X_FLAG) - { - X = (uint8)X; - Y = (uint8)Y; - } -} - -template -INLINE void Core65816::Instr_PLX(void) -{ - IO(); - IO(); - - X = Pull(); - SetZN(X); -} - -template -INLINE void Core65816::Instr_PLY(void) -{ - IO(); - IO(); - - Y = Pull(); - SetZN(Y); -} - -INLINE void Core65816::Instr_REP(void) -{ - uint8 tmp; - - tmp = OpRead(PCPBR); - PC++; - - IO(); - P &= ~tmp; -} - -INLINE void Core65816::Instr_SEP(void) -{ - uint8 tmp; - - tmp = OpRead(PCPBR); - PC++; - - IO(); - P |= tmp; - - if(P & X_FLAG) - { - X = (uint8)X; - Y = (uint8)Y; - } -} - - -template -INLINE void Core65816::RunInstruction(void) -{ - switch(opcode) - { - case 0x00: Instr_BRK(); break; // BRK - case 0x02: Instr_COP(); break; // COP - case 0xEA: Instr_NOP(); break; // NOP - case 0xDB: Instr_STP(); break; // STP - case 0xCB: Instr_WAI(); break; // WAI - case 0x42: Instr_WDM(); break; // WDM (effectively 2-byte NOP). - - // - // Block transfer - // - case 0x44: Instr_MVx(); break; // MVP - case 0x54: Instr_MVx(); break; // MVN - - // - // Stack pushing... - // - case 0xF4: Instr_PEA(); break; // PEA - case 0xD4: Instr_PEI(); break; // PEI - case 0x62: Instr_PER(); break; // PER - case 0x48: Instr_PHA(); break; // PHA - case 0x8B: Instr_PHB(); break; // PHB - case 0x0B: Instr_PHD(); break; // PHD - case 0x4B: Instr_PHK(); break; // PHK - case 0x08: Instr_PHP(); break; // PHP - case 0xDA: Instr_PHX(); break; // PHX - case 0x5A: Instr_PHY(); break; // PHY - - // - // ...and pulling. - // - case 0x68: Instr_PLA(); break; // PLA - case 0xAB: Instr_PLB(); break; // PLB - case 0x2B: Instr_PLD(); break; // PLD - case 0x28: Instr_PLP(); break; // PLP - case 0xFA: Instr_PLX(); break; // PLX - case 0x7A: Instr_PLY(); break; // PLY - - case 0x4C: Instr_JMP(); break; // JMP $addr - case 0x6C: Instr_JMP_I(); break; // JMP ($addr) - case 0x7C: Instr_JMP_II(); break; // JMP ($addr, X) - case 0x5C: Instr_JML(); break; // JMP long(aka JML). - case 0xDC: Instr_JML_I(); break; // JMP [long] (aka JML) - - case 0x22: Instr_JSL(); break; // JSR long(aka JSL) - case 0x20: Instr_JSR(); break; // JSR $addr - case 0xFC: Instr_JSR_II(); break; // JSR ($addr, X) - - case 0x40: Instr_RTI(); break; // RTI - case 0x6B: Instr_RTL(); break; // RTL - case 0x60: Instr_RTS(); break; // RTS - - #define INSTR(J, K, L) Instr_##J(&Core65816::GetEA_##K, &Core65816::Op_##L) - // - // ADC - // - case 0x69: Instr_LD_IM (&Core65816::Op_ADC); break; - case 0x65: INSTR(LD, DP, ADC); break; - case 0x75: INSTR(LD, DPX, ADC); break; - case 0x6D: INSTR(LD, AB, ADC); break; - case 0x6F: INSTR(LD, ABL, ADC); break; - case 0x7D: INSTR(LD, ABX, ADC); break; - case 0x7F: INSTR(LD, ABLX, ADC); break; - case 0x79: INSTR(LD, ABY, ADC); break; - case 0x72: INSTR(LD, IND, ADC); break; - case 0x67: INSTR(LD, INDL, ADC); break; - case 0x61: INSTR(LD, IX, ADC); break; - case 0x71: INSTR(LD, IY, ADC); break; - case 0x77: INSTR(LD, ILY, ADC); break; - case 0x63: INSTR(LD, SR, ADC); break; - case 0x73: INSTR(LD, SRIY, ADC); break; - - // - // AND - // - case 0x29: Instr_LD_IM (&Core65816::Op_AND); break; - case 0x25: INSTR(LD, DP, AND); break; - case 0x35: INSTR(LD, DPX, AND); break; - case 0x2D: INSTR(LD, AB, AND); break; - case 0x2F: INSTR(LD, ABL, AND); break; - case 0x3D: INSTR(LD, ABX, AND); break; - case 0x3F: INSTR(LD, ABLX, AND); break; - case 0x39: INSTR(LD, ABY, AND); break; - case 0x32: INSTR(LD, IND, AND); break; - case 0x27: INSTR(LD, INDL, AND); break; - case 0x21: INSTR(LD, IX, AND); break; - case 0x31: INSTR(LD, IY, AND); break; - case 0x37: INSTR(LD, ILY, AND); break; - case 0x23: INSTR(LD, SR, AND); break; - case 0x33: INSTR(LD, SRIY, AND); break; - - // - // CMP - // - case 0xC9: Instr_LD_IM (&Core65816::Op_CMP); break; - case 0xC5: INSTR(LD, DP, CMP); break; - case 0xD5: INSTR(LD, DPX, CMP); break; - case 0xCD: INSTR(LD, AB, CMP); break; - case 0xCF: INSTR(LD, ABL, CMP); break; - case 0xDD: INSTR(LD, ABX, CMP); break; - case 0xDF: INSTR(LD, ABLX, CMP); break; - case 0xD9: INSTR(LD, ABY, CMP); break; - case 0xD2: INSTR(LD, IND, CMP); break; - case 0xC7: INSTR(LD, INDL, CMP); break; - case 0xC1: INSTR(LD, IX, CMP); break; - case 0xD1: INSTR(LD, IY, CMP); break; - case 0xD7: INSTR(LD, ILY, CMP); break; - case 0xC3: INSTR(LD, SR, CMP); break; - case 0xD3: INSTR(LD, SRIY, CMP); break; - - // - // EOR - // - case 0x49: Instr_LD_IM (&Core65816::Op_EOR); break; - case 0x45: INSTR(LD, DP, EOR); break; - case 0x55: INSTR(LD, DPX, EOR); break; - case 0x4D: INSTR(LD, AB, EOR); break; - case 0x4F: INSTR(LD, ABL, EOR); break; - case 0x5D: INSTR(LD, ABX, EOR); break; - case 0x5F: INSTR(LD, ABLX, EOR); break; - case 0x59: INSTR(LD, ABY, EOR); break; - case 0x52: INSTR(LD, IND, EOR); break; - case 0x47: INSTR(LD, INDL, EOR); break; - case 0x41: INSTR(LD, IX, EOR); break; - case 0x51: INSTR(LD, IY, EOR); break; - case 0x57: INSTR(LD, ILY, EOR); break; - case 0x43: INSTR(LD, SR, EOR); break; - case 0x53: INSTR(LD, SRIY, EOR); break; +void DBG_CPUHook(uint32 PCPBR, uint8 P); - // - // LDA - // - case 0xA9: Instr_LD_IM (&Core65816::Op_LDA); break; - case 0xA5: INSTR(LD, DP, LDA); break; - case 0xB5: INSTR(LD, DPX, LDA); break; - case 0xAD: INSTR(LD, AB, LDA); break; - case 0xAF: INSTR(LD, ABL, LDA); break; - case 0xBD: INSTR(LD, ABX, LDA); break; - case 0xBF: INSTR(LD, ABLX, LDA); break; - case 0xB9: INSTR(LD, ABY, LDA); break; - case 0xB2: INSTR(LD, IND, LDA); break; - case 0xA7: INSTR(LD, INDL, LDA); break; - case 0xA1: INSTR(LD, IX, LDA); break; - case 0xB1: INSTR(LD, IY, LDA); break; - case 0xB7: INSTR(LD, ILY, LDA); break; - case 0xA3: INSTR(LD, SR, LDA); break; - case 0xB3: INSTR(LD, SRIY, LDA); break; +#include "cpu_hlif.inc" - // - // ORA - // - case 0x09: Instr_LD_IM (&Core65816::Op_ORA); break; - case 0x05: INSTR(LD, DP, ORA); break; - case 0x15: INSTR(LD, DPX, ORA); break; - case 0x0D: INSTR(LD, AB, ORA); break; - case 0x0F: INSTR(LD, ABL, ORA); break; - case 0x1D: INSTR(LD, ABX, ORA); break; - case 0x1F: INSTR(LD, ABLX, ORA); break; - case 0x19: INSTR(LD, ABY, ORA); break; - case 0x12: INSTR(LD, IND, ORA); break; - case 0x07: INSTR(LD, INDL, ORA); break; - case 0x01: INSTR(LD, IX, ORA); break; - case 0x11: INSTR(LD, IY, ORA); break; - case 0x17: INSTR(LD, ILY, ORA); break; - case 0x03: INSTR(LD, SR, ORA); break; - case 0x13: INSTR(LD, SRIY, ORA); break; - - // - // SBC - // - case 0xE9: Instr_LD_IM (&Core65816::Op_SBC); break; - case 0xE5: INSTR(LD, DP, SBC); break; - case 0xF5: INSTR(LD, DPX, SBC); break; - case 0xED: INSTR(LD, AB, SBC); break; - case 0xEF: INSTR(LD, ABL, SBC); break; - case 0xFD: INSTR(LD, ABX, SBC); break; - case 0xFF: INSTR(LD, ABLX, SBC); break; - case 0xF9: INSTR(LD, ABY, SBC); break; - case 0xF2: INSTR(LD, IND, SBC); break; - case 0xE7: INSTR(LD, INDL, SBC); break; - case 0xE1: INSTR(LD, IX, SBC); break; - case 0xF1: INSTR(LD, IY, SBC); break; - case 0xF7: INSTR(LD, ILY, SBC); break; - case 0xE3: INSTR(LD, SR, SBC); break; - case 0xF3: INSTR(LD, SRIY, SBC); break; - - // - // STA - // - case 0x85: INSTR(ST, DP, STA); break; - case 0x95: INSTR(ST, DPX, STA); break; - case 0x8D: INSTR(ST, AB, STA); break; - case 0x8F: INSTR(ST, ABL, STA); break; - case 0x9D: INSTR(ST, ABX, STA); break; - case 0x9F: INSTR(ST, ABLX, STA); break; - case 0x99: INSTR(ST, ABY, STA); break; - case 0x92: INSTR(ST, IND, STA); break; - case 0x87: INSTR(ST, INDL, STA); break; - case 0x81: INSTR(ST, IX, STA); break; - case 0x91: INSTR(ST, IY, STA); break; - case 0x97: INSTR(ST, ILY, STA); break; - case 0x83: INSTR(ST, SR, STA); break; - case 0x93: INSTR(ST, SRIY, STA); break; - - // - // BIT - // - case 0x89: Instr_LD_IM(&Core65816::Op_BIT); break; - case 0x24: INSTR(LD, DP, BIT); break; - case 0x34: INSTR(LD, DPX, BIT); break; - case 0x2C: INSTR(LD, AB, BIT); break; - case 0x3C: INSTR(LD, ABX, BIT); break; - - // - // CPX - // - case 0xE0: Instr_LD_IM (&Core65816::Op_CPX); break; - case 0xE4: INSTR(LD, DP, CPX); break; - case 0xEC: INSTR(LD, AB, CPX); break; - - // - // CPY - // - case 0xC0: Instr_LD_IM (&Core65816::Op_CPY); break; - case 0xC4: INSTR(LD, DP, CPY); break; - case 0xCC: INSTR(LD, AB, CPY); break; - - // - // LDX - // - case 0xA2: Instr_LD_IM (&Core65816::Op_LDX); break; - case 0xA6: INSTR(LD, DP, LDX); break; - case 0xB6: INSTR(LD, DPY, LDX); break; - case 0xAE: INSTR(LD, AB, LDX); break; - case 0xBE: INSTR(LD, ABY, LDX); break; - - // - // LDY - // - case 0xA0: Instr_LD_IM (&Core65816::Op_LDY); break; - case 0xA4: INSTR(LD, DP, LDY); break; - case 0xB4: INSTR(LD, DPX, LDY); break; - case 0xAC: INSTR(LD, AB, LDY); break; - case 0xBC: INSTR(LD, ABX, LDY); break; - - // - // STX - // - case 0x86: INSTR(ST, DP, STX); break; - case 0x96: INSTR(ST, DPY, STX); break; - case 0x8E: INSTR(ST, AB, STX); break; - - // - // STY - // - case 0x84: INSTR(ST, DP, STY); break; - case 0x94: INSTR(ST, DPX, STY); break; - case 0x8C: INSTR(ST, AB, STY); break; - - // - // STZ - // - case 0x64: INSTR(ST, DP, STZ); break; - case 0x74: INSTR(ST, DPX, STZ); break; - case 0x9C: INSTR(ST, AB, STZ); break; - case 0x9E: INSTR(ST, ABX, STZ); break; - - // - // - // ASL - // - case 0x0A: Instr_RMW_A(&Core65816::Op_ASL); break; - case 0x06: INSTR(RMW, DP, ASL); break; - case 0x16: INSTR(RMW, DPX, ASL); break; - case 0x0E: INSTR(RMW, AB, ASL); break; - case 0x1E: INSTR(RMW, ABX, ASL); break; - - // - // DEC - // - case 0x3A: Instr_RMW_A(&Core65816::Op_DEC); break; - case 0xC6: INSTR(RMW, DP, DEC); break; - case 0xD6: INSTR(RMW, DPX, DEC); break; - case 0xCE: INSTR(RMW, AB, DEC); break; - case 0xDE: INSTR(RMW, ABX, DEC); break; - - // - // INC - // - case 0x1A: Instr_RMW_A(&Core65816::Op_INC); break; - case 0xE6: INSTR(RMW, DP, INC); break; - case 0xF6: INSTR(RMW, DPX, INC); break; - case 0xEE: INSTR(RMW, AB, INC); break; - case 0xFE: INSTR(RMW, ABX, INC); break; - - // - // LSR - // - case 0x4A: Instr_RMW_A(&Core65816::Op_LSR); break; - case 0x46: INSTR(RMW, DP, LSR); break; - case 0x56: INSTR(RMW, DPX, LSR); break; - case 0x4E: INSTR(RMW, AB, LSR); break; - case 0x5E: INSTR(RMW, ABX, LSR); break; - - // - // ROL - // - case 0x2A: Instr_RMW_A(&Core65816::Op_ROL); break; - case 0x26: INSTR(RMW, DP, ROL); break; - case 0x36: INSTR(RMW, DPX, ROL); break; - case 0x2E: INSTR(RMW, AB, ROL); break; - case 0x3E: INSTR(RMW, ABX, ROL); break; - - // - // ROR - // - case 0x6A: Instr_RMW_A(&Core65816::Op_ROR); break; - case 0x66: INSTR(RMW, DP, ROR); break; - case 0x76: INSTR(RMW, DPX, ROR); break; - case 0x6E: INSTR(RMW, AB, ROR); break; - case 0x7E: INSTR(RMW, ABX, ROR); break; - - // - // TRB - // - case 0x14: INSTR(RMW, DP, TRB); break; - case 0x1C: INSTR(RMW, AB, TRB); break; - - // - // TSB - // - case 0x04: INSTR(RMW, DP, TSB); break; - case 0x0C: INSTR(RMW, AB, TSB); break; - - #undef INSTR - - case 0xE8: Instr_INX(); break; - case 0xC8: Instr_INY(); break; - - case 0xCA: Instr_DEX(); break; - case 0x88: Instr_DEY(); break; - - // - // Branch Instructions - // - case 0x90: Instr_Bxx(!(P & C_FLAG)); break; // BCC - case 0xB0: Instr_Bxx( (P & C_FLAG)); break; // BCS - case 0xF0: Instr_Bxx( (P & Z_FLAG)); break; // BEQ - case 0x30: Instr_Bxx( (P & N_FLAG)); break; // BMI - case 0xD0: Instr_Bxx(!(P & Z_FLAG)); break; // BNE - case 0x10: Instr_Bxx(!(P & N_FLAG)); break; // BPL - case 0x80: Instr_Bxx( true ); break; // BRA - case 0x50: Instr_Bxx(!(P & V_FLAG)); break; // BVC - case 0x70: Instr_Bxx( (P & V_FLAG)); break; // BVS - case 0x82: Instr_BRL(); break; // BRL - - // - // Exchange/Transfer instructions - // - case 0xAA: Instr_TAX(); break; // TAX - case 0xA8: Instr_TAY(); break; // TAY - case 0x5B: Instr_TCD(); break; // TCD - case 0x1B: Instr_TCS(); break; // TCS - case 0x7B: Instr_TDC(); break; // TDC - case 0x3B: Instr_TSC(); break; // TSC - case 0xBA: Instr_TSX(); break; // TSX - case 0x8A: Instr_TXA(); break; // TXA - case 0x9A: Instr_TXS(); break; // TXS - case 0x9B: Instr_TXY(); break; // TXY - case 0x98: Instr_TYA(); break; // TYA - case 0xBB: Instr_TYX(); break; // TYX - case 0xEB: Instr_XBA(); break; // XBA - case 0xFB: Instr_XCE(); break; // XCE - - // - // Simple flag setting and clearing instructions. - // - case 0x18: Instr_CLx(); break; // CLC - case 0xD8: Instr_CLx(); break; // CLD - case 0x58: Instr_CLx(); break; // CLI - case 0xB8: Instr_CLx(); break; // CLV - - case 0x38: Instr_SEx(); break; // SEC - case 0xF8: Instr_SEx(); break; // SED - case 0x78: Instr_SEx(); break; // SEI - - case 0xC2: Instr_REP(); break; // REP (Reset Status Bits) - case 0xE2: Instr_SEP(); break; // SEP (Set Processor Status Bits) - } -} - -void Core65816::Reset(bool powering_up) -{ - E = true; // Oh Tetris Attack, you're so crazy~ - D = 0x0000; - DBRSL16 = 0x00 << 16; - PBR = 0x00; - S = 0x01FD; - P = M_FLAG | X_FLAG | I_FLAG; - - PIN_Delay = 0; - - PC = MemRead(0xFFFC); -} - -static Core65816 core; -CPU_Misc CPUM; - -void CPU_Run(void) -{ -#ifdef HAVE_COMPUTED_GOTO - const void* const LoopTable[4] = - { - &&Loop_0, &&Loop_1, &&Loop_2, &&Loop_3, - }; - #define GOTO_MXLOOPTABLE() goto *LoopTable[(lc.P >> 4) & 0x3]; -#else - #define GOTO_MXLOOPTABLE() { switch((lc.P >> 4) & 0x3) { case 0: goto Loop_0; case 1: goto Loop_1; case 2: goto Loop_2; case 3: goto Loop_3; } } -#endif - - Core65816 lc = core; - - CPUM.running_mask = ~0U; - GOTO_MXLOOPTABLE(); - - #define CPULBMX Loop_0 - #define CPULBMTYPE uint16 - #define CPULBXTYPE uint16 - #include "cpu_loop_body.inc" - #undef CPULBXTYPE - #undef CPULBMTYPE - #undef CPULBMX - - #define CPULBMX Loop_1 - #define CPULBMTYPE uint16 - #define CPULBXTYPE uint8 - #include "cpu_loop_body.inc" - #undef CPULBXTYPE - #undef CPULBMTYPE - #undef CPULBMX - - #define CPULBMX Loop_2 - #define CPULBMTYPE uint8 - #define CPULBXTYPE uint16 - #include "cpu_loop_body.inc" - #undef CPULBXTYPE - #undef CPULBMTYPE - #undef CPULBMX - - #define CPULBMX Loop_3 - #define CPULBMTYPE uint8 - #define CPULBXTYPE uint8 - #include "cpu_loop_body.inc" - #undef CPULBXTYPE - #undef CPULBMTYPE - #undef CPULBMX - - - ExitCat: ; - core = lc; -} - -void CPU_Reset(bool powering_up) -{ - CPUM.halted = 0; - CPUM.mdr = 0x00; - - CPUM.CombinedNIState &= ~0x01; - - core.Reset(powering_up); -} - -void CPU_Init(void) -{ - CPUM.PrevNMILineState = false; - CPUM.CombinedNIState = 0x00; - CPUM.NMILineState = false; - CPUM.PrevNMILineState = false; -} - - -void Core65816::StateAction(StateMem* sm, const unsigned load, const bool data_only) -{ - SFORMAT StateRegs[] = - { - SFVAR(PC), - SFVAR(PBR), - SFVAR(DBRSL16), - SFVAR(S), - SFVAR(D), - SFVAR(C), - SFVAR(X), - SFVAR(Y), - SFVAR(P), - SFVAR(E), - - SFVAR(PIN_Delay), - - SFEND - }; - - MDFNSS_StateAction(sm, load, data_only, StateRegs, "CPUCORE"); -}; - -void CPU_StateAction(StateMem* sm, const unsigned load, const bool data_only) -{ - SFORMAT StateRegs[] = - { - SFVAR(CPUM.mdr), - SFVAR(CPUM.halted), - SFVAR(CPUM.CombinedNIState), - SFVAR(CPUM.NMILineState), - SFVAR(CPUM.PrevNMILineState), - - SFEND - }; - - MDFNSS_StateAction(sm, load, data_only, StateRegs, "CPU"); - - core.StateAction(sm, load, data_only); -} } diff --git a/mednafen/snes_faust/cpu.h b/mednafen/snes_faust/cpu.h index b13b782..5895f2c 100644 --- a/mednafen/snes_faust/cpu.h +++ b/mednafen/snes_faust/cpu.h @@ -36,12 +36,14 @@ struct CPU_Misc uint32 next_event_ts; uint32 running_mask; + uint32 PIN_Delay; + enum { HALTED_NOT = 0, - HALTED_WAI = 1, - HALTED_STP = 2, - HALTED_DMA = 3 + HALTED_WAI = 1 << 0, + HALTED_STP = 1 << 1, + HALTED_DMA = 1 << 2 }; uint8 halted; @@ -50,6 +52,7 @@ struct CPU_Misc uint8 CombinedNIState; bool NMILineState; bool PrevNMILineState; + uint8 MultiIRQState; readfunc ReadFuncs[256]; // A and B bus read handlers writefunc WriteFuncs[256]; // A and B bus write handlers @@ -125,10 +128,18 @@ INLINE void CPU_IO(void) CPUM.timestamp += 6; } -INLINE void CPU_SetIRQ(bool active) +enum { + CPU_IRQSOURCE_PPU = 0, + CPU_IRQSOURCE_CART +}; + +INLINE void CPU_SetIRQ(bool active, unsigned w = CPU_IRQSOURCE_PPU) +{ + CPUM.MultiIRQState &= ~(1 << w); + CPUM.MultiIRQState |= active << w; CPUM.CombinedNIState &= ~0x04; - CPUM.CombinedNIState |= active ? 0x04 : 0x00; + CPUM.CombinedNIState |= CPUM.MultiIRQState ? 0x04 : 0x00; } INLINE void CPU_SetNMI(bool active) @@ -139,9 +150,14 @@ INLINE void CPU_SetNMI(bool active) CPUM.NMILineState = active; } +INLINE void CPU_TriggerIRQNMIDelayKludge(void) +{ + CPUM.PIN_Delay |= 0x80; +} + void CPU_Init(void) MDFN_COLD; void CPU_Reset(bool powering_up) MDFN_COLD; -void CPU_StateAction(StateMem* sm, const unsigned load, const bool data_only); +void CPU_StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname, const char* sname_core); void CPU_Run(void) MDFN_HOT; INLINE void CPU_Exit(void) @@ -149,6 +165,17 @@ INLINE void CPU_Exit(void) CPUM.running_mask = 0; CPUM.next_event_ts = 0; } +// +// +// +/* +enum +{ + CPU_GSREG_WHATEVER = Core65816::GSREG__BOUND, +}; +*/ +uint32 CPU_GetRegister(const unsigned id, char* const special = nullptr, const uint32 special_len = 0) MDFN_COLD; +void CPU_SetRegister(const unsigned id, const uint32 value) MDFN_COLD; } diff --git a/mednafen/snes_faust/cpu_hlif.inc b/mednafen/snes_faust/cpu_hlif.inc new file mode 100644 index 0000000..a3f4c6e --- /dev/null +++ b/mednafen/snes_faust/cpu_hlif.inc @@ -0,0 +1,240 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* cpu_hlif.inc: +** Copyright (C) 2015-2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "Core65816.h" + +template +INLINE void Core65816::MemWrite(uint32 addr, T val) +{ + CPU_Write(addr, val); + + if(sizeof(T) == 2) + { + addr++; + CPU_Write(addr, val >> 8); + } +} + +template +INLINE T Core65816::MemRead(uint32 addr) +{ + T ret; + + ret = CPU_Read(addr); + + if(sizeof(T) == 2) + { + addr++; + ret |= CPU_Read(addr) << 8; + } + + return ret; +} +//static bool popread = false; +INLINE uint8 Core65816::OpRead(uint32 addr) +{ + uint8 ret = MemRead(addr); + + //if(popread) + // SNES_DBG(" %02x\n", ret); + + return ret; +} + +INLINE void Core65816::IO(void) +{ + CPU_IO(); +} + +INLINE void Core65816::Instr_STP(void) +{ + SNES_DBG("[CPU] STP\n"); + CPUM.halted |= CPU_Misc::HALTED_STP; + + if(CPUM.timestamp < CPUM.next_event_ts) + CPUM.timestamp = CPUM.next_event_ts; +} + +INLINE void Core65816::Instr_WAI(void) +{ + SampleIRQ(); // Important(to match games' expectations). + + if(!CPUM.CombinedNIState) + { + CPUM.halted |= CPU_Misc::HALTED_WAI; + + if(CPUM.timestamp < CPUM.next_event_ts) + CPUM.timestamp = CPUM.next_event_ts; + } +} + +INLINE void Core65816::SampleIRQ(void) +{ + CPUM.PIN_Delay = ((P ^ I_FLAG) | 0x01) & CPUM.CombinedNIState; +} + +INLINE void Core65816::BranchOccurred(unsigned iseq) +{ +#ifdef SNES_DBG_ENABLE + DBG_AddBranchTrace(PCPBR, iseq); +#endif +} + +#include "Core65816.inc" + +static Core65816 core; +CPU_Misc CPUM; + +void CPU_Run(void) +{ +#ifdef HAVE_COMPUTED_GOTO + const void* const LoopTable[4] = + { + &&Loop_0, &&Loop_1, &&Loop_2, &&Loop_3, + }; + #define GOTO_MXLOOPTABLE() goto *LoopTable[(lc.P >> 4) & 0x3]; +#else + #define GOTO_MXLOOPTABLE() { switch((lc.P >> 4) & 0x3) { case 0: goto Loop_0; case 1: goto Loop_1; case 2: goto Loop_2; case 3: goto Loop_3; } } +#endif + + Core65816 lc = core; + + CPUM.running_mask = ~0U; + GOTO_MXLOOPTABLE(); + + #define CPULBMX Loop_0 + #define CPULBMTYPE uint16 + #define CPULBXTYPE uint16 + #include "cpu_loop_body.inc" + #undef CPULBXTYPE + #undef CPULBMTYPE + #undef CPULBMX + + #define CPULBMX Loop_1 + #define CPULBMTYPE uint16 + #define CPULBXTYPE uint8 + #include "cpu_loop_body.inc" + #undef CPULBXTYPE + #undef CPULBMTYPE + #undef CPULBMX + + #define CPULBMX Loop_2 + #define CPULBMTYPE uint8 + #define CPULBXTYPE uint16 + #include "cpu_loop_body.inc" + #undef CPULBXTYPE + #undef CPULBMTYPE + #undef CPULBMX + + #define CPULBMX Loop_3 + #define CPULBMTYPE uint8 + #define CPULBXTYPE uint8 + #include "cpu_loop_body.inc" + #undef CPULBXTYPE + #undef CPULBMTYPE + #undef CPULBMX + + + ExitCat: ; + core = lc; +} + +void CPU_Reset(bool powering_up) +{ + CPUM.halted = 0; + CPUM.mdr = 0x00; + + CPUM.CombinedNIState &= ~0x01; + + if(powering_up) + core.Power(); + // + CPUM.PIN_Delay = 0x40; // Trigger reset +} + +void CPU_Init(void) +{ + CPUM.timestamp = 0; + + CPUM.PIN_Delay = 0; + CPUM.PrevNMILineState = false; + CPUM.CombinedNIState = 0x00; + CPUM.MultiIRQState = 0x00; + CPUM.NMILineState = false; + CPUM.PrevNMILineState = false; +} + +void CPU_StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname, const char* sname_core) +{ + if(load && load < 0x00102300) + { + SFORMAT BWCStateRegs[] = + { + SFVARN(CPUM.PIN_Delay, "PIN_Delay"), + SFEND + }; + MDFNSS_StateAction(sm, load, data_only, BWCStateRegs, sname_core); + } + // + // + // + SFORMAT StateRegs[] = + { + SFVAR(CPUM.PIN_Delay), + SFVAR(CPUM.mdr), + SFVAR(CPUM.halted), + SFVAR(CPUM.CombinedNIState), + SFVAR(CPUM.NMILineState), + SFVAR(CPUM.PrevNMILineState), + SFVAR(CPUM.MultiIRQState), + SFEND + }; + + MDFNSS_StateAction(sm, load, data_only, StateRegs, sname); + + if(load && load < 0x00102300) + { + uint8 new_halted = 0; + + switch(CPUM.halted) + { + case 1: new_halted = CPU_Misc::HALTED_WAI; break; + case 2: new_halted = CPU_Misc::HALTED_STP; break; + case 3: new_halted = CPU_Misc::HALTED_DMA; break; + } + CPUM.halted = new_halted; + } + + core.StateAction(sm, load, data_only, sname_core); +} +// +// +// +uint32 CPU_GetRegister(const unsigned id, char* const special, const uint32 special_len) +{ + return core.GetRegister(id, special, special_len); +} + +void CPU_SetRegister(const unsigned id, const uint32 value) +{ + core.SetRegister(id, value); +} + diff --git a/mednafen/snes_faust/cpu_loop_body.inc b/mednafen/snes_faust/cpu_loop_body.inc index f5d3838..446dc61 100644 --- a/mednafen/snes_faust/cpu_loop_body.inc +++ b/mednafen/snes_faust/cpu_loop_body.inc @@ -2,7 +2,7 @@ /* Mednafen Fast SNES Emulation Module */ /******************************************************************************/ /* cpu_loop_body.inc: -** Copyright (C) 2015-2016 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -23,46 +23,102 @@ CPULBMX : while(MDFN_LIKELY(CPUM.running_mask)) { - if(CPUM.halted) + if(MDFN_UNLIKELY(CPUM.halted)) { - if(CPUM.halted == CPU_Misc::HALTED_DMA) + if(CPUM.halted & CPU_Misc::HALTED_DMA) CPUM.RunDMA(); - else + // + // + if(CPUM.halted && !(CPUM.halted & CPU_Misc::HALTED_DMA)) { - lc.SampleIRQ(); - - if(CPUM.halted == CPU_Misc::HALTED_WAI && CPUM.CombinedNIState) + if((CPUM.halted & CPU_Misc::HALTED_WAI) && CPUM.CombinedNIState) + { + lc.SampleIRQ(); + lc.IO(); + lc.IO(); +#if 1 + // Mortal Kombat II-related kludge. + lc.IO(); +#endif + SNES_DBG("WAI done\n"); CPUM.halted = CPU_Misc::HALTED_NOT; + } else if(CPUM.timestamp < CPUM.next_event_ts) CPUM.timestamp = CPUM.next_event_ts; } +#ifdef SNES_DBG_ENABLE + if(!CPUM.halted) + printf("CPU halted finished: %u\n", CPUM.timestamp); +#endif } while(MDFN_LIKELY(CPUM.timestamp < CPUM.next_event_ts)) { uint8 opcode; - if(MDFN_UNLIKELY(lc.PIN_Delay)) +#ifdef SNES_DBG_ENABLE + core = lc; + DBG_CPUHook(core.PCPBR, core.P); + lc = core; +#endif + { - lc.OpRead(lc.PCPBR); - lc.IO(); + const uint32 pind = CPUM.PIN_Delay; - if(MDFN_UNLIKELY(lc.PIN_Delay & 1)) + if(MDFN_UNLIKELY(pind)) { - lc.ISequence(Core65816::ISEQ_NMI); - CPUM.CombinedNIState &= ~0x01; + if(MDFN_LIKELY(!(pind & 0xC1))) // IRQ + { + lc.OpRead(lc.PCPBR); + lc.IO(); + lc.ISequence(Core65816::ISEQ_IRQ); + CPUM.PIN_Delay = 0; + } + else + { + if(MDFN_UNLIKELY(pind & 0x40)) // Reset + { + lc.Reset(); + CPUM.PIN_Delay = 0; + GOTO_MXLOOPTABLE() + } + else if(pind & 0x01) // NMI + { + lc.OpRead(lc.PCPBR); + lc.IO(); + lc.ISequence(Core65816::ISEQ_NMI); + CPUM.CombinedNIState &= ~0x01; + CPUM.PIN_Delay = 0; + } + else // DMA IRQ/NMI delay kludge + { + lc.SampleIRQ(); + opcode = lc.OpRead(lc.PCPBR); + lc.PC++; + // + // + // +#define COMBINE2(a,b) a ## b +#define COMBINE(a,b) COMBINE2(a,b) + if(opcode == 0xA9 && (lc.P & Core65816::M_FLAG)) + CPUM.PIN_Delay = 0; + + goto COMBINE(CPULBMX, OpDispatch); + } + } + continue; } - else - lc.ISequence(Core65816::ISEQ_IRQ); } + // + // + // lc.SampleIRQ(); - -//popread = false; opcode = lc.OpRead(lc.PCPBR); -//popread = true; -// printf("Instr: %02x:%04x, %02x --- C=0x%04x, X=0x%04x, Y=0x%04x -- S=0x%04x, D=0x%04x --- P=0x%02x\n", lc.PBR, lc.PC, opcode, lc.C, lc.X, lc.Y, lc.S, lc.D, lc.P); lc.PC++; + COMBINE(CPULBMX, OpDispatch):; +#undef COMBINE2 +#undef COMBINE switch(opcode) { case 0x00: lc.RunInstruction<0x00, CPULBMTYPE, CPULBXTYPE>(); continue; diff --git a/mednafen/snes_faust/debug.cpp b/mednafen/snes_faust/debug.cpp new file mode 100644 index 0000000..3e19d0f --- /dev/null +++ b/mednafen/snes_faust/debug.cpp @@ -0,0 +1,630 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* debug.cpp: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "snes.h" +#include "input.h" +#include "cart.h" +#include "apu.h" +#include "ppu.h" + +#include "dis65816.h" + +#include + +#include + +#ifdef SNES_DBG_ENABLE + +namespace MDFN_IEN_SNES_FAUST +{ +#include "Core65816.h" + +bool DBG_InHLRead; +static Dis65816* dis; +static uint32 CurPC; + +enum { NUMBT = 24 }; + +static struct +{ + uint32 from; + uint32 to; + uint32 branch_count; + unsigned iseq; // ~0U for no interrupt + bool valid; +} BTEntries[NUMBT]; +//static bool BTEnabled; +static unsigned BTIndex; + +static void (*CPUHook)(uint32, bool); +static bool CPUHookContinuous; + +struct BPOINT +{ + uint32 A[2]; +}; + +static std::vector BreakPointsRead, BreakPointsWrite, BreakPointsPC; + +static bool FoundBPoint; + +enum +{ + ASPACE_PHYSICAL = 0, + ASPACE_WRAM, + ASPACE_VRAM, + ASPACE_CGRAM, + ASPACE_OAM, + ASPACE_OAMHI, + ASPACE_APURAM, + + ASPACE_CARTRAM +}; + +static uint8 HLCPUBusRead(uint32 A) +{ + const uint32 ts_save = CPUM.timestamp; + uint8 ret; + + A &= 0xFFFFFF; + + DBG_InHLRead = true; + ret = CPUM.ReadFuncsA[CPUM.RWIndex[A]](A); + DBG_InHLRead = false; + + if(CPUM.timestamp != ts_save) + { + printf("0x%08x\n", A); + assert(CPUM.timestamp == ts_save); + } + return ret; +} + +template +static MDFN_COLD void GetAddressSpaceBytes(const char *name, uint32 Address, uint32 Length, uint8 *Buffer) +{ + while(MDFN_LIKELY(Length--)) + { + switch(id) + { + default: + break; + + case ASPACE_PHYSICAL: + //TODO: + *Buffer = HLCPUBusRead(Address); + break; + + case ASPACE_WRAM: + Address &= 0x1FFFF; + *Buffer = PeekWRAM(Address); + break; + + case ASPACE_VRAM: + Address &= 0xFFFF; + *Buffer = PPU_PeekVRAM(Address >> 1) >> ((Address & 0x1) << 3); + break; + + case ASPACE_CGRAM: + Address &= 0x1FF; + *Buffer = PPU_PeekCGRAM(Address >> 1) >> ((Address & 0x1) << 3); + break; + + case ASPACE_OAM: + Address &= 0x1FF; + *Buffer = PPU_PeekOAM(Address); + break; + + case ASPACE_OAMHI: + Address &= 0x1F; + *Buffer = PPU_PeekOAMHI(Address); + break; + + case ASPACE_APURAM: + Address &= 0xFFFF; + *Buffer = APU_PeekRAM(Address); + break; + + case ASPACE_CARTRAM: + *Buffer = CART_PeekRAM(Address); + break; + } + Address++; + Buffer++; + } +} + +template +static MDFN_COLD void PutAddressSpaceBytes(const char *name, uint32 Address, uint32 Length, uint32 Granularity, bool hl, const uint8 *Buffer) +{ + while(MDFN_LIKELY(Length--)) + { + switch(id) + { + default: + break; + + case ASPACE_PHYSICAL: + //TODO: + break; + + case ASPACE_WRAM: + Address &= 0x1FFFF; + PokeWRAM(Address, *Buffer); + break; + + case ASPACE_VRAM: + { + const unsigned shift = ((Address & 0x1) << 3); + Address &= 0xFFFF; + PPU_PokeVRAM(Address >> 1, (PPU_PeekVRAM(Address >> 1) & (0xFF00 >> shift)) | (*Buffer << shift)); + } + break; + + case ASPACE_CGRAM: + { + const unsigned shift = ((Address & 0x1) << 3); + Address &= 0x1FF; + PPU_PokeCGRAM(Address >> 1, (PPU_PeekCGRAM(Address >> 1) & (0xFF00 >> shift)) | (*Buffer << shift)); + } + break; + + case ASPACE_OAM: + Address &= 0x1FF; + PPU_PokeOAM(Address, *Buffer); + break; + + case ASPACE_OAMHI: + Address &= 0x1F; + PPU_PokeOAMHI(Address, *Buffer); + break; + + case ASPACE_APURAM: + Address &= 0xFFFF; + APU_PokeRAM(Address, *Buffer); + break; + + case ASPACE_CARTRAM: + CART_PokeRAM(Address, *Buffer); + break; + } + Address++; + Buffer++; + } +} + +static uint32 MemPeek(uint32 A, unsigned int bsize, bool hl, bool logical) +{ + uint32 ret = 0; + + while(bsize) + { + ret <<= 8; + ret |= HLCPUBusRead(A); + bsize--; + } + + return ret; +} + +static MDFN_COLD void FlushBreakPoints(int type) +{ + if(type == BPOINT_READ) + BreakPointsRead.clear(); + else if(type == BPOINT_WRITE) + BreakPointsWrite.clear(); + else if(type == BPOINT_PC) + BreakPointsPC.clear(); +} + +static MDFN_COLD void AddBreakPoint(int type, unsigned int A1, unsigned int A2, bool logical) +{ + BPOINT tmp; + + tmp.A[0] = A1; + tmp.A[1] = A2; + + if(type == BPOINT_READ) + BreakPointsRead.push_back(tmp); + else if(type == BPOINT_WRITE) + BreakPointsWrite.push_back(tmp); + else if(type == BPOINT_PC) + BreakPointsPC.push_back(tmp); +} + +static MDFN_COLD void SetCPUCallback(void (*callb)(uint32 PC, bool bpoint), bool continuous) +{ + CPUHook = callb; + CPUHookContinuous = continuous; +} + +static MDFN_COLD void EnableBranchTrace(bool enable) +{ + +} + +static MDFN_COLD std::vector GetBranchTrace(void) +{ + std::vector ret; + BranchTraceResult tmp; + + for(unsigned x = 0; x < NUMBT; x++) + { + const char* estr = ""; + const auto* bt = &BTEntries[(x + BTIndex) % NUMBT]; + + if(!bt->valid) + continue; + + tmp.count = bt->branch_count; + trio_snprintf(tmp.from, sizeof(tmp.from), "%06x", bt->from); + trio_snprintf(tmp.to, sizeof(tmp.to), "%06x", bt->to); + + switch(bt->iseq) + { + case Core65816::ISEQ_COP: + estr = "COP"; + break; + + case Core65816::ISEQ_BRK: + estr = "BRK"; + break; + + case Core65816::ISEQ_ABORT: + estr = "ABORT"; + break; + + case Core65816::ISEQ_NMI: + estr = "NMI"; + break; + + case Core65816::ISEQ_IRQ: + estr = "IRQ"; + break; + } + + trio_snprintf(tmp.code, sizeof(tmp.code), "%s", estr); + + ret.push_back(tmp); + } + return ret; +} + +void DBG_AddBranchTrace(uint32 to, unsigned iseq) +{ + const uint32 from = CurPC; + auto *prevbt = &BTEntries[(BTIndex + NUMBT - 1) % NUMBT]; + + //if(BTEntries[(BTIndex - 1) & 0xF] == PC) return; + + if(prevbt->from == from && prevbt->to == to && prevbt->iseq == iseq && prevbt->branch_count < 0xFFFFFFFF && prevbt->valid) + prevbt->branch_count++; + else + { + auto& bte = BTEntries[BTIndex]; + bte.from = from; + bte.to = to; + bte.iseq = iseq; + bte.branch_count = 1; + bte.valid = true; + + BTIndex = (BTIndex + 1) % NUMBT; + } +} + +void DBG_CPUHook(uint32 PCPBR, uint8 P) +{ + CurPC = PCPBR; + // + if(!dis) + dis = new Dis65816(); + + dis->SetMXHint(PCPBR, (bool)(P & Core65816::M_FLAG), (bool)(P & Core65816::X_FLAG)); + // + for(auto& bp : BreakPointsPC) + { + if(PCPBR >= bp.A[0] && PCPBR <= bp.A[1]) + { + FoundBPoint = true; + break; + } + } + + //CPU[which].CheckRWBreakpoints(DBG_CheckReadBP, DBG_CheckWriteBP); + //CPU->CheckBreakpoints(CheckCPUBPCallB, CPU->PeekMem32(PC)); + + CPUHookContinuous |= FoundBPoint; + + if(CPUHookContinuous && CPUHook) + { + //ForceEventUpdates(timestamp); + CPUHook(PCPBR, FoundBPoint); + // + CurPC = CPU_GetRegister(Core65816::GSREG_PCPBR); + //P = CPU_GetRegister(Core65816::GSREG_P); + //dis->SetMXHint(CurPC, (bool)(P & Core65816::M_FLAG), (bool)(P & Core65816::X_FLAG)); + } + + FoundBPoint = false; +} + +static MDFN_COLD void Disassemble(uint32& A, uint32 SpecialA, char* TextBuf) +{ + if(!dis) + dis = new Dis65816(); + + const uint8 P = CPU_GetRegister(Core65816::GSREG_P); + + dis->Disassemble(A, SpecialA, TextBuf, (bool)(P & Core65816::M_FLAG), (bool)(P & Core65816::X_FLAG), HLCPUBusRead); +} + +static const RegType DBG_Regs_CPU[] = +{ + { (0 << 16) | Core65816::GSREG_PCPBR, "PC", "PC", 3 }, + { (0 << 16) | Core65816::GSREG_P, "P", "P", 1 }, + + { (0 << 16) | Core65816::GSREG_A, "A", "A", 2 }, + { (0 << 16) | Core65816::GSREG_X, "X", "X", 2 }, + { (0 << 16) | Core65816::GSREG_Y, "Y", "Y", 2 }, + + { (0 << 16) | Core65816::GSREG_S, "S", "S", 2 }, + { (0 << 16) | Core65816::GSREG_D, "D", "D", 2 }, + { (0 << 16) | Core65816::GSREG_DBR, "DBR", "DBR", 1 }, + // + { 0, "------", "", 0xFFFF }, + { (3 << 16) | SNES_GSREG_MEMSEL, "MemSel", "MemSel", 0x100 | 1 }, + { 0, "------", "", 0xFFFF }, + { (3 << 16) | SNES_GSREG_TS, "TS", "TS", 4 }, + // + // + // + { 0, "", "", 0 } +}; + +#define DMACH(ch) \ + { 0, "--CH" #ch ":--", "", 0xFFFF }, \ + { (2 << 16) | (ch << 8) | DMA_GSREG_CHN_CONTROL, "Control", "Control", 1 }, \ + { (2 << 16) | (ch << 8) | DMA_GSREG_CHN_BBUSADDR, "BBusAddr", "B-Bus Address", 1 }, \ + { (2 << 16) | (ch << 8) | DMA_GSREG_CHN_ABUSADDR, "ABusAddr", "A-Bus Address", 2 }, \ + { (2 << 16) | (ch << 8) | DMA_GSREG_CHN_ABUSBANK, "ABusBank", "A-Bus Bank", 1 }, \ + { (2 << 16) | (ch << 8) | DMA_GSREG_CHN_INDIRBANK, "IndirBank", "Indirect Bank", 1 }, \ + { (2 << 16) | (ch << 8) | DMA_GSREG_CHN_COUNT_INDIRADDR, "Count/IA", "Count/Indirect Address", 2 },\ + { (2 << 16) | (ch << 8) | DMA_GSREG_CHN_TABLEADDR, "TableAddr", "Table Address", 2 }, \ + { (2 << 16) | (ch << 8) | DMA_GSREG_CHN_LINECOUNTER, "LineCounter", "Line Counter", 1 }, \ + { (2 << 16) | (ch << 8) | DMA_GSREG_CHN_UNKNOWN, "Unknown", "Unknown", 1 }, \ + { (2 << 16) | (ch << 8) | DMA_GSREG_CHN_OFFSET, "Offset", "Offset", 1 }, \ + { (2 << 16) | (ch << 8) | DMA_GSREG_CHN_DOTRANSFER, "DoTransfer", "DoTransfer", 1 }, + +static const RegType DBG_Regs_DMA03[] = +{ + { (2 << 16) | DMA_GSREG_DMAENABLE, "DMAEnable", "DMA Enable", 1 }, + { (2 << 16) | DMA_GSREG_HDMAENABLE, "HDMAEnable", "HDMA Enable", 1 }, + { (2 << 16) | DMA_GSREG_HDMAENABLEM, "HDMAEnableM", "HDMA Enable Mask", 1 }, + + DMACH(0) + DMACH(1) + DMACH(2) + DMACH(3) + // + // + // + { 0, "", "", 0 } +}; + +static const RegType DBG_Regs_DMA47[] = +{ + DMACH(4) + DMACH(5) + DMACH(6) + DMACH(7) + // + // + // + { 0, "", "", 0 } +}; + +#undef DMACH + +static const RegType DBG_Regs_PPU[] = +{ + { (1 << 16) | PPU_GSREG_NMITIMEEN, "NMITIMEEN", "NMITIMEEN", 1 }, + { (1 << 16) | PPU_GSREG_HTIME, "HTIME", "HTIME", 0x100 | 9 }, + { (1 << 16) | PPU_GSREG_VTIME, "VTIME", "VTIME", 0x100 | 9 }, + { (1 << 16) | PPU_GSREG_NMIFLAG, "NMIFlag", "NMIFlag", 1 }, + { (1 << 16) | PPU_GSREG_IRQFLAG, "IRQFlag", "IRQFlag", 1 }, + { (1 << 16) | PPU_GSREG_HVBJOY, "HVBJOY", "HVBJOY", 1 }, + + { (1 << 16) | PPU_GSREG_SCANLINE, "scanline", "scanline", 2 }, + + { 0, "------", "", 0xFFFF }, + { (1 << 16) | PPU_GSREG_BGMODE, "BGMode", "BGMode", 1 }, + { (1 << 16) | PPU_GSREG_SCREENMODE, "ScreenMode", "ScreenMode", 1 }, + { (1 << 16) | PPU_GSREG_MOSAIC, "Mosaic", "Mosaic Control", 1 }, + { 0, "------", "", 0xFFFF }, + { (1 << 16) | PPU_GSREG_W12SEL, "W12SEL", "W12SEL", 1 }, + { (1 << 16) | PPU_GSREG_W34SEL, "W34SEL", "W34SEL", 1 }, + { (1 << 16) | PPU_GSREG_WOBJSEL, "WOBJSEL", "WOBJSEL", 1 }, + { (1 << 16) | PPU_GSREG_WH0, "WH0", "WH0", 1 }, + { (1 << 16) | PPU_GSREG_WH1, "WH1", "WH1", 1 }, + { (1 << 16) | PPU_GSREG_WH2, "WH2", "WH2", 1 }, + { (1 << 16) | PPU_GSREG_WH3, "WH3", "WH3", 1 }, + { (1 << 16) | PPU_GSREG_WBGLOG, "WBGLOG", "WBGLOG", 1 }, + { (1 << 16) | PPU_GSREG_WOBJLOG, "WOBJLOG", "WOBJLOG", 1 }, + { (1 << 16) | PPU_GSREG_TM, "TM", "TM", 1 }, + { (1 << 16) | PPU_GSREG_TS, "TS", "TS", 1 }, + { (1 << 16) | PPU_GSREG_CGWSEL, "CGWSEL", "CGWSEL", 1 }, + { (1 << 16) | PPU_GSREG_CGADSUB, "CGADSUB", "CGADSUB", 1 }, + { 0, "------", "", 0xFFFF }, + { (1 << 16) | PPU_GSREG_BG1HOFS, "BG1HOFS", "BG1 H Scroll", 2 }, + { (1 << 16) | PPU_GSREG_BG1VOFS, "BG1VOFS", "BG1 V Scroll", 2 }, + { (1 << 16) | PPU_GSREG_BG2HOFS, "BG2HOFS", "BG2 H Scroll", 2 }, + { (1 << 16) | PPU_GSREG_BG2VOFS, "BG2VOFS", "BG2 V Scroll", 2 }, + { (1 << 16) | PPU_GSREG_BG3HOFS, "BG3HOFS", "BG3 H Scroll", 2 }, + { (1 << 16) | PPU_GSREG_BG3VOFS, "BG3VOFS", "BG3 V Scroll", 2 }, + { (1 << 16) | PPU_GSREG_BG4HOFS, "BG4HOFS", "BG4 H Scroll", 2 }, + { (1 << 16) | PPU_GSREG_BG4VOFS, "BG4VOFS", "BG4 V Scroll", 2 }, + { 0, "------", "", 0xFFFF }, + { (1 << 16) | PPU_GSREG_M7SEL, "M7SEL", "Mode 7 Settings", 1 }, + { (1 << 16) | PPU_GSREG_M7A, "M7A", "Mode 7 Matrix A", 2 }, + { (1 << 16) | PPU_GSREG_M7B, "M7B", "Mode 7 Matrix B", 2 }, + { (1 << 16) | PPU_GSREG_M7C, "M7C", "Mode 7 Matrix C", 2 }, + { (1 << 16) | PPU_GSREG_M7D, "M7D", "Mode 7 Matrix D", 2 }, + { (1 << 16) | PPU_GSREG_M7X, "M7X", "Mode 7 Center X", 0x100 | 13 }, + { (1 << 16) | PPU_GSREG_M7Y, "M7Y", "Mode 7 Center Y", 0x100 | 13 }, + { (1 << 16) | PPU_GSREG_M7HOFS, "M7HOFS", "Mode 7 H Scroll", 0x100 | 13 }, + { (1 << 16) | PPU_GSREG_M7VOFS, "M7VOFS", "Mode 7 V Scroll", 0x100 | 13 }, + + // + // + // + { 0, "", "", 0 } +}; + +static MDFN_COLD uint32 GetRegister(const unsigned int id, char* special, const uint32 special_len) +{ + switch(id >> 16) + { + case 0: return CPU_GetRegister((uint16)id, special, special_len); + case 1: return PPU_GetRegister((uint16)id, special, special_len); + case 2: return DMA_GetRegister((uint16)id, special, special_len); + case 3: return SNES_GetRegister((uint16)id, special, special_len); + } + + return 0xCAFEBABE; +} + +static MDFN_COLD void SetRegister(const unsigned int id, uint32 value) +{ + switch(id >> 16) + { + case 0: CPU_SetRegister((uint16)id, value); break; + case 1: PPU_SetRegister((uint16)id, value); break; + case 2: DMA_SetRegister((uint16)id, value); break; + case 3: SNES_SetRegister((uint16)id, value); break; + } +} + +static const RegGroupType DBG_RegGroup_CPU = +{ + NULL, + DBG_Regs_CPU, + GetRegister, + SetRegister +}; + +static const RegGroupType DBG_RegGroup_DMA03 = +{ + NULL, + DBG_Regs_DMA03, + GetRegister, + SetRegister +}; + +static const RegGroupType DBG_RegGroup_DMA47 = +{ + NULL, + DBG_Regs_DMA47, + GetRegister, + SetRegister +}; + +static const RegGroupType DBG_RegGroup_PPU = +{ + NULL, + DBG_Regs_PPU, + GetRegister, + SetRegister +}; + +void DBG_Init(void) +{ + ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "cpu24", "CPU (24-bit address)", 24); + ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "wram", "Work RAM", 17); + ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "vram", "PPU VRAM", 16); + ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "vram", "PPU CGRAM", 9); + ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "oam", "PPU OAM", 9); + ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "oamhi", "PPU OAM High", 5); + ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "apuram", "APU RAM", 16); + +/* + const size_t cart_ram_size = 32768; //CART_GetRAMSize(); + if(cart_ram_size) + ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "cartram", "Cart RAM", MDFN_log2(round_up_pow2(cart_ram_size))); +*/ + // + // + MDFNDBG_AddRegGroup(&DBG_RegGroup_CPU); + MDFNDBG_AddRegGroup(&DBG_RegGroup_DMA03); + MDFNDBG_AddRegGroup(&DBG_RegGroup_DMA47); + MDFNDBG_AddRegGroup(&DBG_RegGroup_PPU); + + DBG_InHLRead = false; +} + +void DBG_Kill(void) +{ + // TODO, call + if(dis) + { + delete dis; + dis = nullptr; + } +} + +DebuggerInfoStruct DBG_DBGInfo +{ + "cp437", + + 4, + 1, + + 24, + 24, + + 0x0000, + ~0U, + + MemPeek, + + Disassemble, + NULL, + + NULL, + NULL, + + FlushBreakPoints, + AddBreakPoint, + SetCPUCallback, + + EnableBranchTrace, + GetBranchTrace, + + NULL, + NULL, + + NULL, + NULL, +}; + + +} + +#endif diff --git a/mednafen/snes_faust/debug.h b/mednafen/snes_faust/debug.h new file mode 100644 index 0000000..a1df8d3 --- /dev/null +++ b/mednafen/snes_faust/debug.h @@ -0,0 +1,42 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* debug.h: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __MDFN_SNES_FAUST_DEBUG_H +#define __MDFN_SNES_FAUST_DEBUG_H + +namespace MDFN_IEN_SNES_FAUST +{ + +#ifdef SNES_DBG_ENABLE +void DBG_AddBranchTrace(uint32 to, unsigned iseq); +void DBG_Init(void); +extern DebuggerInfoStruct DBG_DBGInfo; + +extern bool DBG_InHLRead; +#else +static INLINE void DBG_AddBranchTrace(uint32 to, unsigned iseq) { } +static INLINE void DBG_Init(void) { } + +enum : bool { DBG_InHLRead = false }; +#endif +} + +#endif diff --git a/mednafen/snes_faust/dis65816.cpp b/mednafen/snes_faust/dis65816.cpp new file mode 100644 index 0000000..d8f2249 --- /dev/null +++ b/mednafen/snes_faust/dis65816.cpp @@ -0,0 +1,502 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* dis65816.cpp: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include "dis65816.h" + +#include + +namespace Mednafen +{ + +Dis65816::Dis65816() +{ + ResetMXHints(); +} + +Dis65816::~Dis65816() +{ + +} + +void Dis65816::ResetMXHints(void) +{ + memset(MXHints, 0xFF, sizeof(MXHints)); +} + +void Dis65816::SetMXHint(uint32 addr, int M, int X) +{ + const unsigned shift = (addr & 1) << 2; + uint8& r = MXHints[addr >> 1]; + + r = (r & (0xF0 >> shift)) | (((M & 3) | ((X & 3) << 2)) << shift); +} + +INLINE bool Dis65816::IsMXHintSet(uint32 addr) +{ + const unsigned shift = (addr & 1) << 2; + + if((MXHints[addr >> 1] >> (shift + 0)) & 0xA) + return false; + + return true; +} + +INLINE bool Dis65816::GetM(uint32 addr, bool CurM) +{ + const unsigned shift = (addr & 1) << 2; + int ret = (MXHints[addr >> 1] >> (shift + 0)) & 0x3; + + if(ret & 2) + ret = CurM; + + return ret; +} + +INLINE bool Dis65816::GetX(uint32 addr, bool CurX) +{ + const unsigned shift = (addr & 1) << 2; + int ret = (MXHints[addr >> 1] >> (shift + 2)) & 0x3; + + if(ret & 2) + ret = CurX; + + return ret; +} + +const Dis65816::OpTableEntry Dis65816::OpTable[256] = +{ + /* 0x00 */ { "BRK", AM_IM_1 }, + /* 0x01 */ { "ORA", AM_IX }, + /* 0x02 */ { "COP", AM_IM_1 }, + /* 0x03 */ { "ORA", AM_SR }, + /* 0x04 */ { "TSB", AM_DP }, + /* 0x05 */ { "ORA", AM_DP }, + /* 0x06 */ { "ASL", AM_DP }, + /* 0x07 */ { "ORA", AM_INDL }, + /* 0x08 */ { "PHP", AM_IMP }, + /* 0x09 */ { "ORA", AM_IM_M }, + /* 0x0a */ { "ASL", AM_IMP }, + /* 0x0b */ { "PHD", AM_IMP }, + /* 0x0c */ { "TSB", AM_AB }, + /* 0x0d */ { "ORA", AM_AB }, + /* 0x0e */ { "ASL", AM_AB }, + /* 0x0f */ { "ORA", AM_ABL }, + /* 0x10 */ { "BPL", AM_R }, + /* 0x11 */ { "ORA", AM_IY }, + /* 0x12 */ { "ORA", AM_IND }, + /* 0x13 */ { "ORA", AM_SRIY }, + /* 0x14 */ { "TRB", AM_DP }, + /* 0x15 */ { "ORA", AM_DPX }, + /* 0x16 */ { "ASL", AM_DPX }, + /* 0x17 */ { "ORA", AM_ILY }, + /* 0x18 */ { "CLC", AM_IMP }, + /* 0x19 */ { "ORA", AM_ABY }, + /* 0x1a */ { "INC", AM_IMP }, + /* 0x1b */ { "TCS", AM_IMP }, + /* 0x1c */ { "TRB", AM_AB }, + /* 0x1d */ { "ORA", AM_ABX }, + /* 0x1e */ { "ASL", AM_ABX }, + /* 0x1f */ { "ORA", AM_ABLX }, + /* 0x20 */ { "JSR", AM_AB }, + /* 0x21 */ { "AND", AM_IX }, + /* 0x22 */ { "JSL", AM_ABL }, + /* 0x23 */ { "AND", AM_SR }, + /* 0x24 */ { "BIT", AM_DP }, + /* 0x25 */ { "AND", AM_DP }, + /* 0x26 */ { "ROL", AM_DP }, + /* 0x27 */ { "AND", AM_INDL }, + /* 0x28 */ { "PLP", AM_IMP }, + /* 0x29 */ { "AND", AM_IM_M }, + /* 0x2a */ { "ROL", AM_IMP }, + /* 0x2b */ { "PLD", AM_IMP }, + /* 0x2c */ { "BIT", AM_AB }, + /* 0x2d */ { "AND", AM_AB }, + /* 0x2e */ { "ROL", AM_AB }, + /* 0x2f */ { "AND", AM_ABL }, + /* 0x30 */ { "BMI", AM_R }, + /* 0x31 */ { "AND", AM_IY }, + /* 0x32 */ { "AND", AM_IND }, + /* 0x33 */ { "AND", AM_SRIY }, + /* 0x34 */ { "BIT", AM_DPX }, + /* 0x35 */ { "AND", AM_DPX }, + /* 0x36 */ { "ROL", AM_DPX }, + /* 0x37 */ { "AND", AM_ILY }, + /* 0x38 */ { "SEC", AM_IMP }, + /* 0x39 */ { "AND", AM_ABY }, + /* 0x3a */ { "DEC", AM_IMP }, + /* 0x3b */ { "TSC", AM_IMP }, + /* 0x3c */ { "BIT", AM_ABX }, + /* 0x3d */ { "AND", AM_ABX }, + /* 0x3e */ { "ROL", AM_ABX }, + /* 0x3f */ { "AND", AM_ABLX }, + /* 0x40 */ { "RTI", AM_IMP }, + /* 0x41 */ { "EOR", AM_IX }, + /* 0x42 */ { "WDM", AM_IM_1 }, + /* 0x43 */ { "EOR", AM_SR }, + /* 0x44 */ { "MVP", AM_BLOCK }, + /* 0x45 */ { "EOR", AM_DP }, + /* 0x46 */ { "LSR", AM_DP }, + /* 0x47 */ { "EOR", AM_INDL }, + /* 0x48 */ { "PHA", AM_IMP }, + /* 0x49 */ { "EOR", AM_IM_M }, + /* 0x4a */ { "LSR", AM_IMP }, + /* 0x4b */ { "PHK", AM_IMP }, + /* 0x4c */ { "JMP", AM_AB }, + /* 0x4d */ { "EOR", AM_AB }, + /* 0x4e */ { "LSR", AM_AB }, + /* 0x4f */ { "EOR", AM_ABL }, + /* 0x50 */ { "BVC", AM_R }, + /* 0x51 */ { "EOR", AM_IY }, + /* 0x52 */ { "EOR", AM_IND }, + /* 0x53 */ { "EOR", AM_SRIY }, + /* 0x54 */ { "MVN", AM_BLOCK }, + /* 0x55 */ { "EOR", AM_DPX }, + /* 0x56 */ { "LSR", AM_DPX }, + /* 0x57 */ { "EOR", AM_ILY }, + /* 0x58 */ { "CLI", AM_IMP }, + /* 0x59 */ { "EOR", AM_ABY }, + /* 0x5a */ { "PHY", AM_IMP }, + /* 0x5b */ { "TCD", AM_IMP }, + /* 0x5c */ { "JMP", AM_ABL }, + /* 0x5d */ { "EOR", AM_ABX }, + /* 0x5e */ { "LSR", AM_ABX }, + /* 0x5f */ { "EOR", AM_ABLX }, + /* 0x60 */ { "RTS", AM_IMP }, + /* 0x61 */ { "ADC", AM_IX }, + /* 0x62 */ { "PER", AM_RL }, + /* 0x63 */ { "ADC", AM_SR }, + /* 0x64 */ { "STZ", AM_DP }, + /* 0x65 */ { "ADC", AM_DP }, + /* 0x66 */ { "ROR", AM_DP }, + /* 0x67 */ { "ADC", AM_INDL }, + /* 0x68 */ { "PLA", AM_IMP }, + /* 0x69 */ { "ADC", AM_IM_M }, + /* 0x6a */ { "ROR", AM_IMP }, + /* 0x6b */ { "RTL", AM_IMP }, + /* 0x6c */ { "JMP", AM_ABIND }, + /* 0x6d */ { "ADC", AM_AB }, + /* 0x6e */ { "ROR", AM_AB }, + /* 0x6f */ { "ADC", AM_ABL }, + /* 0x70 */ { "BVS", AM_R }, + /* 0x71 */ { "ADC", AM_IY }, + /* 0x72 */ { "ADC", AM_IND }, + /* 0x73 */ { "ADC", AM_SRIY }, + /* 0x74 */ { "STZ", AM_DPX }, + /* 0x75 */ { "ADC", AM_DPX }, + /* 0x76 */ { "ROR", AM_DPX }, + /* 0x77 */ { "ADC", AM_ILY }, + /* 0x78 */ { "SEI", AM_IMP }, + /* 0x79 */ { "ADC", AM_ABY }, + /* 0x7a */ { "PLY", AM_IMP }, + /* 0x7b */ { "TDC", AM_IMP }, + /* 0x7c */ { "JMP", AM_ABIX }, + /* 0x7d */ { "ADC", AM_ABX }, + /* 0x7e */ { "ROR", AM_ABX }, + /* 0x7f */ { "ADC", AM_ABLX }, + /* 0x80 */ { "BRA", AM_R }, + /* 0x81 */ { "STA", AM_IX }, + /* 0x82 */ { "BRL", AM_RL }, + /* 0x83 */ { "STA", AM_SR }, + /* 0x84 */ { "STY", AM_DP }, + /* 0x85 */ { "STA", AM_DP }, + /* 0x86 */ { "STX", AM_DP }, + /* 0x87 */ { "STA", AM_INDL }, + /* 0x88 */ { "DEY", AM_IMP }, + /* 0x89 */ { "BIT", AM_IM_M }, + /* 0x8a */ { "TXA", AM_IMP }, + /* 0x8b */ { "PHB", AM_IMP }, + /* 0x8c */ { "STY", AM_AB }, + /* 0x8d */ { "STA", AM_AB }, + /* 0x8e */ { "STX", AM_AB }, + /* 0x8f */ { "STA", AM_ABL }, + /* 0x90 */ { "BCC", AM_R }, + /* 0x91 */ { "STA", AM_IY }, + /* 0x92 */ { "STA", AM_IND }, + /* 0x93 */ { "STA", AM_SRIY }, + /* 0x94 */ { "STY", AM_DPX }, + /* 0x95 */ { "STA", AM_DPX }, + /* 0x96 */ { "STX", AM_DPY }, + /* 0x97 */ { "STA", AM_ILY }, + /* 0x98 */ { "TYA", AM_IMP }, + /* 0x99 */ { "STA", AM_ABY }, + /* 0x9a */ { "TXS", AM_IMP }, + /* 0x9b */ { "TXY", AM_IMP }, + /* 0x9c */ { "STZ", AM_AB }, + /* 0x9d */ { "STA", AM_ABX }, + /* 0x9e */ { "STZ", AM_ABX }, + /* 0x9f */ { "STA", AM_ABLX }, + /* 0xa0 */ { "LDY", AM_IM_X }, + /* 0xa1 */ { "LDA", AM_IX }, + /* 0xa2 */ { "LDX", AM_IM_X }, + /* 0xa3 */ { "LDA", AM_SR }, + /* 0xa4 */ { "LDY", AM_DP }, + /* 0xa5 */ { "LDA", AM_DP }, + /* 0xa6 */ { "LDX", AM_DP }, + /* 0xa7 */ { "LDA", AM_INDL }, + /* 0xa8 */ { "TAY", AM_IMP }, + /* 0xa9 */ { "LDA", AM_IM_M }, + /* 0xaa */ { "TAX", AM_IMP }, + /* 0xab */ { "PLB", AM_IMP }, + /* 0xac */ { "LDY", AM_AB }, + /* 0xad */ { "LDA", AM_AB }, + /* 0xae */ { "LDX", AM_AB }, + /* 0xaf */ { "LDA", AM_ABL }, + /* 0xb0 */ { "BCS", AM_R }, + /* 0xb1 */ { "LDA", AM_IY }, + /* 0xb2 */ { "LDA", AM_IND }, + /* 0xb3 */ { "LDA", AM_SRIY }, + /* 0xb4 */ { "LDY", AM_DPX }, + /* 0xb5 */ { "LDA", AM_DPX }, + /* 0xb6 */ { "LDX", AM_DPY }, + /* 0xb7 */ { "LDA", AM_ILY }, + /* 0xb8 */ { "CLV", AM_IMP }, + /* 0xb9 */ { "LDA", AM_ABY }, + /* 0xba */ { "TSX", AM_IMP }, + /* 0xbb */ { "TYX", AM_IMP }, + /* 0xbc */ { "LDY", AM_ABX }, + /* 0xbd */ { "LDA", AM_ABX }, + /* 0xbe */ { "LDX", AM_ABY }, + /* 0xbf */ { "LDA", AM_ABLX }, + /* 0xc0 */ { "CPY", AM_IM_X }, + /* 0xc1 */ { "CMP", AM_IX }, + /* 0xc2 */ { "REP", AM_IM_1 }, + /* 0xc3 */ { "CMP", AM_SR }, + /* 0xc4 */ { "CPY", AM_DP }, + /* 0xc5 */ { "CMP", AM_DP }, + /* 0xc6 */ { "DEC", AM_DP }, + /* 0xc7 */ { "CMP", AM_INDL }, + /* 0xc8 */ { "INY", AM_IMP }, + /* 0xc9 */ { "CMP", AM_IM_M }, + /* 0xca */ { "DEX", AM_IMP }, + /* 0xcb */ { "WAI", AM_IMP }, + /* 0xcc */ { "CPY", AM_AB }, + /* 0xcd */ { "CMP", AM_AB }, + /* 0xce */ { "DEC", AM_AB }, + /* 0xcf */ { "CMP", AM_ABL }, + /* 0xd0 */ { "BNE", AM_R }, + /* 0xd1 */ { "CMP", AM_IY }, + /* 0xd2 */ { "CMP", AM_IND }, + /* 0xd3 */ { "CMP", AM_SRIY }, + /* 0xd4 */ { "PEI", AM_DP }, + /* 0xd5 */ { "CMP", AM_DPX }, + /* 0xd6 */ { "DEC", AM_DPX }, + /* 0xd7 */ { "CMP", AM_ILY }, + /* 0xd8 */ { "CLD", AM_IMP }, + /* 0xd9 */ { "CMP", AM_ABY }, + /* 0xda */ { "PHX", AM_IMP }, + /* 0xdb */ { "STP", AM_IMP }, + /* 0xdc */ { "JML", AM_ABIND }, + /* 0xdd */ { "CMP", AM_ABX }, + /* 0xde */ { "DEC", AM_ABX }, + /* 0xdf */ { "CMP", AM_ABLX }, + /* 0xe0 */ { "CPX", AM_IM_X }, + /* 0xe1 */ { "SBC", AM_IX }, + /* 0xe2 */ { "SEP", AM_IM_1 }, + /* 0xe3 */ { "SBC", AM_SR }, + /* 0xe4 */ { "CPX", AM_DP }, + /* 0xe5 */ { "SBC", AM_DP }, + /* 0xe6 */ { "INC", AM_DP }, + /* 0xe7 */ { "SBC", AM_INDL }, + /* 0xe8 */ { "INX", AM_IMP }, + /* 0xe9 */ { "SBC", AM_IM_M }, + /* 0xea */ { "NOP", AM_IMP }, + /* 0xeb */ { "XBA", AM_IMP }, + /* 0xec */ { "CPX", AM_AB }, + /* 0xed */ { "SBC", AM_AB }, + /* 0xee */ { "INC", AM_AB }, + /* 0xef */ { "SBC", AM_ABL }, + /* 0xf0 */ { "BEQ", AM_R }, + /* 0xf1 */ { "SBC", AM_IY }, + /* 0xf2 */ { "SBC", AM_IND }, + /* 0xf3 */ { "SBC", AM_SRIY }, + /* 0xf4 */ { "PEA", AM_AB }, + /* 0xf5 */ { "SBC", AM_DPX }, + /* 0xf6 */ { "INC", AM_DPX }, + /* 0xf7 */ { "SBC", AM_ILY }, + /* 0xf8 */ { "SED", AM_IMP }, + /* 0xf9 */ { "SBC", AM_ABY }, + /* 0xfa */ { "PLX", AM_IMP }, + /* 0xfb */ { "XCE", AM_IMP }, + /* 0xfc */ { "JSR", AM_ABIX }, + /* 0xfd */ { "SBC", AM_ABX }, + /* 0xfe */ { "INC", AM_ABX }, + /* 0xff */ { "SBC", AM_ABLX } +}; + +void Dis65816::Disassemble(uint32& A, uint32 SpecialA, char* buf, bool CurM, bool CurX, uint8 (*Read)(uint32 addr)) +{ + //const uint32 InitialA = A; // SpecialA blah blah blah + const bool M = GetM(A, CurM); + const bool X = GetX(A, CurX); + uint8 opbuf[4]; + size_t opbuf_count = 0; + const OpTableEntry* ote; + const bool imxhsa = IsMXHintSet(A); + + for(size_t i = 0; i < 4; i++) + opbuf[i] = Read((A + i) & 0xFFFFFF); + + opbuf_count = 1; + ote = &OpTable[opbuf[0]]; + + switch(ote->address_mode) + { + case AM_IMP: + strcpy(buf, ote->mnemonic); + break; + + case AM_IM_1: + case AM_IM_M: + case AM_IM_X: + { + size_t bs = 0; + switch(ote->address_mode) + { + case AM_IM_1: bs = 1; break; + case AM_IM_M: bs = 2 - M; break; + case AM_IM_X: bs = 2 - X; break; + } + opbuf_count += bs; + trio_snprintf(buf, 256, "%s #$%0*X", ote->mnemonic, (int)(bs * 2), (opbuf[1] | (((bs == 1) ? 0 : opbuf[2]) << 8))); + } + break; + + case AM_AB: + opbuf_count += 2; + trio_snprintf(buf, 256, "%s $%04X", ote->mnemonic, MDFN_de16lsb(&opbuf[1])); + break; + + case AM_ABL: + opbuf_count += 3; + trio_snprintf(buf, 256, "%s $%06X", ote->mnemonic, MDFN_de24lsb(&opbuf[1])); + break; + + case AM_ABLX: + opbuf_count += 3; + trio_snprintf(buf, 256, "%s $%06X, X", ote->mnemonic, MDFN_de24lsb(&opbuf[1])); + break; + + case AM_ABX: + case AM_ABY: + opbuf_count += 2; + trio_snprintf(buf, 256, "%s $%04X, %c", ote->mnemonic, MDFN_de16lsb(&opbuf[1]), ((ote->address_mode == AM_ABY) ? 'Y' : 'X')); + break; + + case AM_DP: // d + opbuf_count += 1; + trio_snprintf(buf, 256, "%s $%02X", ote->mnemonic, opbuf[1]); + break; + + case AM_DPX: // d, X + case AM_DPY: // d, Y + opbuf_count += 1; + trio_snprintf(buf, 256, "%s $%02X, %c", ote->mnemonic, opbuf[1], ((ote->address_mode == AM_DPY) ? 'Y' : 'X')); + break; + + case AM_IND: // (d) + opbuf_count += 1; + trio_snprintf(buf, 256, "%s ($%02X)", ote->mnemonic, opbuf[1]); + break; + + case AM_INDL: // [d] + opbuf_count += 1; + trio_snprintf(buf, 256, "%s [$%02X]", ote->mnemonic, opbuf[1]); + break; + + case AM_IX: // (d, X) + opbuf_count += 1; + trio_snprintf(buf, 256, "%s ($%02X, X)", ote->mnemonic, opbuf[1]); + break; + + case AM_IY: // (d), Y + opbuf_count += 1; + trio_snprintf(buf, 256, "%s ($%02X), Y", ote->mnemonic, opbuf[1]); + break; + + case AM_ILY: // [d], Y + opbuf_count += 1; + trio_snprintf(buf, 256, "%s [$%02X], Y", ote->mnemonic, opbuf[1]); + break; + + case AM_SR: + opbuf_count += 1; + trio_snprintf(buf, 256, "%s $%02X, S", ote->mnemonic, opbuf[1]); + break; + + case AM_SRIY: + opbuf_count += 1; + trio_snprintf(buf, 256, "%s ($%02X, S), Y", ote->mnemonic, opbuf[1]); + break; + + case AM_BLOCK: + opbuf_count += 2; + trio_snprintf(buf, 256, "%s $%02X, $%02X", ote->mnemonic, opbuf[1], opbuf[2]); + break; + + case AM_ABIND: + opbuf_count += 2; + trio_snprintf(buf, 256, "%s ($%04X)", ote->mnemonic, MDFN_de16lsb(&opbuf[1])); + break; + + case AM_ABIX: + opbuf_count += 2; + trio_snprintf(buf, 256, "%s ($%04X, X)", ote->mnemonic, MDFN_de16lsb(&opbuf[1])); + break; + // + // + // + case AM_R: + opbuf_count += 1; + trio_snprintf(buf, 256, "%s $%06X", ote->mnemonic, (A & 0xFF0000) | ((A + 2 + (int8)opbuf[1]) & 0xFFFF) ); + break; + + case AM_RL: + opbuf_count += 2; + trio_snprintf(buf, 256, "%s $%06X", ote->mnemonic, (A & 0xFF0000) | ((A + 2 + (int16)MDFN_de16lsb(&opbuf[1])) & 0xFFFF) ); + break; + } + + for(uint32 TestA = A + 1; TestA != ((A + opbuf_count) & 0xFFFFFF); TestA = (TestA + 1) & 0xFFFFFF) + { + if((!imxhsa && IsMXHintSet(TestA)) || TestA == SpecialA) + { + trio_snprintf(buf, 256, ".db $%02X", opbuf[0]); + A++; + return; + } + } + + { + const size_t tp = 16; + const char* qstring = imxhsa ? "" : "?"; + for(size_t i = strlen(buf); i < tp; i++) + { + buf[i] = ' '; + } + trio_snprintf(buf + tp, 256 - tp, "; .M=%s%d%s, .X=%s%d%s", qstring, M, qstring, qstring, X, qstring); + } + // + // + A = (A + opbuf_count) & 0xFFFFFF; +} + +} diff --git a/mednafen/snes_faust/dis65816.h b/mednafen/snes_faust/dis65816.h new file mode 100644 index 0000000..6c43d91 --- /dev/null +++ b/mednafen/snes_faust/dis65816.h @@ -0,0 +1,83 @@ +/******************************************************************************/ +/* Mednafen Fast SNES Emulation Module */ +/******************************************************************************/ +/* dis65816.h: +** Copyright (C) 2019 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +namespace Mednafen +{ + class Dis65816 + { + public: + Dis65816(); + ~Dis65816(); + + void Disassemble(uint32& A, uint32 SpecialA, char* buf, bool CurM, bool CurX, uint8 (*Read)(uint32 addr)); + + void ResetMXHints(void); + void SetMXHint(uint32 addr, int M, int X); + + private: + + bool IsMXHintSet(uint32 addr); + bool GetM(uint32 addr, bool CurM); + bool GetX(uint32 addr, bool CurX); + + uint8 MXHints[(1U << 24) / 2]; + + enum + { + AM_IMP, + + AM_IM_1, + AM_IM_M, + AM_IM_X, + + AM_AB, + AM_ABL, + AM_ABLX, + AM_ABX, + AM_ABY, + AM_DP, + AM_DPX, + AM_DPY, + AM_IND, + AM_INDL, + AM_IX, + AM_IY, + AM_ILY, + AM_SR, + AM_SRIY, + + AM_R, + AM_RL, + + AM_BLOCK, + AM_ABIND, + AM_ABIX, + }; + + struct OpTableEntry + { + const char* mnemonic; + uint8 address_mode; + }; + + static const OpTableEntry OpTable[256]; + }; +} diff --git a/mednafen/snes_faust/dma.inc b/mednafen/snes_faust/dma.inc index 2cf37b0..7a3a2fa 100644 --- a/mednafen/snes_faust/dma.inc +++ b/mednafen/snes_faust/dma.inc @@ -2,7 +2,7 @@ /* Mednafen Fast SNES Emulation Module */ /******************************************************************************/ /* dma.inc: -** Copyright (C) 2015-2016 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -20,7 +20,6 @@ */ // FIXME: Be careful to reset DMACH[ch].Offset to 0 at appropriate times(like what if HDMA cancels DMA..) - static uint8 DMAEnable; static uint8 HDMAEnable; static uint8 HDMAEnableMask; @@ -69,6 +68,16 @@ TModes[8] = { 3, { 0, 0, 1, 1 } }, }; +#if 1 +extern uint32 scanline; +#endif + +static void DMA_UnhaltCPU(void) +{ + CPUM.halted &= ~CPU_Misc::HALTED_DMA; + CPU_TriggerIRQNMIDelayKludge(); +} + // TODO: Warning message when DMA overwrites DMA registers. void CPU_Misc::RunDMA(void) { @@ -117,7 +126,10 @@ void CPU_Misc::RunDMA(void) } if(DMAEnable == 0) - CPUM.halted = HALTED_NOT; + { + SNES_DBG("DMA done: %u, scanline=%u\n", CPUM.timestamp, scanline); + DMA_UnhaltCPU(); + } } static uint32 DMA_Update(uint32 timestamp) @@ -125,7 +137,7 @@ static uint32 DMA_Update(uint32 timestamp) if(DMAEnable != 0) { //puts("WOOTS"); - CPUM.halted = CPU_Misc::HALTED_DMA; + CPUM.halted |= CPU_Misc::HALTED_DMA; } return SNES_EVENT_MAXTS; @@ -135,8 +147,8 @@ void DMA_InitHDMA(void) { DMAEnable &= ~HDMAEnable; - if(CPUM.halted == CPU_Misc::HALTED_DMA && DMAEnable == 0) - CPUM.halted = CPU_Misc::HALTED_NOT; + if((CPUM.halted & CPU_Misc::HALTED_DMA) && DMAEnable == 0) + DMA_UnhaltCPU(); // // HDMAEnableMask = 0xFF; @@ -167,11 +179,11 @@ void DMA_InitHDMA(void) DMACH[ch].DoTransfer = true; } - //printf("[DMA] HDMA %u Init: Control=0x%02x, LineCounter=0x%02x, TableAddr=0x%04x, IndirAddr=0x%04x --- ABank=0x%02x, IndirBank=0x%02x\n", ch, DMACH[ch].Control, DMACH[ch].LineCounter, DMACH[ch].TableAddr, DMACH[ch].IndirAddr, DMACH[ch].ABusBank, DMACH[ch].IndirBank); + SNES_DBG("[DMA] HDMA %u Init: Control=0x%02x, LineCounter=0x%02x, TableAddr=0x%04x, IndirAddr=0x%04x --- ABank=0x%02x, IndirBank=0x%02x\n", ch, DMACH[ch].Control, DMACH[ch].LineCounter, DMACH[ch].TableAddr, DMACH[ch].IndirAddr, DMACH[ch].ABusBank, DMACH[ch].IndirBank); } } } -extern uint32 scanline; + void DMA_RunHDMA(void) { for(unsigned ch = 0; ch < 8; ch++) @@ -216,17 +228,24 @@ void DMA_RunHDMA(void) } DMACH[ch].Offset = 0; } - // - // - // + } + } + for(unsigned ch = 0; ch < 8; ch++) + { + if(HDMAEnable & HDMAEnableMask & (1U << ch)) + { DMACH[ch].LineCounter--; DMACH[ch].DoTransfer = DMACH[ch].LineCounter & 0x80; if(!(DMACH[ch].LineCounter & 0x7F)) { - DMACH[ch].LineCounter = CPUM.ReadA((DMACH[ch].ABusBank << 16) + DMACH[ch].TableAddr); - DMACH[ch].TableAddr++; + { + const uint32 save_timestamp = CPUM.timestamp; + DMACH[ch].LineCounter = CPUM.ReadA((DMACH[ch].ABusBank << 16) + DMACH[ch].TableAddr); + DMACH[ch].TableAddr++; + CPUM.timestamp = save_timestamp + MEMCYC_SLOW; + } //fprintf(stderr, "HDMA %u NewLineCounter=0x%02x --- scanline=%u\n", ch, DMACH[ch].LineCounter, scanline); @@ -253,14 +272,15 @@ void DMA_RunHDMA(void) DMACH[ch].DoTransfer = true; } // end if(!(DMACH[ch].LineCounter & 0x7F)) - + else + CPUM.timestamp += MEMCYC_SLOW; } } // // - if(CPUM.halted == CPU_Misc::HALTED_DMA && DMAEnable == 0) - CPUM.halted = CPU_Misc::HALTED_NOT; + if((CPUM.halted & CPU_Misc::HALTED_DMA) && DMAEnable == 0) + CPUM.halted &= ~CPU_Misc::HALTED_DMA; } @@ -268,9 +288,9 @@ static DEFWRITE(Write_420B) { CPUM.timestamp += MEMCYC_FAST; -#if 0 +#ifdef SNES_DBG_ENABLE if(V) - fprintf(stderr, "DMA: %02x\n", V); + fprintf(stderr, "DMA: %02x --- %u, scanline=%u\n", V, CPUM.timestamp, scanline); for(unsigned i = 0; i < 8; i++) { if(V & (1 << i)) @@ -307,6 +327,11 @@ static DEFWRITE(Write_43x0) static DEFREAD(Read_43x0) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DMACH[(A >> 4) & 0x7].Control; + } + CPUM.timestamp += MEMCYC_FAST; return DMACH[(A >> 4) & 0x7].Control; @@ -325,6 +350,11 @@ static DEFWRITE(Write_43x1) static DEFREAD(Read_43x1) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DMACH[(A >> 4) & 0x7].BBusAddr; + } + CPUM.timestamp += MEMCYC_FAST; return DMACH[(A >> 4) & 0x7].BBusAddr; @@ -343,6 +373,11 @@ static DEFWRITE(Write_43x2) static DEFREAD(Read_43x2) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DMACH[(A >> 4) & 0x7].ABusAddr >> 0; + } + CPUM.timestamp += MEMCYC_FAST; return DMACH[(A >> 4) & 0x7].ABusAddr >> 0; @@ -361,6 +396,11 @@ static DEFWRITE(Write_43x3) static DEFREAD(Read_43x3) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DMACH[(A >> 4) & 0x7].ABusAddr >> 8; + } + CPUM.timestamp += MEMCYC_FAST; return DMACH[(A >> 4) & 0x7].ABusAddr >> 8; @@ -378,6 +418,11 @@ static DEFWRITE(Write_43x4) static DEFREAD(Read_43x4) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DMACH[(A >> 4) & 0x7].ABusBank; + } + CPUM.timestamp += MEMCYC_FAST; return DMACH[(A >> 4) & 0x7].ABusBank; @@ -396,6 +441,11 @@ static DEFWRITE(Write_43x5) static DEFREAD(Read_43x5) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DMACH[(A >> 4) & 0x7].IndirAddr >> 0; + } + CPUM.timestamp += MEMCYC_FAST; return DMACH[(A >> 4) & 0x7].IndirAddr >> 0; @@ -414,6 +464,11 @@ static DEFWRITE(Write_43x6) static DEFREAD(Read_43x6) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DMACH[(A >> 4) & 0x7].IndirAddr >> 8; + } + CPUM.timestamp += MEMCYC_FAST; return DMACH[(A >> 4) & 0x7].IndirAddr >> 8; @@ -431,6 +486,11 @@ static DEFWRITE(Write_43x7) static DEFREAD(Read_43x7) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DMACH[(A >> 4) & 0x7].IndirBank; + } + CPUM.timestamp += MEMCYC_FAST; return DMACH[(A >> 4) & 0x7].IndirBank; @@ -449,6 +509,11 @@ static DEFWRITE(Write_43x8) static DEFREAD(Read_43x8) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DMACH[(A >> 4) & 0x7].TableAddr >> 0; + } + CPUM.timestamp += MEMCYC_FAST; return DMACH[(A >> 4) & 0x7].TableAddr >> 0; @@ -467,6 +532,11 @@ static DEFWRITE(Write_43x9) static DEFREAD(Read_43x9) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DMACH[(A >> 4) & 0x7].TableAddr >> 8; + } + CPUM.timestamp += MEMCYC_FAST; return DMACH[(A >> 4) & 0x7].TableAddr >> 8; @@ -484,6 +554,11 @@ static DEFWRITE(Write_43xA) static DEFREAD(Read_43xA) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DMACH[(A >> 4) & 0x7].LineCounter; + } + CPUM.timestamp += MEMCYC_FAST; return DMACH[(A >> 4) & 0x7].LineCounter; @@ -499,6 +574,11 @@ static DEFWRITE(Write_43xB_43xF) static DEFREAD(Read_43xB_43xF) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DMACH[(A >> 4) & 0x7].Unknown; + } + CPUM.timestamp += MEMCYC_FAST; return DMACH[(A >> 4) & 0x7].Unknown; @@ -510,6 +590,7 @@ static void DMA_Reset(bool powering_up) { DMAEnable = 0; HDMAEnable = 0; + HDMAEnableMask = 0; for(unsigned ch = 0; ch < 8; ch++) { @@ -526,6 +607,7 @@ static void DMA_Reset(bool powering_up) DMACH[ch].Unknown = 0xFF; DMACH[ch].Offset = 0; + DMACH[ch].DoTransfer = false; } } } @@ -598,4 +680,82 @@ static void DMA_StateAction(StateMem* sm, const unsigned load, const bool data_o MDFNSS_StateAction(sm, load, data_only, StateRegs, "DMA"); } +// +// +// + +uint32 DMA_GetRegister(const unsigned id, char* const special, const uint32 special_len) +{ + const unsigned ch = (id >> 8) & 0x7; + uint32 ret = 0xDEADBEEF; + + switch(id & ~0x700) + { + case DMA_GSREG_DMAENABLE: + ret = DMAEnable; + break; + + case DMA_GSREG_HDMAENABLE: + ret = HDMAEnable; + break; + + case DMA_GSREG_HDMAENABLEM: + ret = HDMAEnableMask; + break; + + case DMA_GSREG_CHN_CONTROL: + ret = DMACH[ch].Control; + break; + + case DMA_GSREG_CHN_BBUSADDR: + ret = DMACH[ch].BBusAddr; + break; + + case DMA_GSREG_CHN_ABUSADDR: + ret = DMACH[ch].ABusAddr; + break; + + case DMA_GSREG_CHN_ABUSBANK: + ret = DMACH[ch].ABusBank; + break; + + case DMA_GSREG_CHN_INDIRBANK: + ret = DMACH[ch].IndirBank; + break; + + case DMA_GSREG_CHN_COUNT_INDIRADDR: + ret = DMACH[ch].IndirAddr; + break; + + case DMA_GSREG_CHN_TABLEADDR: + ret = DMACH[ch].TableAddr; + break; + + case DMA_GSREG_CHN_LINECOUNTER: + ret = DMACH[ch].LineCounter; + break; + + case DMA_GSREG_CHN_UNKNOWN: + ret = DMACH[ch].Unknown; + break; + + case DMA_GSREG_CHN_OFFSET: + ret = DMACH[ch].Offset; + break; + + case DMA_GSREG_CHN_DOTRANSFER: + ret = DMACH[ch].DoTransfer; + break; + } + + return ret; +} + +void DMA_SetRegister(const unsigned id, const uint32 value) +{ + switch(id) + { + // TODO + } +} diff --git a/mednafen/snes_faust/dsp.inc b/mednafen/snes_faust/dsp.inc index 6251f0b..41dcf5b 100644 --- a/mednafen/snes_faust/dsp.inc +++ b/mednafen/snes_faust/dsp.inc @@ -2,7 +2,7 @@ /* Mednafen Fast SNES Emulation Module */ /******************************************************************************/ /* dsp.inc: -** Copyright (C) 2015-2016 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -63,7 +63,6 @@ static INLINE int16 ClampS16(int32 v) return v; } -static int16 ResampHalfImp[512]; static const int16 ResampHalfImp_Init[512] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -144,8 +143,6 @@ enum GRA_FIR7 = 0x7F, }; -static uint8 Regs[0x80]; - struct DSP_HGS { bool KPollCycle; @@ -213,16 +210,16 @@ struct DSP_Voice uint8 RB_Pos; uint8 RB_In; - uint8 Latch_SRCN; uint16 Addr; + uint8 Latch_SRCN; bool StartReload; bool LoopReload; uint8 Latch_ADSR1; uint8 ADSRPhase; - uint16 ADSRLevel; bool ADSRBentFastNext; + uint16 ADSRLevel; uint8 Pending_ENVX; uint8 Pending_OUTX; @@ -233,10 +230,47 @@ struct DSP_Voice unsigned Phase; }; -static DSP_HGS HGS; -static DSP_Voice Voices[8]; +static struct +{ + DSP_Voice Voices[8]; + DSP_HGS HGS; + + int8 weights[4][2]; + uint16 RateMasks[32]; + uint16 RateCompares[32]; + + uint8 Regs[0x80]; + + int16 ResampHalfImp[512]; + // + // + // + int16 OutputL; // To avoid distortion, since L and R aren't updated at the same time(and the emulation frame can end between them). + unsigned OutputBufPos; + OwlResampler* Resampler; + double ResampLastRate; + OwlBuffer ResampBuf[2]; +} DSP; + +#define GLBVAR(x) static auto& x = DSP.x; + GLBVAR(Voices) + GLBVAR(HGS) + GLBVAR(weights) + GLBVAR(RateMasks) + GLBVAR(RateCompares) + GLBVAR(Regs) + GLBVAR(ResampHalfImp) + GLBVAR(OutputL) + GLBVAR(OutputBufPos) + GLBVAR(Resampler) + GLBVAR(ResampLastRate) + GLBVAR(ResampBuf) +#undef GLBVAR + +//static uint16 sawthing; + +//static int KONCounter[8] = { 9, 9, 9, 9, 9, 9, 9, 9 }; -static int8 weights[4][2]; static const int8 weights_init[4][2] = { // i-2, i-1 @@ -246,7 +280,6 @@ static const int8 weights_init[4][2] = { -52, 115 }, }; -static uint16 RateMasks[32]; static const uint16 RateMasks_Init[32] = { 0x0000, 0xFFE0, 0x3FF8, @@ -263,7 +296,6 @@ static const uint16 RateMasks_Init[32] = 0x0000 }; -static uint16 RateCompares[32]; static const uint16 RateCompares_Init[32] = { 0xffff, 0x0000, 0x3e08, @@ -281,16 +313,6 @@ static const uint16 RateCompares_Init[32] = }; -static int16 OutputL; // To avoid distortion, since L and R aren't updated at the same time(and the emulation frame can end between them). -static unsigned OutputBufPos; -static OwlResampler* Resampler; -static double ResampLastRate; -static OwlBuffer ResampBuf[2]; - -//static uint16 sawthing; - -//static int KONCounter[8] = { 9, 9, 9, 9, 9, 9, 9, 9 }; - static INLINE bool CheckRC(unsigned rate) { return (HGS.RateCounter & RateMasks[rate]) == RateCompares[rate]; @@ -1037,6 +1059,7 @@ static MDFN_COLD void DSP_Reset(bool powering_up) Regs[GRA_FLG] = 0xE0; HGS.EchoWriteDisable = true; + OutputL = 0; OutputBufPos = 0; HGS.NoiseVal = 0x4000; diff --git a/mednafen/snes_faust/input.cpp b/mednafen/snes_faust/input.cpp index bae1000..a565d9e 100644 --- a/mednafen/snes_faust/input.cpp +++ b/mednafen/snes_faust/input.cpp @@ -2,7 +2,7 @@ /* Mednafen Fast SNES Emulation Module */ /******************************************************************************/ /* input.cpp: -** Copyright (C) 2015-2017 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -294,6 +294,11 @@ static uint8 JoyARData[8]; static DEFREAD(Read_JoyARData) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return JoyARData[A & 0x7]; + } + CPUM.timestamp += MEMCYC_FAST; //printf("Read: %08x\n", A); @@ -303,6 +308,11 @@ static DEFREAD(Read_JoyARData) static DEFREAD(Read_4016) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return CPUM.mdr & 0xFC; // | TODO! + } + CPUM.timestamp += MEMCYC_XSLOW; uint8 ret = CPUM.mdr & 0xFC; @@ -326,6 +336,11 @@ static DEFWRITE(Write_4016) static DEFREAD(Read_4017) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return (CPUM.mdr & 0xE0) | 0x1C; // | TODO! + } + CPUM.timestamp += MEMCYC_XSLOW; uint8 ret = (CPUM.mdr & 0xE0) | 0x1C; @@ -344,6 +359,11 @@ static DEFWRITE(Write_WRIO) static DEFREAD(Read_4213) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return WRIO; + } + CPUM.timestamp += MEMCYC_FAST; return WRIO; @@ -447,6 +467,8 @@ void INPUT_Reset(bool powering_up) for(unsigned sport = 0; sport < 2; sport++) Ports[sport]->SetLatch(JoyLS); + memset(JoyARData, 0x00, sizeof(JoyARData)); + if(powering_up) { WRIO = 0xFF; diff --git a/mednafen/snes_faust/notes/GAME_NOTES b/mednafen/snes_faust/notes/GAME_NOTES new file mode 100644 index 0000000..0a6493c --- /dev/null +++ b/mednafen/snes_faust/notes/GAME_NOTES @@ -0,0 +1,118 @@ +Animaniacs - HTIME!=0, race between CPU and HDMA +Battle Blaze - Title screen really timing sensitive... +Demon's Crest - HTIME!=0, lots of different HTIME values used on mode 7 overhead world map +F-1 Grand Prix - HV IRQ shenanigans +F1 ROC - HTIME!=0, ? +Jungle Strike - WAI; HV IRQ shenanigans +Mortal Kombat II - WAI; HV IRQ shenanigans? +Secret of Mana - HTIME!=0, CPU/HDMA race on mode 7 overworld view? +Super Off Road: The Baja - WAI; HV IRQ shenanigans, race between CPU M7HOFS writes and HDMA M7VOFS writes +// +// +// +Mighty Morphin Power Rangers: The Fighting Edition +Wild Guns - 89AB DMA/NMI race condition +// +// +// +F-Zero - HTIME != 0 +Ganbare Goemon II - HTIME != 0 +Hyper Zone - HTIME != 0 +Mega Man X - HTIME != 0 +Street Fighter II Turbo - HTIME != 0 +Super Metroid - HTIME != 0 + +// +// Attempts to write to VRAM with HDMA during active display: +// +Hook +Tecmo Super Bowl II + + +// +// Interlace: +// +Air Strike Patrol +Bishoujo Wrestler Retsuden +GT Racing +Power Drive +RPM Racing +Syvalion +Yuu Yuu Hakusho Tokubetsu Hen + +// +// Fancy Mode 7 effects: +// +Air Cavalry (gameplay) +Albert Odyssey (overhead map) +Axelay (gameplay) +Battle Racers (somewhat sensitive to HDMA overhead, does mid-frame DMA to OAM) +Brett Hull Hockey 95 (gameplay) +Chrono Trigger (racing sequence in attract mode, and later in game) +Demon's Crest (overhead world map) +F-15 Super Strike Eagle (takeoff) +F-Zero (gameplay) +F1 Pole Position (gameplay; flickering line?) +F1 ROC (gameplay) +Final Fantasy 5 (Meteor crash) +Final Fantasy 6 (Overworld view) +GP-1 Part II +GT Racing (gameplay) +HyperZone (gameplay) +J.League Super Soccer (gameplay) +J.League Excite Stage 94, 95, 96 (gameplay; flickering line?) +Jumbo Ozaki +Kat's Run (gameplay) +!!! Mecarobot Golf (gameplay) +Mickey Mania (attract mode moose?) +Mohawk and Headphone Jack (title screen) +NCAA Basketball (gameplay) +NHL Stanley Cup (gameplay) +SD F-1 Grand Prix +!!! Secret of Mana (overhead world view after starting new game) +Seiken Densetsu III (overhead world view after starting new game) +Street Racer (title screen, gameplay) +Super Castlevania IV (block 4-3) +Super Formation Soccer, II, 94, 95, 96 (gameplay) +!!! Super Off Road: The Baja (gameplay) +Super Star Wars (attract mode, hoverthing sequence) +Super Turrican 2 (stage 2-2) +Tales of Phantasia +Tenchi Souzou (underworld sky) +Touge Densetsu (gameplay) +Wakuwaku Ski Wonder Spur (gameplay) + +// +// Line flickering: +// +Great Battle IV - PC=$8584CC 85851F 8584D1 $1BDC --- 8584F7 +Lemmings +Mouryou Senki Madara 2 + +// +// +// +Metal Marines - TXS in 65816 emulation mode + +// +// SA-1 DMA: +// +Marvelous + +// +// SA-1 char conv DMA: +// +Masters New - Harukanaru Augusta 3 +Pebble Beach no Hatou New +SD Gundam G Next +Super Mario RPG (level up screen) + +// +// SPC700 timing sensitive games +// +Illusion of Gaia +N-Warp Daisakusen? +Tales of Phantasia +Tenchi Souzo +Tenshi no Uta (presumably) +Terranigma diff --git a/mednafen/snes_faust/PPU_DESIGN b/mednafen/snes_faust/notes/PPU_DESIGN similarity index 100% rename from mednafen/snes_faust/PPU_DESIGN rename to mednafen/snes_faust/notes/PPU_DESIGN diff --git a/mednafen/snes_faust/notes/genops.cpp b/mednafen/snes_faust/notes/genops.cpp new file mode 100644 index 0000000..657ca1f --- /dev/null +++ b/mednafen/snes_faust/notes/genops.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include + +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; + +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; + +int main(int argc, char* argv[]) +{ + char buf[1024]; + unsigned opc = 0; + + while(fgets(buf, sizeof(buf), stdin)) + { + const size_t bsl = strlen(buf); + size_t s = 0; + + for(size_t i = 0; i < bsl; i++) + { + if(buf[i] == '*' || buf[i] == '\n') + { + static const struct + { + const char* a; + const char* b; + } ttab[] = + { + { "i", "AM_IMP" }, + { "A", "AM_IMP" }, + { "s", "AM_IMP" }, + { "#1", "AM_IM_1" }, + { "#m", "AM_IM_M" }, + { "#x", "AM_IM_X" }, + { "a", "AM_AB" }, + { "al", "AM_ABL" }, + { "al,x", "AM_ABLX" }, + { "a,x", "AM_ABX" }, + { "a,y", "AM_ABY" }, + { "d", "AM_DP" }, + { "d,x", "AM_DPX" }, + { "d,y", "AM_DPY" }, + { "(d)", "AM_IND" }, + { "[d]", "AM_INDL" }, + { "(d,x)", "AM_IX" }, + { "(d),y", "AM_IY" }, + { "[d],y", "AM_ILY" }, + { "r,s", "AM_SR" }, + { "(r,s),y", "AM_SRIY" }, + { "r", "AM_R" }, + { "rl", "AM_RL" }, + { "xya", "AM_BLOCK" }, + { "(a)", "AM_ABIND" }, + { "(a,x)", "AM_ABIX" }, + }; + char mnemonic[256]; + char address_mode[256]; + const char* new_am = address_mode; + + buf[i] = 0; + + if(sscanf(buf + s, "%255s %255s", mnemonic, address_mode) != 2) + abort(); + + for(size_t ti = 0; ti < sizeof(ttab) / sizeof(ttab[0]); ti++) + { + if(!strcmp(address_mode, ttab[ti].a)) + { + new_am = ttab[ti].b; + break; + } + } + + printf(" /* 0x%02x */ { \"%s\", %s },\n", opc, mnemonic, new_am); + + s = i + 1; + opc++; + } + } + } +} diff --git a/mednafen/snes_faust/notes/ops.h b/mednafen/snes_faust/notes/ops.h new file mode 100644 index 0000000..feff9d3 --- /dev/null +++ b/mednafen/snes_faust/notes/ops.h @@ -0,0 +1,256 @@ + /* 0x00 */ { "BRK", AM_IM_1 }, + /* 0x01 */ { "ORA", AM_IX }, + /* 0x02 */ { "COP", AM_IM_1 }, + /* 0x03 */ { "ORA", AM_SR }, + /* 0x04 */ { "TSB", AM_DP }, + /* 0x05 */ { "ORA", AM_DP }, + /* 0x06 */ { "ASL", AM_DP }, + /* 0x07 */ { "ORA", AM_INDL }, + /* 0x08 */ { "PHP", AM_IMP }, + /* 0x09 */ { "ORA", AM_IM_M }, + /* 0x0a */ { "ASL", AM_IMP }, + /* 0x0b */ { "PHD", AM_IMP }, + /* 0x0c */ { "TSB", AM_AB }, + /* 0x0d */ { "ORA", AM_AB }, + /* 0x0e */ { "ASL", AM_AB }, + /* 0x0f */ { "ORA", AM_ABL }, + /* 0x10 */ { "BPL", AM_R }, + /* 0x11 */ { "ORA", AM_IY }, + /* 0x12 */ { "ORA", AM_IND }, + /* 0x13 */ { "ORA", AM_SRIY }, + /* 0x14 */ { "TRB", AM_DP }, + /* 0x15 */ { "ORA", AM_DPX }, + /* 0x16 */ { "ASL", AM_DPX }, + /* 0x17 */ { "ORA", AM_ILY }, + /* 0x18 */ { "CLC", AM_IMP }, + /* 0x19 */ { "ORA", AM_ABY }, + /* 0x1a */ { "INC", AM_IMP }, + /* 0x1b */ { "TCS", AM_IMP }, + /* 0x1c */ { "TRB", AM_AB }, + /* 0x1d */ { "ORA", AM_ABX }, + /* 0x1e */ { "ASL", AM_ABX }, + /* 0x1f */ { "ORA", AM_ABLX }, + /* 0x20 */ { "JSR", AM_AB }, + /* 0x21 */ { "AND", AM_IX }, + /* 0x22 */ { "JSL", AM_ABL }, + /* 0x23 */ { "AND", AM_SR }, + /* 0x24 */ { "BIT", AM_DP }, + /* 0x25 */ { "AND", AM_DP }, + /* 0x26 */ { "ROL", AM_DP }, + /* 0x27 */ { "AND", AM_INDL }, + /* 0x28 */ { "PLP", AM_IMP }, + /* 0x29 */ { "AND", AM_IM_M }, + /* 0x2a */ { "ROL", AM_IMP }, + /* 0x2b */ { "PLD", AM_IMP }, + /* 0x2c */ { "BIT", AM_AB }, + /* 0x2d */ { "AND", AM_AB }, + /* 0x2e */ { "ROL", AM_AB }, + /* 0x2f */ { "AND", AM_ABL }, + /* 0x30 */ { "BMI", AM_R }, + /* 0x31 */ { "AND", AM_IY }, + /* 0x32 */ { "AND", AM_IND }, + /* 0x33 */ { "AND", AM_SRIY }, + /* 0x34 */ { "BIT", AM_DPX }, + /* 0x35 */ { "AND", AM_DPX }, + /* 0x36 */ { "ROL", AM_DPX }, + /* 0x37 */ { "AND", AM_ILY }, + /* 0x38 */ { "SEC", AM_IMP }, + /* 0x39 */ { "AND", AM_ABY }, + /* 0x3a */ { "DEC", AM_IMP }, + /* 0x3b */ { "TSC", AM_IMP }, + /* 0x3c */ { "BIT", AM_ABX }, + /* 0x3d */ { "AND", AM_ABX }, + /* 0x3e */ { "ROL", AM_ABX }, + /* 0x3f */ { "AND", AM_ABLX }, + /* 0x40 */ { "RTI", AM_IMP }, + /* 0x41 */ { "EOR", AM_IX }, + /* 0x42 */ { "WDM", AM_IM_1 }, + /* 0x43 */ { "EOR", AM_SR }, + /* 0x44 */ { "MVP", AM_BLOCK }, + /* 0x45 */ { "EOR", AM_DP }, + /* 0x46 */ { "LSR", AM_DP }, + /* 0x47 */ { "EOR", AM_INDL }, + /* 0x48 */ { "PHA", AM_IMP }, + /* 0x49 */ { "EOR", AM_IM_M }, + /* 0x4a */ { "LSR", AM_IMP }, + /* 0x4b */ { "PHK", AM_IMP }, + /* 0x4c */ { "JMP", AM_AB }, + /* 0x4d */ { "EOR", AM_AB }, + /* 0x4e */ { "LSR", AM_AB }, + /* 0x4f */ { "EOR", AM_ABL }, + /* 0x50 */ { "BVC", AM_R }, + /* 0x51 */ { "EOR", AM_IY }, + /* 0x52 */ { "EOR", AM_IND }, + /* 0x53 */ { "EOR", AM_SRIY }, + /* 0x54 */ { "MVN", AM_BLOCK }, + /* 0x55 */ { "EOR", AM_DPX }, + /* 0x56 */ { "LSR", AM_DPX }, + /* 0x57 */ { "EOR", AM_ILY }, + /* 0x58 */ { "CLI", AM_IMP }, + /* 0x59 */ { "EOR", AM_ABY }, + /* 0x5a */ { "PHY", AM_IMP }, + /* 0x5b */ { "TCD", AM_IMP }, + /* 0x5c */ { "JMP", AM_ABL }, + /* 0x5d */ { "EOR", AM_ABX }, + /* 0x5e */ { "LSR", AM_ABX }, + /* 0x5f */ { "EOR", AM_ABLX }, + /* 0x60 */ { "RTS", AM_IMP }, + /* 0x61 */ { "ADC", AM_IX }, + /* 0x62 */ { "PER", AM_RL }, + /* 0x63 */ { "ADC", AM_SR }, + /* 0x64 */ { "STZ", AM_DP }, + /* 0x65 */ { "ADC", AM_DP }, + /* 0x66 */ { "ROR", AM_DP }, + /* 0x67 */ { "ADC", AM_INDL }, + /* 0x68 */ { "PLA", AM_IMP }, + /* 0x69 */ { "ADC", AM_IM_M }, + /* 0x6a */ { "ROR", AM_IMP }, + /* 0x6b */ { "RTL", AM_IMP }, + /* 0x6c */ { "JMP", AM_ABIND }, + /* 0x6d */ { "ADC", AM_AB }, + /* 0x6e */ { "ROR", AM_AB }, + /* 0x6f */ { "ADC", AM_ABL }, + /* 0x70 */ { "BVS", AM_R }, + /* 0x71 */ { "ADC", AM_IY }, + /* 0x72 */ { "ADC", AM_IND }, + /* 0x73 */ { "ADC", AM_SRIY }, + /* 0x74 */ { "STZ", AM_DPX }, + /* 0x75 */ { "ADC", AM_DPX }, + /* 0x76 */ { "ROR", AM_DPX }, + /* 0x77 */ { "ADC", AM_ILY }, + /* 0x78 */ { "SEI", AM_IMP }, + /* 0x79 */ { "ADC", AM_ABY }, + /* 0x7a */ { "PLY", AM_IMP }, + /* 0x7b */ { "TDC", AM_IMP }, + /* 0x7c */ { "JMP", AM_ABIX }, + /* 0x7d */ { "ADC", AM_ABX }, + /* 0x7e */ { "ROR", AM_ABX }, + /* 0x7f */ { "ADC", AM_ABLX }, + /* 0x80 */ { "BRA", AM_R }, + /* 0x81 */ { "STA", AM_IX }, + /* 0x82 */ { "BRL", AM_RL }, + /* 0x83 */ { "STA", AM_SR }, + /* 0x84 */ { "STY", AM_DP }, + /* 0x85 */ { "STA", AM_DP }, + /* 0x86 */ { "STX", AM_DP }, + /* 0x87 */ { "STA", AM_INDL }, + /* 0x88 */ { "DEY", AM_IMP }, + /* 0x89 */ { "BIT", AM_IM_M }, + /* 0x8a */ { "TXA", AM_IMP }, + /* 0x8b */ { "PHB", AM_IMP }, + /* 0x8c */ { "STY", AM_AB }, + /* 0x8d */ { "STA", AM_AB }, + /* 0x8e */ { "STX", AM_AB }, + /* 0x8f */ { "STA", AM_ABL }, + /* 0x90 */ { "BCC", AM_R }, + /* 0x91 */ { "STA", AM_IY }, + /* 0x92 */ { "STA", AM_IND }, + /* 0x93 */ { "STA", AM_SRIY }, + /* 0x94 */ { "STY", AM_DPX }, + /* 0x95 */ { "STA", AM_DPX }, + /* 0x96 */ { "STX", AM_DPY }, + /* 0x97 */ { "STA", AM_ILY }, + /* 0x98 */ { "TYA", AM_IMP }, + /* 0x99 */ { "STA", AM_ABY }, + /* 0x9a */ { "TXS", AM_IMP }, + /* 0x9b */ { "TXY", AM_IMP }, + /* 0x9c */ { "STZ", AM_AB }, + /* 0x9d */ { "STA", AM_ABX }, + /* 0x9e */ { "STZ", AM_ABX }, + /* 0x9f */ { "STA", AM_ABLX }, + /* 0xa0 */ { "LDY", AM_IM_X }, + /* 0xa1 */ { "LDA", AM_IX }, + /* 0xa2 */ { "LDX", AM_IM_X }, + /* 0xa3 */ { "LDA", AM_SR }, + /* 0xa4 */ { "LDY", AM_DP }, + /* 0xa5 */ { "LDA", AM_DP }, + /* 0xa6 */ { "LDX", AM_DP }, + /* 0xa7 */ { "LDA", AM_INDL }, + /* 0xa8 */ { "TAY", AM_IMP }, + /* 0xa9 */ { "LDA", AM_IM_M }, + /* 0xaa */ { "TAX", AM_IMP }, + /* 0xab */ { "PLB", AM_IMP }, + /* 0xac */ { "LDY", AM_AB }, + /* 0xad */ { "LDA", AM_AB }, + /* 0xae */ { "LDX", AM_AB }, + /* 0xaf */ { "LDA", AM_ABL }, + /* 0xb0 */ { "BCS", AM_R }, + /* 0xb1 */ { "LDA", AM_IY }, + /* 0xb2 */ { "LDA", AM_IND }, + /* 0xb3 */ { "LDA", AM_SRIY }, + /* 0xb4 */ { "LDY", AM_DPX }, + /* 0xb5 */ { "LDA", AM_DPX }, + /* 0xb6 */ { "LDX", AM_DPY }, + /* 0xb7 */ { "LDA", AM_ILY }, + /* 0xb8 */ { "CLV", AM_IMP }, + /* 0xb9 */ { "LDA", AM_ABY }, + /* 0xba */ { "TSX", AM_IMP }, + /* 0xbb */ { "TYX", AM_IMP }, + /* 0xbc */ { "LDY", AM_ABX }, + /* 0xbd */ { "LDA", AM_ABX }, + /* 0xbe */ { "LDX", AM_ABY }, + /* 0xbf */ { "LDA", AM_ABLX }, + /* 0xc0 */ { "CPY", AM_IM_X }, + /* 0xc1 */ { "CMP", AM_IX }, + /* 0xc2 */ { "REP", AM_IM_1 }, + /* 0xc3 */ { "CMP", AM_SR }, + /* 0xc4 */ { "CPY", AM_DP }, + /* 0xc5 */ { "CMP", AM_DP }, + /* 0xc6 */ { "DEC", AM_DP }, + /* 0xc7 */ { "CMP", AM_INDL }, + /* 0xc8 */ { "INY", AM_IMP }, + /* 0xc9 */ { "CMP", AM_IM_M }, + /* 0xca */ { "DEX", AM_IMP }, + /* 0xcb */ { "WAI", AM_IMP }, + /* 0xcc */ { "CPY", AM_AB }, + /* 0xcd */ { "CMP", AM_AB }, + /* 0xce */ { "DEC", AM_AB }, + /* 0xcf */ { "CMP", AM_ABL }, + /* 0xd0 */ { "BNE", AM_R }, + /* 0xd1 */ { "CMP", AM_IY }, + /* 0xd2 */ { "CMP", AM_IND }, + /* 0xd3 */ { "CMP", AM_SRIY }, + /* 0xd4 */ { "PEI", AM_DP }, + /* 0xd5 */ { "CMP", AM_DPX }, + /* 0xd6 */ { "DEC", AM_DPX }, + /* 0xd7 */ { "CMP", AM_ILY }, + /* 0xd8 */ { "CLD", AM_IMP }, + /* 0xd9 */ { "CMP", AM_ABY }, + /* 0xda */ { "PHX", AM_IMP }, + /* 0xdb */ { "STP", AM_IMP }, + /* 0xdc */ { "JML", AM_ABIND }, + /* 0xdd */ { "CMP", AM_ABX }, + /* 0xde */ { "DEC", AM_ABX }, + /* 0xdf */ { "CMP", AM_ABLX }, + /* 0xe0 */ { "CPX", AM_IM_X }, + /* 0xe1 */ { "SBC", AM_IX }, + /* 0xe2 */ { "SEP", AM_IM_1 }, + /* 0xe3 */ { "SBC", AM_SR }, + /* 0xe4 */ { "CPX", AM_DP }, + /* 0xe5 */ { "SBC", AM_DP }, + /* 0xe6 */ { "INC", AM_DP }, + /* 0xe7 */ { "SBC", AM_INDL }, + /* 0xe8 */ { "INX", AM_IMP }, + /* 0xe9 */ { "SBC", AM_IM_M }, + /* 0xea */ { "NOP", AM_IMP }, + /* 0xeb */ { "XBA", AM_IMP }, + /* 0xec */ { "CPX", AM_AB }, + /* 0xed */ { "SBC", AM_AB }, + /* 0xee */ { "INC", AM_AB }, + /* 0xef */ { "SBC", AM_ABL }, + /* 0xf0 */ { "BEQ", AM_R }, + /* 0xf1 */ { "SBC", AM_IY }, + /* 0xf2 */ { "SBC", AM_IND }, + /* 0xf3 */ { "SBC", AM_SRIY }, + /* 0xf4 */ { "PEA", AM_AB }, + /* 0xf5 */ { "SBC", AM_DPX }, + /* 0xf6 */ { "INC", AM_DPX }, + /* 0xf7 */ { "SBC", AM_ILY }, + /* 0xf8 */ { "SED", AM_IMP }, + /* 0xf9 */ { "SBC", AM_ABY }, + /* 0xfa */ { "PLX", AM_IMP }, + /* 0xfb */ { "XCE", AM_IMP }, + /* 0xfc */ { "JSR", AM_ABIX }, + /* 0xfd */ { "SBC", AM_ABX }, + /* 0xfe */ { "INC", AM_ABX }, + /* 0xff */ { "SBC", AM_ABLX }, diff --git a/mednafen/snes_faust/notes/ops.txt b/mednafen/snes_faust/notes/ops.txt new file mode 100644 index 0000000..42d1e3b --- /dev/null +++ b/mednafen/snes_faust/notes/ops.txt @@ -0,0 +1,51 @@ + | y0 | y1 | y2 | y3 | y4 | y5 | y6 | y7 | y8 | y9 | yA | yB | yC | yD | yE | yF | + |---------------------------------------------------------------------------------------------------------------- + 0x | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + 1x | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + 2x | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + 3x | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + 4x | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + 5x | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + 6x | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + 7x | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + 8x | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + 9x | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + Ax | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + Bx | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + Cx | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + Dx | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + Ex | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + Fx | | | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------------------------------------------------------| + diff --git a/mednafen/snes_faust/notes/ops2.txt b/mednafen/snes_faust/notes/ops2.txt new file mode 100644 index 0000000..5910eb3 --- /dev/null +++ b/mednafen/snes_faust/notes/ops2.txt @@ -0,0 +1,16 @@ +BRK s * ORA (d,x) * COP s * ORA r,s * TSB d * ORA d * ASL d * ORA [d] * PHP s * ORA # * ASL A * PHD s * TSB a * ORA a * ASL a * ORA al +BPL r * ORA (d),y * ORA (d) * ORA (r,s),y * TRB d * ORA d,x * ASL d,x * ORA [d],y * CLC i * ORA a,y * INC A * TCS i * TRB a * ORA a,x * ASL a,x * ORA al,x +JSR a * AND (d,x) * JSL al * AND r,s * BIT d * AND d * ROL d * AND [d] * PLP s * AND # * ROL A * PLD s * BIT a * AND a * ROL a * AND al +BMI r * AND (d),y * AND (d) * AND (r,s),y * BIT d,x * AND d,x * ROL d,x * AND [d],y * SEC i * AND a,y * DEC A * TSC i * BIT a,x * AND a,x * ROL a,x * AND al,x +RTI s * EOR (d,x) * reserv * EOR r,s * MVP xya * EOR d * LSR d * EOR [d] * PHA s * EOR # * LSR A * PHK s * JMP a * EOR a * LSR a * EOR al +BVC r * EOR (d),y * EOR (d) * EOR (r,s),y * MVN xya * EOR d,x * LSR d,x * EOR [d],y * CLI i * EOR a,y * PHY s * TCD i * JMP al * EOR a,x * LSR a,x * EOR al,x +RTS s * ADC (d,x) * PER s * ADC r,s * STZ d * ADC d * ROR d * ADC[d] * PLA s * ADC # * ROR A * RTL s * JMP (a) * ADC a * ROR a * ADC al +BVS r * ADC (d),y * ADC (d) * ADC (r,s),y * STZ d,x * ADC d,x * ROR d,x * ADC [d],y * SEI i * ADC a,y * PLY s * TDC i * JMP (a,x) * ADC a,x * ROR a,x * ADC al,x +BRA r * STA (d,x) * BRL rl * STA r,s * STY d * STA d * STX d * STA [d] * DEY i * BIT # * TXA i * PHB s * STY a * STA a * STX a * STA al +BCC r * STA (d),y * STA (d) * STA (r,s),y * STY d,x * STA d,x * STX d,y * STA [d],y * TYA i * STA a,y * TXS i * TXY i * STZ a * STA a,x * STZ a,x * STA al,x +LDY # * LDA (d,x) * LDX # * LDA r,s * LDY d * LDA d * LDX d * LDA [d] * TAY i * LDA # * TAX i * PLB s * LDY a * LDA a * LDX a * LDA al +BCS r * LDA (d),y * LDA (d) * LDA (r,s),y * LDY d,x * LDA d,x * LDX d,y * LDA [d],y * CLV i * LDA a,y * TSX i * TYX i * LDY a,x * LDA a,x * LDX a,y * LDA al,x +CPY # * CMP (d,x) * REP # * CMP r,s * CPY d * CMP d * DEC d * CMP [d] * INY i * CMP # * DEX i * WAI i * CPY a * CMP a * DEC a * CMP al +BNE r * CMP (d),y * CMP (d) * CMP (r,s),y * PEI s * CMP d,x * DEC d,x * CMP [d],y * CLD i * CMP a,y * PHX s * STP i * JML (a) * CMP a,x * DEC a,x * CMP al,x +CPX # * SBC (d,x) * SEP # * SBC r,s * CPX d * SBC d * INC d * SBC [d] * INX i * SBC # * NOP i * XBA i * CPX a * SBC a * INC a * SBC al +BEQ r * SBC (d),y * SBC (d) * SBC (r,s),y * PEA s * SBC d,x * INC d,x * SBC [d],y * SED i * SBC a,y * PLX s * XCE i * JSR (a,x) * SBC a,x * INC a,x * SBC al,x diff --git a/mednafen/snes_faust/notes/ops3.txt b/mednafen/snes_faust/notes/ops3.txt new file mode 100644 index 0000000..f579339 --- /dev/null +++ b/mednafen/snes_faust/notes/ops3.txt @@ -0,0 +1,16 @@ +BRK #1 * ORA (d,x) * COP #1 * ORA r,s * TSB d * ORA d * ASL d * ORA [d] * PHP s * ORA #m * ASL A * PHD s * TSB a * ORA a * ASL a * ORA al +BPL r * ORA (d),y * ORA (d) * ORA (r,s),y * TRB d * ORA d,x * ASL d,x * ORA [d],y * CLC i * ORA a,y * INC A * TCS i * TRB a * ORA a,x * ASL a,x * ORA al,x +JSR a * AND (d,x) * JSL al * AND r,s * BIT d * AND d * ROL d * AND [d] * PLP s * AND #m * ROL A * PLD s * BIT a * AND a * ROL a * AND al +BMI r * AND (d),y * AND (d) * AND (r,s),y * BIT d,x * AND d,x * ROL d,x * AND [d],y * SEC i * AND a,y * DEC A * TSC i * BIT a,x * AND a,x * ROL a,x * AND al,x +RTI s * EOR (d,x) * WDM #1 * EOR r,s * MVP xya * EOR d * LSR d * EOR [d] * PHA s * EOR #m * LSR A * PHK s * JMP a * EOR a * LSR a * EOR al +BVC r * EOR (d),y * EOR (d) * EOR (r,s),y * MVN xya * EOR d,x * LSR d,x * EOR [d],y * CLI i * EOR a,y * PHY s * TCD i * JMP al * EOR a,x * LSR a,x * EOR al,x +RTS s * ADC (d,x) * PER rl * ADC r,s * STZ d * ADC d * ROR d * ADC [d] * PLA s * ADC #m * ROR A * RTL s * JMP (a) * ADC a * ROR a * ADC al +BVS r * ADC (d),y * ADC (d) * ADC (r,s),y * STZ d,x * ADC d,x * ROR d,x * ADC [d],y * SEI i * ADC a,y * PLY s * TDC i * JMP (a,x) * ADC a,x * ROR a,x * ADC al,x +BRA r * STA (d,x) * BRL rl * STA r,s * STY d * STA d * STX d * STA [d] * DEY i * BIT #m * TXA i * PHB s * STY a * STA a * STX a * STA al +BCC r * STA (d),y * STA (d) * STA (r,s),y * STY d,x * STA d,x * STX d,y * STA [d],y * TYA i * STA a,y * TXS i * TXY i * STZ a * STA a,x * STZ a,x * STA al,x +LDY #x * LDA (d,x) * LDX #x * LDA r,s * LDY d * LDA d * LDX d * LDA [d] * TAY i * LDA #m * TAX i * PLB s * LDY a * LDA a * LDX a * LDA al +BCS r * LDA (d),y * LDA (d) * LDA (r,s),y * LDY d,x * LDA d,x * LDX d,y * LDA [d],y * CLV i * LDA a,y * TSX i * TYX i * LDY a,x * LDA a,x * LDX a,y * LDA al,x +CPY #x * CMP (d,x) * REP #1 * CMP r,s * CPY d * CMP d * DEC d * CMP [d] * INY i * CMP #m * DEX i * WAI i * CPY a * CMP a * DEC a * CMP al +BNE r * CMP (d),y * CMP (d) * CMP (r,s),y * PEI d * CMP d,x * DEC d,x * CMP [d],y * CLD i * CMP a,y * PHX s * STP i * JML (a) * CMP a,x * DEC a,x * CMP al,x +CPX #x * SBC (d,x) * SEP #1 * SBC r,s * CPX d * SBC d * INC d * SBC [d] * INX i * SBC #m * NOP i * XBA i * CPX a * SBC a * INC a * SBC al +BEQ r * SBC (d),y * SBC (d) * SBC (r,s),y * PEA a * SBC d,x * INC d,x * SBC [d],y * SED i * SBC a,y * PLX s * XCE i * JSR (a,x) * SBC a,x * INC a,x * SBC al,x diff --git a/mednafen/snes_faust/ppu.cpp b/mednafen/snes_faust/ppu.cpp index 86ab640..cf90c26 100644 --- a/mednafen/snes_faust/ppu.cpp +++ b/mednafen/snes_faust/ppu.cpp @@ -2,7 +2,7 @@ /* Mednafen Fast SNES Emulation Module */ /******************************************************************************/ /* ppu.cpp: -** Copyright (C) 2015-2018 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -26,102 +26,186 @@ // // FIXME: Correct handling of lower 3 bits of BGHOFS registers. // -// FIXME: Interlaced support. +// FIXME: Short/long line. // #include "snes.h" #include "ppu.h" #include "input.h" +#include "cart.h" namespace MDFN_IEN_SNES_FAUST { -static uint32 lastts; +uint32 scanline; -static uint32 LineStartTS; -static unsigned HLatch, VLatch; -static unsigned HLatchReadShift, VLatchReadShift; - - -// -// Cheaty registers and state: -static uint16 HTime; -static uint16 VTime; +static struct +{ + uint32 lastts; -static uint8 NMITIMEEN; + uint32 LineStartTS; + uint32 HLatch; + uint32 VLatch; + uint32 HLatchReadShift; + uint32 VLatchReadShift; -static uint8 HVBJOY; -static uint8 NMIFlag; // 0x00 or 0x80 -static uint8 IRQFlag; // 0x00 or 0x80 -static uint8 JPReadCounter; -// -// + // + // Cheaty registers and state: + uint32 InHDMA; + uint16 HTime; + uint16 VTime; + bool IRQThing; + + uint8 NMITIMEEN; + + uint8 HVBJOY; + uint8 NMIFlag; // 0x00 or 0x80 + uint8 IRQFlag; // 0x00 or 0x80 + uint8 JPReadCounter; + // + // -static bool PAL; -static bool VBlank; -static bool LinePhase; -static uint32 LineCounter; -/*static*/ uint32 scanline; -static uint32 LinesPerFrame; -static uint32 LineTarget; - -static uint8 BusLatch[2]; -static uint8 Status[2]; // $3E and $3F. - -static uint16 VRAM[32768]; - -static uint8 ScreenMode; // $33 -static uint8 INIDisp; -static uint8 BGMode; -static uint8 Mosaic; -static uint8 MosaicYOffset; - -static uint8 BGSC[4]; - -static uint8 BGNBA[2]; - -static uint8 BGOFSPrev; -static uint16 BGHOFS[4]; -static uint16 BGVOFS[4]; - -static uint16 VRAM_Addr; -static uint16 VRAM_ReadBuffer; -static bool VMAIN_IncMode; -static unsigned VMAIN_AddrInc; -static unsigned VMAIN_AddrTransMaskA; -static unsigned VMAIN_AddrTransShiftB; -static unsigned VMAIN_AddrTransMaskC; - -static uint8 M7Prev; -static uint8 M7SEL; -static int16 M7Matrix[4]; -static int16 M7Center[2]; -static int16 M7HOFS, M7VOFS; - -static bool CGRAM_Toggle; -static uint8 CGRAM_Buffer; -static uint8 CGRAM_Addr; -static uint16 CGRAM[256]; - -static uint8 MSEnable; -static uint8 SSEnable; - -static uint8 WMSettings[3]; -static uint8 WMMainEnable, WMSubEnable; -static uint16 WMLogic; -static uint8 WindowPos[2][2]; -static unsigned WindowPieces[5]; // Derived data, calculated at start of rendering for a scanline. - -static uint8 CGWSEL; -static uint8 CGADSUB; -static uint16 FixedColor; - -static uint8 OBSEL; -static uint8 OAMADDL, OAMADDH; -static uint8 OAM_Buffer; -static uint32 OAM_Addr; -static uint8 OAM[512]; -static uint8 OAMHI[32]; + bool PAL; + bool VBlank; + uint32 LinePhase; + uint32 LineCounter; +///*static*/ uint32 scanline; + uint32 LinesPerFrame; + uint32 LineTarget; + + uint8 BusLatch[2]; + uint8 Status[2]; // $3E and $3F. + + uint8 ScreenMode; // $33 + uint8 INIDisp; + uint8 BGMode; + uint8 Mosaic; + uint8 MosaicYOffset; + + uint8 BGSC[4]; + + uint8 BGNBA[2]; + + uint8 BGOFSPrev; + uint16 BGHOFS[4]; + uint16 BGVOFS[4]; + + uint16 VRAM_Addr; + uint16 VRAM_ReadBuffer; + bool VMAIN_IncMode; + unsigned VMAIN_AddrInc; + unsigned VMAIN_AddrTransMaskA; + unsigned VMAIN_AddrTransShiftB; + unsigned VMAIN_AddrTransMaskC; + + uint8 M7Prev; + uint8 M7SEL; + int16 M7Matrix[4]; + int16 M7Center[2]; + int16 M7HOFS; + int16 M7VOFS; + + bool CGRAM_Toggle; + uint8 CGRAM_Buffer; + uint8 CGRAM_Addr; + uint16 CGRAM[256]; + + uint8 MSEnable; + uint8 SSEnable; + + uint8 WMSettings[3]; + uint8 WMMainEnable; + uint8 WMSubEnable; + uint16 WMLogic; + uint8 WindowPos[2][2]; + unsigned WindowPieces[5]; // Derived data, calculated at start of rendering for a scanline. + + uint8 CGWSEL; + uint8 CGADSUB; + uint16 FixedColor; + + uint8 OBSEL; + uint8 OAMADDL; + uint8 OAMADDH; + uint8 OAM_Buffer; + uint32 OAM_Addr; + uint8 OAM[512]; + uint8 OAMHI[32]; + + uint16 VRAM[32768]; +} PPU; + +#define GLBVAR(x) static auto& x = PPU.x; + GLBVAR(lastts) + GLBVAR(LineStartTS) + GLBVAR(HLatch) + GLBVAR(VLatch) + GLBVAR(HLatchReadShift) + GLBVAR(VLatchReadShift) + GLBVAR(InHDMA) + GLBVAR(IRQThing) + GLBVAR(HTime) + GLBVAR(VTime) + GLBVAR(NMITIMEEN) + GLBVAR(HVBJOY) + GLBVAR(NMIFlag) + GLBVAR(IRQFlag) + GLBVAR(JPReadCounter) + GLBVAR(PAL) + GLBVAR(VBlank) + GLBVAR(LinePhase) + GLBVAR(LineCounter) + GLBVAR(LinesPerFrame) + GLBVAR(LineTarget) + GLBVAR(BusLatch) + GLBVAR(Status) + GLBVAR(ScreenMode) + GLBVAR(INIDisp) + GLBVAR(BGMode) + GLBVAR(Mosaic) + GLBVAR(MosaicYOffset) + GLBVAR(BGSC) + GLBVAR(BGNBA) + GLBVAR(BGOFSPrev) + GLBVAR(BGHOFS) + GLBVAR(BGVOFS) + GLBVAR(VRAM_Addr) + GLBVAR(VRAM_ReadBuffer) + GLBVAR(VMAIN_IncMode) + GLBVAR(VMAIN_AddrInc) + GLBVAR(VMAIN_AddrTransMaskA) + GLBVAR(VMAIN_AddrTransShiftB) + GLBVAR(VMAIN_AddrTransMaskC) + GLBVAR(M7Prev) + GLBVAR(M7SEL) + GLBVAR(M7Matrix) + GLBVAR(M7Center) + GLBVAR(M7HOFS) + GLBVAR(M7VOFS) + GLBVAR(CGRAM_Toggle) + GLBVAR(CGRAM_Buffer) + GLBVAR(CGRAM_Addr) + GLBVAR(CGRAM) + GLBVAR(MSEnable) + GLBVAR(SSEnable) + GLBVAR(WMSettings) + GLBVAR(WMMainEnable) + GLBVAR(WMSubEnable) + GLBVAR(WMLogic) + GLBVAR(WindowPos) + GLBVAR(WindowPieces) + GLBVAR(CGWSEL) + GLBVAR(CGADSUB) + GLBVAR(FixedColor) + GLBVAR(OBSEL) + GLBVAR(OAMADDL) + GLBVAR(OAMADDH) + GLBVAR(OAM_Buffer) + GLBVAR(OAM_Addr) + GLBVAR(OAM) + GLBVAR(OAMHI) + GLBVAR(VRAM) +#undef GLBVAR static DEFWRITE(Write_ScreenMode) { @@ -169,8 +253,17 @@ static DEFWRITE(Write_OAMDATA) { CPUM.timestamp += MEMCYC_FAST; - //fprintf(stderr, "OAMDATA Write: 0x%04x 0x%02x\n", OAM_Addr, V); + //fprintf(stderr, "OAMDATA Write: 0x%04x 0x%02x, %d %d\n", OAM_Addr, V, scanline, (CPUM.timestamp - LineStartTS) >> 2); // +#if 0 + // Uniracers test fix + if(MDFN_UNLIKELY(scanline == 112) && MDFN_UNLIKELY(!(INIDisp & 0x80))) + { + OAMHI[0x18] = V; + return; + } +#endif + if(OAM_Addr & 0x200) OAMHI[OAM_Addr & 0x1F] = V; else if(OAM_Addr & 1) @@ -187,6 +280,11 @@ static DEFWRITE(Write_OAMDATA) static DEFREAD(Read_PPU1_BL) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return BusLatch[0]; + } + CPUM.timestamp += MEMCYC_FAST; // return BusLatch[0]; @@ -195,6 +293,11 @@ static DEFREAD(Read_PPU1_BL) // PPU1 static DEFREAD(Read_OAMDATAREAD) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return (OAM_Addr & 0x200) ? OAMHI[OAM_Addr & 0x1F] : OAM[OAM_Addr]; + } + CPUM.timestamp += MEMCYC_FAST; // if(OAM_Addr & 0x200) @@ -287,7 +390,7 @@ static INLINE void FetchSpriteData(signed line_y) const uint8* const oa = &OAM[SpriteIndex << 2]; const uint8 hob = OAMHI[SpriteIndex >> 2] >> ((SpriteIndex & 0x3) << 1); const bool sizebit = hob & 0x2; - signed x = sign_x_to_s32(9, oa[0] | ((hob & 1) << 8)); + const signed x = sign_x_to_s32(9, oa[0] | ((hob & 1) << 8)); uint8 y_offset = line_y - oa[1]; uint8 w = whtab[sizebit][0]; uint8 h = whtab[sizebit][1]; @@ -296,8 +399,7 @@ static INLINE void FetchSpriteData(signed line_y) continue; //printf("Line %d, Sprite: %d:%d, %d:%d\n", line_y, x, y_offset, w, h); - - if(x <= -w) // fixme: x == -256 special case + if(w <= sign_x_to_s32(9, -x)) continue; if(SpriteCount == 32) @@ -344,54 +446,72 @@ static INLINE void FetchSpriteData(signed line_y) { const auto* const l = &SpriteList[i]; - for(int ht = 0; ht < (l->w >> 3); ht++) + if(MDFN_UNLIKELY(l->x == -256)) { - int xo = l->x + (ht << 3); - - if(xo <= -8 || xo >= 256) //rof > (255 + 7)) - continue; - - if(SpriteTileCount == 34) + for(int ht = 0; ht < l->w; ht += 8) { - //printf("Sprite tile overflow on %u\n", line_y); - Status[0] |= 0x80; - goto ExitTileLoop; + if(SpriteTileCount == 34) + { + //printf("Sprite tile overflow on %u\n", line_y); + Status[0] |= 0x80; + goto ExitTileLoop; + } + + // TODO: initialize the other members if we ever make SpriteTileList temporarily allocated + SpriteTileList[SpriteTileCount++].td = 0; } - auto* const t = &SpriteTileList[SpriteTileCount++]; + } + else + { + for(int ht = 0; ht < l->w; ht += 8) + { + int xo = l->x + ht; - t->x = xo; - t->prio_or = (l->prio + 1) * 0x3030 | ((l->paloffs & 0x40) >> 6) | 2; + if(xo <= -8 || xo >= 256) //rof > (255 + 7)) + continue; - uint8 wt; + if(SpriteTileCount == 34) + { + //printf("Sprite tile overflow on %u\n", line_y); + Status[0] |= 0x80; + goto ExitTileLoop; + } + auto* const t = &SpriteTileList[SpriteTileCount++]; - unsigned rof = ((ht << 3) ^ l->hfxor) >> 3; + t->x = xo; + t->prio_or = (l->prio + 1) * 0x3030 | ((l->paloffs & 0x40) >> 6) | 2; - wt = ((l->tilebase & 0xF0) + (l->y_offset << 1)) & 0xF0; - wt |= (l->tilebase + rof) & 0x0F; + uint8 wt; - uint16* chr = chrbase[l->n] + (wt << 4) + (l->y_offset & 0x7); + unsigned rof = (ht ^ l->hfxor) >> 3; - uint32 bp = chr[0] | (chr[8] << 16); - for(unsigned x = 0; x < 8; x++) - { - uint32 pix; + wt = ((l->tilebase & 0xF0) + (l->y_offset << 1)) & 0xF0; + wt |= (l->tilebase + rof) & 0x0F; - pix = ((bp >> 7) & 0x01); - pix |= ((bp >> 14) & 0x02); - pix |= ((bp >> 21) & 0x04); - pix |= ((bp >> 28) & 0x08); + uint16* chr = chrbase[l->n] + (wt << 4) + (l->y_offset & 0x7); - if(!l->hfxor) - { - t->td >>= 8; - t->td |= (uint64)(pix | l->paloffs) << 56; - } - else + uint32 bp = chr[0] | (chr[8] << 16); + for(unsigned x = 0; x < 8; x++) { - t->td <<= 8; - t->td |= pix | l->paloffs; + uint32 pix; + + pix = ((bp >> 7) & 0x01); + pix |= ((bp >> 14) & 0x02); + pix |= ((bp >> 21) & 0x04); + pix |= ((bp >> 28) & 0x08); + + if(!l->hfxor) + { + t->td >>= 8; + t->td |= (uint64)(pix | l->paloffs) << 56; + } + else + { + t->td <<= 8; + t->td |= pix | l->paloffs; + } + bp <<= 1; } - bp <<= 1; } } } @@ -470,12 +590,15 @@ static DEFWRITE(Write_BGHOFS) { CPUM.timestamp += MEMCYC_FAST; // + //printf("BG%dHOFS Write; Prev=0x%02x, V=0x%02x, InHDMA=0x%08x, scanline=%u\n", 1 + ((uint8)A >> 1) - (0x0D >> 1), BGOFSPrev, V, InHDMA, scanline); + // uint16* const t = &BGHOFS[((size_t)(uint8)A >> 1) - (0x0D >> 1)]; *t = BGOFSPrev | ((V & 0x3) << 8); BGOFSPrev = V; if(bg0) { + //printf("M7HOFS: %u, %02x\n", scanline, V); M7HOFS = sign_13_to_s16(M7Prev | ((V & 0x1F) << 8)); M7Prev = V; } @@ -485,13 +608,15 @@ template static DEFWRITE(Write_BGVOFS) { CPUM.timestamp += MEMCYC_FAST; - + // + //printf("BG%dVOFS Write; Prev=0x%02x, V=0x%02x, InHDMA=0x%08x, scanline=%u\n", 1 + ((uint8)A >> 1) - (0x0E >> 1), BGOFSPrev, V, InHDMA, scanline); // BGVOFS[((size_t)(uint8)A >> 1) - (0x0E >> 1)] = BGOFSPrev | ((V & 0x3) << 8); BGOFSPrev = V; if(bg0) { + //printf("M7VOFS: %u, %02x\n", scanline, V); M7VOFS = sign_13_to_s16(M7Prev | ((V & 0x1F) << 8)); M7Prev = V; } @@ -547,6 +672,12 @@ static DEFWRITE(Write_2118) { CPUM.timestamp += MEMCYC_FAST; // + // TODO: Block all VRAM writes during active display, not just those from HDMA(just doing the latter + // for now in case small timing errors might break legitimate write attempts). + if(MDFN_UNLIKELY(InHDMA != 0x80000000U && !(INIDisp & 0x80))) + return; + // + // const unsigned va = GetVAddr(); //if(va >= 0x2000 && va < 0x3000) @@ -563,6 +694,12 @@ static DEFWRITE(Write_2119) { CPUM.timestamp += MEMCYC_FAST; // + // TODO: Block all VRAM writes during active display, not just those from HDMA(just doing the latter + // for now in case small timing errors might break legitimate write attempts). + if(MDFN_UNLIKELY(InHDMA != 0x80000000U && !(INIDisp & 0x80))) + return; + // + // const unsigned va = GetVAddr(); //if(va >= 0x2000 && va < 0x3000) @@ -578,6 +715,11 @@ static DEFWRITE(Write_2119) // PPU1 static DEFREAD(Read_2139) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return VRAM_ReadBuffer; + } + CPUM.timestamp += MEMCYC_FAST; // BusLatch[0] = VRAM_ReadBuffer; @@ -594,6 +736,11 @@ static DEFREAD(Read_2139) // PPU1 static DEFREAD(Read_213A) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return VRAM_ReadBuffer >> 8; + } + CPUM.timestamp += MEMCYC_FAST; // BusLatch[0] = VRAM_ReadBuffer >> 8; @@ -627,6 +774,11 @@ static DEFWRITE(Write_M7Matrix) // $1b-$1e template static DEFREAD(Read_M7Multiplier) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return (uint32)((int16)M7Matrix[0] * (int8)(M7Matrix[1] >> 8)) >> shift; + } + CPUM.timestamp += MEMCYC_FAST; // BusLatch[0] = (uint32)((int16)M7Matrix[0] * (int8)(M7Matrix[1] >> 8)) >> shift; @@ -670,6 +822,11 @@ static DEFWRITE(Write_CGDATA) // PPU2 static DEFREAD(Read_CGDATAREAD) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return CGRAM_Toggle ? ((BusLatch[1] & 0x80) | (CGRAM[CGRAM_Addr] >> 8)) : (CGRAM[CGRAM_Addr] >> 0); + } + CPUM.timestamp += MEMCYC_FAST; // if(CGRAM_Toggle) @@ -775,6 +932,11 @@ static DEFWRITE(Write_COLDATA) static DEFREAD(Read_HVLatchTrigger) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return CPUM.mdr; + } + CPUM.timestamp += MEMCYC_FAST; // @@ -795,7 +957,7 @@ static DEFREAD(Read_HVLatchTrigger) else { HLatch -= 341; - VLatch = (VLatch + 1) % LinesPerFrame; // FIXME + VLatch = (VLatch + 1) % (LinesPerFrame + ((~Status[1] >> 7) & ScreenMode & 1)); // FIXME } } @@ -810,6 +972,11 @@ static DEFREAD(Read_HVLatchTrigger) // PPU2 static DEFREAD(Read_HLatch) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return (HLatch | ((BusLatch[1] & 0xFE) << 8)) >> HLatchReadShift; + } + CPUM.timestamp += MEMCYC_FAST; // BusLatch[1] = (HLatch | ((BusLatch[1] & 0xFE) << 8)) >> HLatchReadShift; @@ -822,6 +989,11 @@ static DEFREAD(Read_HLatch) // PPU2 static DEFREAD(Read_VLatch) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return (VLatch | ((BusLatch[1] & 0xFE) << 8)) >> VLatchReadShift; + } + CPUM.timestamp += MEMCYC_FAST; // BusLatch[1] = (VLatch | ((BusLatch[1] & 0xFE) << 8)) >> VLatchReadShift; @@ -834,6 +1006,11 @@ static DEFREAD(Read_VLatch) // PPU1 static DEFREAD(Read_PPU1_Status) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return (BusLatch[0] & 0x10) | Status[0]; + } + CPUM.timestamp += MEMCYC_FAST; // BusLatch[0] = (BusLatch[0] & 0x10) | Status[0]; @@ -844,6 +1021,11 @@ static DEFREAD(Read_PPU1_Status) // PPU2 static DEFREAD(Read_PPU2_Status) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return (BusLatch[1] & 0x20) | Status[1]; + } + CPUM.timestamp += MEMCYC_FAST; // BusLatch[1] = (BusLatch[1] & 0x20) | Status[1]; @@ -894,11 +1076,12 @@ void PPU_StartFrame(EmulateSpecStruct* espec) { es = espec; + es->InterlaceOn = false; es->LineWidths[0] = 0; es->DisplayRect.x = 0; - es->DisplayRect.y = PAL ? 0 : 8; es->DisplayRect.w = 256; - es->DisplayRect.h = PAL ? 239 : 224; + es->DisplayRect.y = 0; + es->DisplayRect.h = 0; if(es->VideoFormatChanged) { @@ -1001,15 +1184,29 @@ static INLINE unsigned DirColCvt(unsigned inpix, unsigned palbase = 0) template static MDFN_HOT MDFN_FASTCALL void DrawBG(const unsigned n, const unsigned y, uint32 prio_or) { - unsigned VOFS = BGVOFS[n] + (y - ((Mosaic & (1U << n)) ? MosaicYOffset : 0)); + const bool MosaicOn = Mosaic & (1U << n); + unsigned VOFS = y - (MosaicOn ? MosaicYOffset : 0); unsigned HOFS = BGHOFS[n]; unsigned tm_w_mask = ((BGSC[n] & 0x1) << 10); unsigned tm_h_shift = ((BGSC[n] & 0x2) ? ((BGSC[n] & 0x1) ? 3 : 2) : 24); - unsigned tile_y_offs = (VOFS & 0x7); //if(scanline == 100 && n == 0) // MDFN_DispMessage("%d %d --- BGHOFS0=%u BGHOFS1=%u\n", hires, size16, BGHOFS[0], BGHOFS[1]); + if(hires && (ScreenMode & 0x01)) + { + VOFS <<= 1; + + if(!MosaicOn) + VOFS += Status[1] >> 7; + } + + VOFS += BGVOFS[n]; + // + unsigned tile_y_offs = (VOFS & 0x7); + // + // + // if(hires) HOFS <<= 1; @@ -1624,6 +1821,8 @@ static MDFN_HOT MDFN_FASTCALL NO_INLINE void MixMainSubSubSubMarine(uint32* MDFN sub_color = CMath<(bool)(cmath_mode & 1), (bool)(cmath_mode & 2)>(sub_color, FixedColor); } } + else if(!(main & 0x2)) + sub_color = 0; //rand(); target[(i << 1) + 0] = ConvertRGB555(sub_color); target[(i << 1) + 1] = ConvertRGB555(main_color); @@ -1936,55 +2135,142 @@ static INLINE void DrawBGAndMixToMS(void) SNES_DBG("[PPU] BGMODE: %02x\n", BGMode); } +static INLINE uint32 Blend32(uint32 a, uint32 b) +{ + #ifdef HAVE_NATIVE64BIT + a = ((((uint64)a + b) - ((a ^ b) & 0x01010101))) >> 1; + #else + a = ((((a & 0x00FF00FF) + (b & 0x00FF00FF)) >> 1) & 0x00FF00FF) | (((((a & 0xFF00FF00) >> 1) + ((b & 0xFF00FF00) >> 1))) & 0xFF00FF00); + #endif + return a; +} + +template +static uint32 T_DoHFilter(uint32* const t, const uint32 w, const bool hires) +{ + //assert(w == 512 || w == 256); + if(w == 512) + { + if(!hires && Mode == PPU_HFILTER_PHR256BLEND) + { + for(uint32 i = 0; i < 256; i++) + { + t[i] = Blend32(t[(i << 1) + 0], t[(i << 1) + 1]); + } + return 256; + } + else if(!hires && Mode == PPU_HFILTER_PHR256BLEND_512) + { + for(uint32 i = 0; i < 512; i += 2) + { + const uint32 pix = Blend32(t[i + 0], t[i + 1]); + + t[i + 0] = pix; + t[i + 1] = pix; + } + return 512; + } + else if(Mode == PPU_HFILTER_512_BLEND) + { + uint32 prev = t[0]; + for(uint32 i = 0; i < 512; i++) + { + const uint32 pix = Blend32(t[i], prev); + + prev = t[i]; + + t[i] = pix; + } + return 512; + } + else + return 512; + } + else + { + if(Mode == PPU_HFILTER_PHR256BLEND_512 || Mode == PPU_HFILTER_512) + { + for(int32 i = 255; i >= 0; i--) + { + const uint32 pix = t[i]; + + t[(i << 1) + 0] = pix; + t[(i << 1) + 1] = pix; + } + return 512; + } + else if(Mode == PPU_HFILTER_512_BLEND) + { + for(uint32 i = 255; i > 0; i--) + { + t[(i << 1) + 0] = Blend32(t[i], t[i - 1]); + t[(i << 1) + 1] = t[i]; + } + t[1] = t[0]; + return 512; + } + else + return 256; + } +} + +static uint32 (*DoHFilter)(uint32* const t, const uint32 w, const bool hires); + static MDFN_HOT void RenderLine(void) { if(MDFN_UNLIKELY(LineTarget > 239)) // Sanity check(239 isn't shown, too...) LineTarget = 239; - uint32* const out_target = es->surface->pixels + (LineTarget * es->surface->pitchinpix); + const int32 out_line = (LineTarget << es->InterlaceOn) + (es->InterlaceOn & es->InterlaceField); + uint32* const out_target = es->surface->pixels + out_line * es->surface->pitchinpix; const uint32 w = ((BGMode & 0x7) == 0x5 || (BGMode & 0x7) == 0x6 || (ScreenMode & 0x08)) ? 512 : 256; - es->LineWidths[LineTarget] = w; + es->LineWidths[out_line] = w; // LineTarget++; // - if(INIDisp & 0x80) + if(MDFN_UNLIKELY(INIDisp & 0x80)) { for(unsigned i = 0; i < w; i++) out_target[i] = 0; - - return; } - - if(scanline == 1) - MosaicYOffset = 0; else { - MosaicYOffset++; - if(MosaicYOffset > (Mosaic >> 4)) + if(scanline == 1) MosaicYOffset = 0; - } + else + { + MosaicYOffset++; + if(MosaicYOffset > (Mosaic >> 4)) + MosaicYOffset = 0; + } - CalcWindowPieces(); - // - // - // - DrawSprites(); - DoWindow(4, &objbuf[8]); + CalcWindowPieces(); + // + // + // + DrawSprites(); + DoWindow(4, &objbuf[8]); - DrawBGAndMixToMS(); - DoWindow(5, linebuf.main); + DrawBGAndMixToMS(); + DoWindow(5, linebuf.main); - if(MDFN_UNLIKELY(w == 512)) - { - // Nope, won't work right! - //DoWindow(5, linebuf.sub); // For color window masking to black. Probably should find a more efficient/logical way to do this... - MixMainSub(out_target); + if(MDFN_UNLIKELY(w == 512)) + { + // Nope, won't work right! + //DoWindow(5, linebuf.sub); // For color window masking to black. Probably should find a more efficient/logical way to do this... + MixMainSub(out_target); + } + else + { + MixMainSub(out_target); + } } - else + + if(MDFN_UNLIKELY(DoHFilter)) { - MixMainSub(out_target); + es->LineWidths[out_line] = DoHFilter(out_target, w, (BGMode & 0x7) == 0x5 || (BGMode & 0x7) == 0x6); } } @@ -2000,15 +2286,26 @@ static DEFWRITE(Write_NMITIMEEN) // $4200 { CPUM.timestamp += MEMCYC_FAST; // - NMITIMEEN = V; + SNES_DBG("[SNES] Write NMITIMEEN: 0x%02x --- scanline=%u, %u\n", V, scanline, (CPUM.timestamp - LineStartTS) >> 2); + + if(NMITIMEEN != V) + { +#if 1 + // Mortal Kombat II kludge + if(MDFN_UNLIKELY(CPUM.timestamp >= events[SNES_EVENT_PPU].event_time) && InHDMA == 0x80000000U) + CPUM.EventHandler(); +#endif + // + NMITIMEEN = V; - if(!(NMITIMEEN & 0x30)) - IRQFlag = 0x00; + if(!(NMITIMEEN & 0x30)) + IRQFlag = 0x00; - CPU_SetNMI(NMIFlag & NMITIMEEN & 0x80); - CPU_SetIRQ(IRQFlag); + CPU_SetNMI(NMIFlag & NMITIMEEN & 0x80); + CPU_SetIRQ(IRQFlag); - SNES_DBG("[SNES] Write NMITIMEEN: 0x%02x --- scanline=%u, LineCounter=%u, LinePhase=%u\n", V, scanline, LineCounter, LinePhase); + SNES_SetEventNT(SNES_EVENT_PPU_LINEIRQ, PPU_UpdateLineIRQ((InHDMA != 0x80000000U) ? InHDMA : CPUM.timestamp)); + } } static DEFWRITE(Write_HTIME) // $4207 and $4208 @@ -2016,16 +2313,18 @@ static DEFWRITE(Write_HTIME) // $4207 and $4208 CPUM.timestamp += MEMCYC_FAST; // const unsigned shift = (~A & 1) << 3; - unsigned New_HTime = HTime; + const unsigned Old_HTime = HTime; - New_HTime &= 0xFF00 >> shift; - New_HTime |= V << shift; - New_HTime &= 0x1FF; + HTime &= 0xFF00 >> shift; + HTime |= V << shift; + HTime &= 0x1FF; - if(New_HTime != HTime) - SNES_DBG("[SNES] HTIME Changed: new=0x%04x(old=0x%04x) --- scanline=%u, LineCounter=%u, LinePhase=%u\n", New_HTime, HTime, scanline, LineCounter, LinePhase); + if(HTime != Old_HTime) + { + SNES_DBG("[SNES] HTIME Changed: new=0x%04x(old=0x%04x) --- scanline=%u, LineCounter=%u, LinePhase=%u -- %u\n", HTime, Old_HTime, scanline, LineCounter, LinePhase, (CPUM.timestamp - LineStartTS) >> 2); - HTime = New_HTime; + SNES_SetEventNT(SNES_EVENT_PPU_LINEIRQ, PPU_UpdateLineIRQ((InHDMA != 0x80000000U) ? InHDMA : CPUM.timestamp)); + } } static DEFWRITE(Write_VTIME) // $4209 and $420A @@ -2033,40 +2332,35 @@ static DEFWRITE(Write_VTIME) // $4209 and $420A CPUM.timestamp += MEMCYC_FAST; // const unsigned shift = (~A & 1) << 3; - unsigned New_VTime = VTime; + const unsigned Old_VTime = VTime; - New_VTime &= 0xFF00 >> shift; - New_VTime |= V << shift; - New_VTime &= 0x1FF; + VTime &= 0xFF00 >> shift; + VTime |= V << shift; + VTime &= 0x1FF; - if(New_VTime != VTime) + if(VTime != Old_VTime) { - SNES_DBG("[SNES] VTIME Changed: new=0x%04x(old=0x%04x) --- HTIME=0x%04x, scanline=%u, LineCounter=%u, LinePhase=%u -- %u\n", New_VTime, VTime, HTime, scanline, LineCounter, LinePhase, (CPUM.timestamp - LineStartTS)); + SNES_DBG("[SNES] VTIME Changed: new=0x%04x(old=0x%04x) --- HTIME=0x%04x, scanline=%u, LineCounter=%u, LinePhase=%u -- %u\n", VTime, Old_VTime, HTime, scanline, LineCounter, LinePhase, (CPUM.timestamp - LineStartTS) >> 2); -#if 0 - // Kludge for F-1 Grand Prix - if(!LinePhase && LineCounter >= 1088) //(CPUM.timestamp - LineStartTS) < 10) - { - if(!(NMITIMEEN & 0x10) || HTime == 0) - { - if(((NMITIMEEN & 0x20) && scanline == New_VTime) || ((NMITIMEEN & 0x30) == 0x10)) - { - printf("Kludge IRQ: %d\n", scanline); - IRQFlag = 0x80; - CPU_SetIRQ(IRQFlag); - } - } - } -#endif + SNES_SetEventNT(SNES_EVENT_PPU_LINEIRQ, PPU_UpdateLineIRQ((InHDMA != 0x80000000U) ? InHDMA : CPUM.timestamp)); } - - VTime = New_VTime; } static DEFREAD(Read_4210) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return NMIFlag | 0x01; + } + CPUM.timestamp += MEMCYC_FAST; // +#if 1 + // Kludge of doooooom~ + if(MDFN_UNLIKELY(CPUM.timestamp >= events[SNES_EVENT_PPU].event_time) && InHDMA == 0x80000000U) + CPUM.EventHandler(); +#endif + // uint8 ret = NMIFlag | 0x01; NMIFlag = 0x00; @@ -2077,6 +2371,11 @@ static DEFREAD(Read_4210) static DEFREAD(Read_4211) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return IRQFlag; + } + CPUM.timestamp += MEMCYC_FAST; // uint8 ret = IRQFlag; @@ -2091,6 +2390,11 @@ static DEFREAD(Read_4211) static DEFREAD(Read_4212) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return HVBJOY; + } + CPUM.timestamp += MEMCYC_FAST; // return HVBJOY; @@ -2098,6 +2402,11 @@ static DEFREAD(Read_4212) static DEFREAD(Read_4213) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return 0; + } + CPUM.timestamp += MEMCYC_FAST; // SNES_DBG("[PPU] Read 4213\n"); @@ -2113,20 +2422,126 @@ static DEFREAD(Read_4213) // // // -static INLINE void RenderZero(uint32 bound) +static void RenderZero(uint32 bound) { + if(MDFN_UNLIKELY(es->skip)) + { + LineTarget = std::max(LineTarget, bound); + return; + } + while(LineTarget < bound) { - uint32* const out_target = es->surface->pixels + (LineTarget * es->surface->pitchinpix); + const int32 out_line = (LineTarget << es->InterlaceOn) + (es->InterlaceOn & es->InterlaceField); - es->LineWidths[LineTarget] = 2; - out_target[0] = 0; - out_target[1] = 0; + if(MDFN_LIKELY(out_line >= es->DisplayRect.y && out_line < (es->DisplayRect.y + es->DisplayRect.h))) + { + uint32* const out_target = es->surface->pixels + out_line * es->surface->pitchinpix; + + if(MDFN_UNLIKELY(DoHFilter)) + { + const unsigned w = (DoHFilter == &T_DoHFilter || DoHFilter == &T_DoHFilter || DoHFilter == &T_DoHFilter) ? 512 : 256; + + //printf("BORP: %d\n", LineTarget); + + es->LineWidths[out_line] = w; + + for(unsigned i = 0; i < w; i++) + out_target[i] = 0; + } + else + { + es->LineWidths[out_line] = 2; + out_target[0] = 0; + out_target[1] = 0; + } + } LineTarget++; } } +/* +uint32 PPU_UpdateLineIRQ(uint32 timestamp) +{ + uint32 ret = SNES_EVENT_MAXTS; + bool NewIRQThing = false; + + if(NMITIMEEN & 0x30) + { + if((scanline == VTime) || !(NMITIMEEN & 0x20)) + { + if(!(NMITIMEEN & 0x10)) + NewIRQThing = true; + else if(HTime < 340) + { + const int32 td = (timestamp - LineStartTS) - (HTime << 2); + + if(td < 0) + ret = timestamp - td; + else if(td < 4) + { + NewIRQThing = true; + ret = timestamp + 4; + } + } + } + } + + if(NewIRQThing && !IRQThing && !IRQFlag) + { + SNES_DBG("[SNES] IRQ: %d\n", scanline); + IRQFlag = 0x80; + CPU_SetIRQ(IRQFlag); + } + + IRQThing = NewIRQThing; + + return ret; +} +*/ + +uint32 PPU_UpdateLineIRQ(uint32 timestamp) +{ + uint32 ret = SNES_EVENT_MAXTS; + bool NewIRQThing = false; + + if(NMITIMEEN & 0x30) + { + if((scanline == VTime) || !(NMITIMEEN & 0x20)) + { + if(!(NMITIMEEN & 0x10)) + NewIRQThing = true; + else if(HTime < 340) + { + const int32 td = (timestamp - LineStartTS) - (HTime << 2); + + if(td < 0) + ret = timestamp - td; + else if(td < 4) + { + NewIRQThing = true; + ret = timestamp + 4; + } + } + } + } + + if(NewIRQThing && !IRQThing && !IRQFlag) + { + SNES_DBG("[SNES] IRQ: %d, %u\n", scanline, (timestamp - LineStartTS) >> 2); + IRQFlag = 0x80; + CPU_SetIRQ(IRQFlag); + } + + IRQThing = NewIRQThing; + + return ret; +} + + +static const int RenderLineDelay = 512; //64; + uint32 PPU_Update(uint32 timestamp) { if(timestamp < lastts) @@ -2139,46 +2554,19 @@ uint32 PPU_Update(uint32 timestamp) if(LineCounter <= 0) { - LinePhase = !LinePhase; + LinePhase = (LinePhase + 1) % 4; - if(LinePhase) // HBlank begin + if(LinePhase == 0) // HBlank end { - // - // - HVBJOY |= 0x40; - // - // - - if(!VBlank) - { - FetchSpriteData(scanline); - DMA_RunHDMA(); - } - - // - LineCounter += 67 * 4; - } - else // HBlank end - { - scanline = (scanline + 1) % LinesPerFrame; + scanline = (scanline + 1) % (LinesPerFrame + ((~Status[1] >> 7) & ScreenMode & 1)); // LineStartTS = timestamp; - // // - // CPUM.timestamp += 40; HVBJOY &= ~0x40; - // FIXME, HORRIBLE(and stuff) - if(!(NMITIMEEN & 0x10) || HTime < 340) - { - if(((NMITIMEEN & 0x20) && scanline == VTime) || ((NMITIMEEN & 0x30) == 0x10)) - { - SNES_DBG("[SNES] IRQ: %d\n", scanline); - IRQFlag = 0x80; - CPU_SetIRQ(IRQFlag); - } - } + SNES_SetEventNT(SNES_EVENT_PPU_LINEIRQ, PPU_UpdateLineIRQ(timestamp)); + if(JPReadCounter > 0) { if(JPReadCounter == 3) @@ -2192,11 +2580,21 @@ uint32 PPU_Update(uint32 timestamp) // // - if(VBlank && scanline == 0) // VBlank end + if(scanline == 0) // VBlank end { VBlank = false; Status[0] &= ~0xC0; // Reset Time Over and Range Over flags. - + Status[1] ^= 0x80; + // + // + // FIXME: Should technically do this earlier, in vblank. + if(ScreenMode & 0x1) + { + es->InterlaceOn = true; + es->InterlaceField = (bool)(Status[1] & 0x80); + } + es->DisplayRect.y = (PAL ? 0 : 8) << es->InterlaceOn; + es->DisplayRect.h = (PAL ? 239 : 224) << es->InterlaceOn; // // // @@ -2221,6 +2619,7 @@ uint32 PPU_Update(uint32 timestamp) VBlank = true; RenderZero(239); + //assert(es->DisplayRect.y != 0); // // // @@ -2229,6 +2628,8 @@ uint32 PPU_Update(uint32 timestamp) HVBJOY |= 0x80; NMIFlag = 0x80; + SNES_DBG("NMI: %u %u\n", scanline, timestamp); + CPU_SetNMI(NMIFlag & NMITIMEEN & 0x80); if(NMITIMEEN & 0x01) @@ -2242,15 +2643,42 @@ uint32 PPU_Update(uint32 timestamp) if(!(INIDisp & 0x80)) OAM_Addr = (OAMADDL | ((OAMADDH & 0x1) << 8)) << 1; } - + // + LineCounter += RenderLineDelay; + } + else if(LinePhase == 1) + { if(MDFN_LIKELY(!VBlank)) { - if(scanline > 0 && !es->skip) + if(scanline > 0 && scanline < 240 && !es->skip) RenderLine(); } + LineCounter += 534 - RenderLineDelay; + } + else if(LinePhase == 2) + { + CPUM.timestamp += 40; + LineCounter += 1096 - 534; + } + else if(LinePhase == 3) // HBlank begin + { + // // - LineCounter += 274 * 4; + HVBJOY |= 0x40; + // + // + + if(!VBlank) + { + InHDMA = timestamp; + DMA_RunHDMA(); + InHDMA = 0x80000000U; + FetchSpriteData(scanline); + } + + // + LineCounter += 1364 - 1096; } } @@ -2274,8 +2702,13 @@ void PPU_Init(const bool IsPAL) // // // + lastts = 0; + LineStartTS = 0; + + DoHFilter = NULL; PAL = IsPAL; LinesPerFrame = IsPAL ? 312 : 262; + InHDMA = 0x80000000U; Set_B_Handlers(0x00, OBRead_FAST, Write_2100); @@ -2388,7 +2821,7 @@ void PPU_Init(const bool IsPAL) } } -void PPU_SetGetVideoParams(MDFNGI* gi, const bool caspect) +void PPU_SetGetVideoParams(MDFNGI* gi, const bool caspect, const unsigned hfilter) { gi->fb_width = 512; gi->fb_height = 480; // Don't change to less than 480 @@ -2410,6 +2843,33 @@ void PPU_SetGetVideoParams(MDFNGI* gi, const bool caspect) gi->lcm_width = 512; gi->lcm_height = gi->nominal_height * 2; + // + switch(hfilter) + { + default: + assert(0); + break; + + case PPU_HFILTER_NONE: + DoHFilter = NULL; + break; + + case PPU_HFILTER_512: + DoHFilter = T_DoHFilter; + break; + + case PPU_HFILTER_PHR256BLEND: + DoHFilter = T_DoHFilter; + break; + + case PPU_HFILTER_PHR256BLEND_512: + DoHFilter = T_DoHFilter; + break; + + case PPU_HFILTER_512_BLEND: + DoHFilter = T_DoHFilter; + break; + } } void PPU_Kill(void) @@ -2420,6 +2880,8 @@ void PPU_Kill(void) void PPU_Reset(bool powering_up) { + IRQThing = false; + HLatch = 0; VLatch = 0; HLatchReadShift = 0; @@ -2431,10 +2893,13 @@ void PPU_Reset(bool powering_up) Status[0] &= ~0xC0; Status[1] &= ~0xC0; - // FIXME? - scanline = 0; - LinePhase = 0; + // + // Be careful: + scanline = LinesPerFrame - 1; + LinePhase = 3; LineCounter = 1; + // + // VBlank = false; @@ -2501,6 +2966,7 @@ void PPU_Reset(bool powering_up) memset(OAM, 0x00, sizeof(OAM)); memset(OAMHI, 0x00, sizeof(OAMHI)); } + SpriteTileCount = 0; // // @@ -2511,6 +2977,8 @@ void PPU_Reset(bool powering_up) VTime = 0x1FF; } + JPReadCounter = 0; + HVBJOY = 0x00; NMIFlag = 0x00; IRQFlag = 0x00; NMITIMEEN = 0; @@ -2530,6 +2998,7 @@ void PPU_StateAction(StateMem* sm, const unsigned load, const bool data_only) SFVAR(NMITIMEEN), + SFVAR(IRQThing), SFVAR(HTime), SFVAR(VTime), @@ -2618,5 +3087,278 @@ void PPU_StateAction(StateMem* sm, const unsigned load, const bool data_only) } } + +uint16 PPU_PeekVRAM(uint32 addr) +{ + return VRAM[addr & 0x7FFF]; +} + +void PPU_PokeVRAM(uint32 addr, uint16 val) +{ + VRAM[addr & 0x7FFF] = val; +} + +uint16 PPU_PeekCGRAM(uint32 addr) +{ + return CGRAM[addr & 0xFF]; +} + +void PPU_PokeCGRAM(uint32 addr, uint16 val) +{ + CGRAM[addr & 0xFF] = val; +} + +uint8 PPU_PeekOAM(uint32 addr) +{ + return OAM[addr & 0x1FF]; +} + +void PPU_PokeOAM(uint32 addr, uint8 val) +{ + OAM[addr & 0x1FF] = val; +} + +uint8 PPU_PeekOAMHI(uint32 addr) +{ + return OAMHI[addr & 0x1F]; +} + +void PPU_PokeOAMHI(uint32 addr, uint8 val) +{ + OAMHI[addr & 0x1F] = val; +} + +uint32 PPU_GetRegister(const unsigned id, char* const special, const uint32 special_len) +{ + uint32 ret = 0xDEADBEEF; + + switch(id) + { + case PPU_GSREG_NMITIMEEN: + ret = NMITIMEEN; + break; + + case PPU_GSREG_HTIME: + ret = HTime; + break; + + case PPU_GSREG_VTIME: + ret = VTime; + break; + + case PPU_GSREG_NMIFLAG: + ret = NMIFlag; + break; + + case PPU_GSREG_IRQFLAG: + ret = IRQFlag; + break; + + case PPU_GSREG_HVBJOY: + ret = HVBJOY; + break; + + case PPU_GSREG_SCANLINE: + ret = scanline; + break; + // + // + // + + case PPU_GSREG_BGMODE: + ret = BGMode; + break; + + case PPU_GSREG_MOSAIC: + ret = Mosaic; + break; + + case PPU_GSREG_W12SEL: + ret = WMSettings[0]; + break; + + case PPU_GSREG_W34SEL: + ret = WMSettings[1]; + break; + + case PPU_GSREG_WOBJSEL: + ret = WMSettings[2]; + break; + + case PPU_GSREG_WH0: + ret = WindowPos[0][0]; + break; + + case PPU_GSREG_WH1: + ret = WindowPos[0][1]; + break; + + case PPU_GSREG_WH2: + ret = WindowPos[1][0]; + break; + + case PPU_GSREG_WH3: + ret = WindowPos[1][1]; + break; + + case PPU_GSREG_WBGLOG: + ret = WMLogic & 0xFF; + break; + + case PPU_GSREG_WOBJLOG: + ret = WMLogic >> 8; + break; + + case PPU_GSREG_TM: + ret = WMMainEnable; + break; + + case PPU_GSREG_TS: + ret = WMSubEnable; + break; + + case PPU_GSREG_CGWSEL: + ret = CGWSEL; + break; + + case PPU_GSREG_CGADSUB: + ret = CGADSUB; + break; + + case PPU_GSREG_BG1HOFS: + ret = BGHOFS[0]; + break; + + case PPU_GSREG_BG1VOFS: + ret = BGVOFS[0]; + break; + + case PPU_GSREG_BG2HOFS: + ret = BGHOFS[1]; + break; + + case PPU_GSREG_BG2VOFS: + ret = BGVOFS[1]; + break; + + case PPU_GSREG_BG3HOFS: + ret = BGHOFS[2]; + break; + + case PPU_GSREG_BG3VOFS: + ret = BGVOFS[2]; + break; + + case PPU_GSREG_BG4HOFS: + ret = BGHOFS[3]; + break; + + case PPU_GSREG_BG4VOFS: + ret = BGVOFS[3]; + break; + + // + // + // + case PPU_GSREG_M7SEL: + ret = M7SEL; + break; + + case PPU_GSREG_M7A: + ret = (uint16)M7Matrix[0]; + break; + + case PPU_GSREG_M7B: + ret = (uint16)M7Matrix[1]; + break; + + case PPU_GSREG_M7C: + ret = (uint16)M7Matrix[2]; + break; + + case PPU_GSREG_M7D: + ret = (uint16)M7Matrix[3]; + break; + + case PPU_GSREG_M7X: + ret = M7Center[0] & 0x1FFF; + break; + + case PPU_GSREG_M7Y: + ret = M7Center[1] & 0x1FFF; + break; + + case PPU_GSREG_M7HOFS: + ret = M7HOFS & 0x1FFF; + break; + + case PPU_GSREG_M7VOFS: + ret = M7VOFS & 0x1FFF; + break; + + + case PPU_GSREG_SCREENMODE: + ret = ScreenMode; + break; + } + return ret; +} + +void PPU_SetRegister(const unsigned id, const uint32 value) +{ + switch(id) + { + // TODO + + case PPU_GSREG_HTIME: + HTime = value & 0x1FF; + break; + + case PPU_GSREG_VTIME: + VTime = value & 0x1FF; + break; + // + // + // + case PPU_GSREG_CGADSUB: + CGADSUB = value & 0xFF; + break; + + case PPU_GSREG_BG1HOFS: + BGHOFS[0] = value & 0x3FF; + break; + + case PPU_GSREG_BG1VOFS: + BGVOFS[0] = value & 0x3FF; + break; + + case PPU_GSREG_BG2HOFS: + BGHOFS[1] = value & 0x3FF; + break; + + case PPU_GSREG_BG2VOFS: + BGVOFS[1] = value & 0x3FF; + break; + + case PPU_GSREG_BG3HOFS: + BGHOFS[2] = value & 0x3FF; + break; + + case PPU_GSREG_BG3VOFS: + BGVOFS[2] = value & 0x3FF; + break; + + case PPU_GSREG_BG4HOFS: + BGHOFS[3] = value & 0x3FF; + break; + + case PPU_GSREG_BG4VOFS: + BGVOFS[3] = value & 0x3FF; + break; + + } +} + + } diff --git a/mednafen/snes_faust/ppu.h b/mednafen/snes_faust/ppu.h index a9f1ff6..dafbb04 100644 --- a/mednafen/snes_faust/ppu.h +++ b/mednafen/snes_faust/ppu.h @@ -2,7 +2,7 @@ /* Mednafen Fast SNES Emulation Module */ /******************************************************************************/ /* ppu.h: -** Copyright (C) 2015-2017 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -26,7 +26,16 @@ namespace MDFN_IEN_SNES_FAUST { void PPU_Init(const bool IsPAL) MDFN_COLD; -void PPU_SetGetVideoParams(MDFNGI* gi, const bool caspect) MDFN_COLD; + +enum +{ + PPU_HFILTER_NONE = 0, + PPU_HFILTER_512, + PPU_HFILTER_PHR256BLEND, + PPU_HFILTER_PHR256BLEND_512, + PPU_HFILTER_512_BLEND +}; +void PPU_SetGetVideoParams(MDFNGI* gi, const bool caspect, const unsigned hfilter) MDFN_COLD; void PPU_Kill(void) MDFN_COLD; void PPU_Reset(bool powering_up) MDFN_COLD; void PPU_ResetTS(void); @@ -35,7 +44,78 @@ void PPU_StateAction(StateMem* sm, const unsigned load, const bool data_only); void PPU_StartFrame(EmulateSpecStruct* espec); +uint32 PPU_UpdateLineIRQ(uint32 timestamp) MDFN_HOT; uint32 PPU_Update(uint32 timestamp) MDFN_HOT; +// +// +// +uint16 PPU_PeekVRAM(uint32 addr) MDFN_COLD; +void PPU_PokeVRAM(uint32 addr, uint16 val) MDFN_COLD; + +uint16 PPU_PeekCGRAM(uint32 addr) MDFN_COLD; +void PPU_PokeCGRAM(uint32 addr, uint16 val) MDFN_COLD; + +uint8 PPU_PeekOAM(uint32 addr) MDFN_COLD; +void PPU_PokeOAM(uint32 addr, uint8 val) MDFN_COLD; + +uint8 PPU_PeekOAMHI(uint32 addr) MDFN_COLD; +void PPU_PokeOAMHI(uint32 addr, uint8 val) MDFN_COLD; +// +// +// +enum +{ + PPU_GSREG_NMITIMEEN, + PPU_GSREG_HTIME, + PPU_GSREG_VTIME, + PPU_GSREG_NMIFLAG, + PPU_GSREG_IRQFLAG, + PPU_GSREG_HVBJOY, + + PPU_GSREG_SCANLINE, + + PPU_GSREG_BGMODE, + PPU_GSREG_MOSAIC, + + PPU_GSREG_W12SEL, + PPU_GSREG_W34SEL, + PPU_GSREG_WOBJSEL, + PPU_GSREG_WH0, + PPU_GSREG_WH1, + PPU_GSREG_WH2, + PPU_GSREG_WH3, + PPU_GSREG_WBGLOG, + PPU_GSREG_WOBJLOG, + PPU_GSREG_TM, + PPU_GSREG_TS, + + PPU_GSREG_CGWSEL, + PPU_GSREG_CGADSUB, + + PPU_GSREG_BG1HOFS, + PPU_GSREG_BG1VOFS, + PPU_GSREG_BG2HOFS, + PPU_GSREG_BG2VOFS, + PPU_GSREG_BG3HOFS, + PPU_GSREG_BG3VOFS, + PPU_GSREG_BG4HOFS, + PPU_GSREG_BG4VOFS, + + PPU_GSREG_M7SEL, + PPU_GSREG_M7A, + PPU_GSREG_M7B, + PPU_GSREG_M7C, + PPU_GSREG_M7D, + PPU_GSREG_M7X, + PPU_GSREG_M7Y, + PPU_GSREG_M7HOFS, + PPU_GSREG_M7VOFS, + + PPU_GSREG_SCREENMODE, +}; + +uint32 PPU_GetRegister(const unsigned id, char* const special, const uint32 special_len) MDFN_COLD; +void PPU_SetRegister(const unsigned id, const uint32 value) MDFN_COLD; } diff --git a/mednafen/snes_faust/snes.cpp b/mednafen/snes_faust/snes.cpp index 7be0281..21da3d3 100644 --- a/mednafen/snes_faust/snes.cpp +++ b/mednafen/snes_faust/snes.cpp @@ -2,7 +2,7 @@ /* Mednafen Fast SNES Emulation Module */ /******************************************************************************/ /* snes.cpp: -** Copyright (C) 2015-2017 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -41,7 +41,7 @@ static bool SpecEx, SpecExSoundToo; static MemoryStream* SpecExSS = NULL; static int32 SpecExAudioExpected; -static void EventReset(void); +static void InitEvents(void) MDFN_COLD; template @@ -105,6 +105,11 @@ bool MemSelect; template static INLINE DEFREAD(OBRead) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return CPUM.mdr; + } + if(cyc >= 0) CPUM.timestamp += cyc; else @@ -144,11 +149,16 @@ static std::bitset<0x20000> WRAMWritten; // for debugging template static DEFREAD(WRAMRead) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return WRAM[A & mask]; + } + CPUM.timestamp += MEMCYC_SLOW; #ifdef SNES_DBG_ENABLE - if(!WRAMWritten[A & mask]) - SNES_DBG("[SNES] Read from uninitialized WRAM at 0x%08x!\n", A & mask); + //if(!WRAMWritten[A & mask]) + // SNES_DBG("[SNES] Read from uninitialized WRAM at 0x%08x!\n", A & mask); #endif return WRAM[A & mask]; @@ -234,6 +244,11 @@ static DEFWRITE(ICRegsWrite) static DEFREAD(Read_4214) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DivQuotient >> 0; + } + CPUM.timestamp += MEMCYC_FAST; return DivQuotient >> 0; @@ -241,6 +256,11 @@ static DEFREAD(Read_4214) static DEFREAD(Read_4215) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return DivQuotient >> 8; + } + CPUM.timestamp += MEMCYC_FAST; return DivQuotient >> 8; @@ -248,6 +268,11 @@ static DEFREAD(Read_4215) static DEFREAD(Read_4216) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return MultProduct >> 0; + } + CPUM.timestamp += MEMCYC_FAST; return MultProduct >> 0; @@ -255,6 +280,11 @@ static DEFREAD(Read_4216) static DEFREAD(Read_4217) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return MultProduct >> 8; + } + CPUM.timestamp += MEMCYC_FAST; return MultProduct >> 8; @@ -301,6 +331,11 @@ static DEFWRITE(Write_2183) static DEFREAD(Read_2180) { + if(MDFN_UNLIKELY(DBG_InHLRead)) + { + return WRAM[WMAddress]; + } + uint8 ret; CPUM.timestamp += MEMCYC_FAST; @@ -350,7 +385,7 @@ static MDFN_COLD void Reset(bool powering_up) // CPU_Reset(powering_up); - EventReset(); + InitEvents(); ForceEventUpdates(0); } @@ -401,7 +436,7 @@ static MDFN_COLD void Cleanup(void) } } -static MDFN_COLD void Load(GameFile* gf) +static MDFN_COLD void LoadReal(GameFile* gf) { if(SPCReader::TestMagic(gf->stream)) { @@ -423,6 +458,8 @@ static MDFN_COLD void Load(GameFile* gf) MDFNMP_Init(8192, (1U << 24) / 8192); MDFNMP_RegSearchable(0x7E0000, 0x20000); + DBG_Init(); + CPU_Init(); memset(CPUM.ReadFuncs, 0, sizeof(CPUM.ReadFuncs)); @@ -491,7 +528,9 @@ static MDFN_COLD void Load(GameFile* gf) Player_Init(1, snsf_loader->tags.GetTag("game"), snsf_loader->tags.GetTag("artist"), snsf_loader->tags.GetTag("copyright"), std::vector({ snsf_loader->tags.GetTag("title") })); } - const bool IsPAL = CART_Init(snsf_loader ? &snsf_loader->ROM_Data : gf->stream, EmulatedSNES_Faust.MD5); + const int32 cx4_ocmultiplier = ((MDFN_GetSettingUI("snes_faust.cx4.clock_rate") << 16) + 50) / 100; + const int32 superfx_ocmultiplier = 1U << 16; //((MDFN_GetSettingUI("snes_faust.superfx.clock_rate") << 16) + 50) / 100; + const bool IsPAL = CART_Init(snsf_loader ? &snsf_loader->ROM_Data : gf->stream, EmulatedSNES_Faust.MD5, cx4_ocmultiplier, superfx_ocmultiplier); CART_LoadNV(); DMA_Init(); @@ -504,13 +543,27 @@ static MDFN_COLD void Load(GameFile* gf) EmulatedSNES_Faust.MasterClock = IsPAL ? MDFN_MASTERCLOCK_FIXED(21281370.0) : MDFN_MASTERCLOCK_FIXED(21477272.7); PPU_Init(IsPAL); - PPU_SetGetVideoParams(&EmulatedSNES_Faust, MDFN_GetSettingB("snes_faust.correct_aspect")); + PPU_SetGetVideoParams(&EmulatedSNES_Faust, MDFN_GetSettingB("snes_faust.correct_aspect"), MDFN_GetSettingUI("snes_faust.h_filter")); APU_Init(IsPAL); Reset(true); } +static MDFN_COLD void Load(GameFile* gf) +{ + try + { + LoadReal(gf); + } + catch(...) + { + Cleanup(); + + throw; + } +} + static MDFN_COLD void CloseGame(void) { if(!snsf_loader && !spc_reader) @@ -563,22 +616,12 @@ static MDFN_COLD void CheatMemWrite(uint32 A, uint8 V) *p = V; } -struct event_list_entry -{ - uint32 which; - uint32 event_time; - event_list_entry *prev; - event_list_entry *next; -}; - -static event_list_entry events[SNES_EVENT__COUNT]; +event_list_entry events[SNES_EVENT__COUNT]; -static void EventReset(void) +static MDFN_COLD void InitEvents(void) { for(unsigned i = 0; i < SNES_EVENT__COUNT; i++) { - events[i].which = i; - if(i == SNES_EVENT__SYNFIRST) events[i].event_time = 0; else if(i == SNES_EVENT__SYNLAST) @@ -589,31 +632,31 @@ static void EventReset(void) events[i].prev = (i > 0) ? &events[i - 1] : NULL; events[i].next = (i < (SNES_EVENT__COUNT - 1)) ? &events[i + 1] : NULL; } -} -//static void RemoveEvent(event_list_entry *e) -//{ -// e->prev->next = e->next; -// e->next->prev = e->prev; -//} + events[SNES_EVENT_PPU].event_handler = PPU_Update; + events[SNES_EVENT_PPU_LINEIRQ].event_handler = PPU_UpdateLineIRQ; + events[SNES_EVENT_DMA_DUMMY].event_handler = DMA_Update; + events[SNES_EVENT_CART].event_handler = CART_GetEventHandler(); +} static void RebaseTS(const uint32 timestamp) { - for(unsigned i = 0; i < SNES_EVENT__COUNT; i++) + for(unsigned i = SNES_EVENT__SYNFIRST + 1; i < SNES_EVENT__SYNLAST; i++) { - if(i == SNES_EVENT__SYNFIRST || i == SNES_EVENT__SYNLAST) - continue; - assert(events[i].event_time > timestamp); events[i].event_time -= timestamp; } + CART_AdjustTS(-timestamp); + CPUM.next_event_ts = events[SNES_EVENT__SYNFIRST].next->event_time; } void SNES_SetEventNT(const int type, const uint32 next_timestamp) { +#ifdef SNES_DBG_ENABLE assert(type > SNES_EVENT__SYNFIRST && type < SNES_EVENT__SYNLAST); +#endif event_list_entry *e = &events[type]; if(next_timestamp < e->event_time) @@ -660,15 +703,17 @@ void SNES_SetEventNT(const int type, const uint32 next_timestamp) e->event_time = next_timestamp; } - CPUM.next_event_ts = events[SNES_EVENT__SYNFIRST].next->event_time; // & Running); + CPUM.next_event_ts = events[SNES_EVENT__SYNFIRST].next->event_time & CPUM.running_mask; } // Called from debug.cpp too. void ForceEventUpdates(const uint32 timestamp) { - SNES_SetEventNT(SNES_EVENT_PPU, PPU_Update(timestamp)); - SNES_SetEventNT(SNES_EVENT_DMA_DUMMY, DMA_Update(timestamp)); - + for(unsigned i = SNES_EVENT__SYNFIRST + 1; i < SNES_EVENT__SYNLAST; i++) + { + SNES_SetEventNT(i, events[i].event_handler(timestamp)); + } + // CPUM.next_event_ts = events[SNES_EVENT__SYNFIRST].next->event_time; } @@ -681,24 +726,12 @@ void CPU_Misc::EventHandler(void) event_list_entry *prev = e->prev; uint32 nt; - switch(e->which) - { - default: abort(); - - case SNES_EVENT_PPU: - nt = PPU_Update(e->event_time); - break; - - case SNES_EVENT_DMA_DUMMY: - nt = DMA_Update(e->event_time); - break; - - } + nt = e->event_handler(e->event_time); //#if SNES_EVENT_SYSTEM_CHECKS assert(nt > e->event_time); //#endif - SNES_SetEventNT(e->which, nt); + SNES_SetEventNT(/*e->which*/e - events, nt); // Order of events can change due to calling SNES_SetEventNT(), this prev business ensures we don't miss an event due to reordering. e = prev->next; @@ -725,6 +758,52 @@ static void NO_INLINE EmulateReal(EmulateSpecStruct* espec) PPU_StartFrame(espec); +#if 0 + for(unsigned msi = 0; msi < 2; msi++) + { + for(uint32 A = 0; A < (1U << 24); A++) + { + CPUM.timestamp = 0; + const uint32 pts = CPUM.timestamp; + + MemSelect = msi; + CPUM.ReadA(A); + // + const uint32 td = CPUM.timestamp - pts; + const uint8 bank = A >> 16; + const uint16 offs = (uint16)A; + uint32 reqtd = ~0U; + + if(!(bank & 0x40)) + { + if(offs < 0x2000) + reqtd = 8; + else if(offs < 0x4000) + reqtd = 6; + else if(offs < 0x4200) + reqtd = 12; + else if(offs < 0x6000) + reqtd = 6; + else if(offs < 0x8000) + reqtd = 8; + else + reqtd = ((bank & 0x80) && msi) ? 6 : 8; + } + else + reqtd = ((bank & 0x80) && msi) ? 6 : 8; + + if(td != reqtd) + { + printf("0x%06x td=%d reqtd=%d\n", A, td, reqtd); + assert(td == reqtd); + } + } + } + printf("Done\n"); + exit(0); +#endif + + CPU_Run(); uint32 prev = CPUM.timestamp; ForceEventUpdates(CPUM.timestamp); @@ -858,7 +937,7 @@ static void StateAction(StateMem *sm, const unsigned load, const bool data_only) MDFNSS_StateAction(sm, load, data_only, StateRegs, "SNES"); - CPU_StateAction(sm, load, data_only); + CPU_StateAction(sm, load, data_only, "CPU", "CPUCORE"); DMA_StateAction(sm, load, data_only); APU_StateAction(sm, load, data_only); PPU_StateAction(sm, load, data_only); @@ -872,6 +951,54 @@ static void StateAction(StateMem *sm, const unsigned load, const bool data_only) } } +static void SetInput(unsigned port, const char *type, uint8* data) +{ + if(spc_reader) + return; + + INPUT_Set(port, type, data); +} + + +uint32 SNES_GetRegister(const unsigned int id, char* special, const uint32 special_len) +{ + uint32 ret = 0xDEADBEEF; + + switch(id) + { + case SNES_GSREG_MEMSEL: + ret = MemSelect; + break; + + case SNES_GSREG_TS: + ret = CPUM.timestamp; + break; + } + + return ret; +} + +void SNES_SetRegister(const unsigned int id, uint32 value) +{ + switch(id) + { + case SNES_GSREG_MEMSEL: + MemSelect = value & 0x1; + break; + } +} + + +uint8 PeekWRAM(uint32 addr) +{ + return WRAM[addr & 0x1FFFF]; +} + +void PokeWRAM(uint32 addr, uint8 val) +{ + WRAM[addr & 0x1FFFF] = val; +} + static const FileExtensionSpecStruct KnownExtensions[] = { { ".smc", 0, "Super Magicom ROM Image" }, @@ -882,6 +1009,17 @@ static const FileExtensionSpecStruct KnownExtensions[] = { NULL, 0, NULL } }; +static const MDFNSetting_EnumList HFilter_List[] = +{ + { "none", PPU_HFILTER_NONE, gettext_noop("None") }, + { "512", PPU_HFILTER_512, gettext_noop("Force 512."), gettext_noop("Double width of line if it's 256.") }, + { "phr256blend", PPU_HFILTER_PHR256BLEND, gettext_noop("Pseudo-hires halve-blend."), gettext_noop("Blend line down to 256 pixels if it's pseudo-hires.") }, + { "phr256blend_512", PPU_HFILTER_PHR256BLEND_512, gettext_noop("Pseudo-hires halve-blend and force 512."), gettext_noop("Blend line down to 256 pixels if it's pseudo-hires. After, double width of line if it's 256.") }, + { "512_blend", PPU_HFILTER_512_BLEND, gettext_noop("Force 512 and blend."), gettext_noop("Double width of line if it's 256. After, blend line.") }, + + { NULL, 0 }, +}; + static const MDFNSetting Settings[] = { { "snes_faust.resamp_quality", MDFNSF_NOFLAGS, gettext_noop("Sound quality."), gettext_noop("Higher values correspond to better SNR and better preservation of higher frequencies(\"brightness\"), at the cost of increased computational complexity and a negligible increase in latency.\n\nHigher values will also slightly increase the probability of sample clipping(relevant if Mednafen's volume control settings are set too high), due to increased (time-domain) ringing."), MDFNST_INT, "3", "0", "5" }, @@ -895,6 +1033,11 @@ static const MDFNSetting Settings[] = { "snes_faust.correct_aspect", MDFNSF_NOFLAGS, gettext_noop("Correct aspect ratio."), NULL, MDFNST_BOOL, "1" }, + { "snes_faust.h_filter", MDFNSF_NOFLAGS, gettext_noop("Horizontal blending/doubling filter."), NULL, MDFNST_ENUM, "none", NULL, NULL, NULL, NULL, HFilter_List }, + + { "snes_faust.cx4.clock_rate", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("CX4 clock rate, specified in percentage of normal."), gettext_noop("Overclocking the CX4 will cause or worsen attract mode desynchronization."), MDFNST_UINT, "100", "100", "500" }, + // TODO: { "snes_faust.superfx.clock_rate", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Super FX clock rate, specified in percentage of normal."), gettext_noop("Overclocking the Super FX will cause or worsen attract mode desynchronization."), MDFNST_UINT, "100", "100", "500" }, + { NULL } }; @@ -920,12 +1063,13 @@ MDFNGI EmulatedSNES_Faust = "Super Nintendo Entertainment System/Super Famicom", KnownExtensions, MODPRIO_INTERNAL_LOW, - //#ifdef WANT_DEBUGGER - //&SNES_DBGInfo, - //#else + #ifdef SNES_DBG_ENABLE + &DBG_DBGInfo, + #else NULL, - //#endif + #endif INPUT_PortInfo, + NULL, Load, TestMagic, NULL, @@ -947,7 +1091,7 @@ MDFNGI EmulatedSNES_Faust = StateAction, Emulate, NULL, - INPUT_Set, + SetInput, NULL, DoSimpleCommand, NULL, diff --git a/mednafen/snes_faust/snes.h b/mednafen/snes_faust/snes.h index 86d6983..df7e9d5 100644 --- a/mednafen/snes_faust/snes.h +++ b/mednafen/snes_faust/snes.h @@ -2,7 +2,7 @@ /* Mednafen Fast SNES Emulation Module */ /******************************************************************************/ /* snes.h: -** Copyright (C) 2015-2016 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -19,8 +19,8 @@ ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __MDFN_SNESFAST_SNES_H -#define __MDFN_SNESFAST_SNES_H +#ifndef __MDFN_SNES_FAUST_SNES_H +#define __MDFN_SNES_FAUST_SNES_H #pragma GCC optimize ("unroll-loops") @@ -33,7 +33,7 @@ #define MEMCYC_SLOW 8 #define MEMCYC_XSLOW 12 -#if 0 +#if defined(WANT_DEBUGGER) && defined(MDFN_ENABLE_DEV_BUILD) #define SNES_DBG_ENABLE 1 #define SNES_DBG(s, ...) printf(s, ## __VA_ARGS__) #else @@ -41,6 +41,7 @@ #endif #include "cpu.h" +#include "debug.h" namespace MDFN_IEN_SNES_FAUST { @@ -75,21 +76,69 @@ static INLINE void Set_A_Handlers(uint32 A1, readfunc read_handler, writefunc wr void DMA_InitHDMA(void) MDFN_HOT; void DMA_RunHDMA(void) MDFN_HOT; -void ForceEventUpdates(const uint32 timestamp); +typedef uint32 (*snes_event_handler)(const uint32 timestamp); + +struct event_list_entry +{ + uint32 event_time; + event_list_entry *prev; + event_list_entry *next; + snes_event_handler event_handler; +}; enum { SNES_EVENT__SYNFIRST = 0, SNES_EVENT_PPU, + SNES_EVENT_PPU_LINEIRQ, SNES_EVENT_DMA_DUMMY, + SNES_EVENT_CART, SNES_EVENT__SYNLAST, SNES_EVENT__COUNT, }; #define SNES_EVENT_MAXTS 0x20000000 + +extern event_list_entry events[SNES_EVENT__COUNT]; + +void ForceEventUpdates(const uint32 timestamp); + void SNES_SetEventNT(const int type, const uint32 next_timestamp) MDFN_HOT; +// +// +// +enum +{ + DMA_GSREG_DMAENABLE, + DMA_GSREG_HDMAENABLE, + DMA_GSREG_HDMAENABLEM, + + DMA_GSREG_CHN_CONTROL, + DMA_GSREG_CHN_BBUSADDR, + DMA_GSREG_CHN_ABUSADDR, + DMA_GSREG_CHN_ABUSBANK, + DMA_GSREG_CHN_INDIRBANK, + DMA_GSREG_CHN_COUNT_INDIRADDR, + DMA_GSREG_CHN_TABLEADDR, + DMA_GSREG_CHN_LINECOUNTER, + DMA_GSREG_CHN_UNKNOWN, + DMA_GSREG_CHN_OFFSET, + DMA_GSREG_CHN_DOTRANSFER, +}; +uint32 DMA_GetRegister(const unsigned id, char* const special, const uint32 special_len) MDFN_COLD; +void DMA_SetRegister(const unsigned id, const uint32 value) MDFN_COLD; + +enum +{ + SNES_GSREG_MEMSEL, + SNES_GSREG_TS +}; +uint32 SNES_GetRegister(const unsigned int id, char* special, const uint32 special_len) MDFN_COLD; +void SNES_SetRegister(const unsigned int id, uint32 value) MDFN_COLD; +uint8 PeekWRAM(uint32 addr) MDFN_COLD; +void PokeWRAM(uint32 addr, uint8 val) MDFN_COLD; } #endif diff --git a/mednafen/snes_faust/spc700.inc b/mednafen/snes_faust/spc700.inc index 413508a..20faeed 100644 --- a/mednafen/snes_faust/spc700.inc +++ b/mednafen/snes_faust/spc700.inc @@ -58,6 +58,8 @@ class SPC700 final case GSREG_PSW: return PSW; case GSREG_SP: return SP; } + + return 0xDEADBEEF; } INLINE void SetRegister(unsigned which, unsigned value) diff --git a/mednafen/sound/SwiftResampler.cpp b/mednafen/sound/SwiftResampler.cpp index 2f30589..ea8bbc8 100644 --- a/mednafen/sound/SwiftResampler.cpp +++ b/mednafen/sound/SwiftResampler.cpp @@ -621,6 +621,30 @@ SwiftResampler::SwiftResampler(double input_rate, double output_rate, double rat debias_multiplier = 0; MDFN_indent(-1); + // + // + // +#if 0 + fprintf(stderr, " { "); + + for(unsigned phase = 0; phase < NumPhases; phase++) + { + fprintf(stderr, "%u, ", PhaseStep[phase]); + } + fprintf(stderr, "},\n"); + fprintf(stderr, " {{\n"); + for(unsigned phase = 0; phase < NumPhases; phase++) + { + fprintf(stderr, " {"); + for(unsigned i = 0; i < NumCoeffs; i++) + { + fprintf(stderr, " %d, ", FIR_ENTRY(0, phase, i)); + } + fprintf(stderr, " },\n"); + } + fprintf(stderr, " }}\n"); + +#endif } } diff --git a/mednafen/ss/cart.h b/mednafen/ss/cart.h index 4ba51e7..85caf3a 100644 --- a/mednafen/ss/cart.h +++ b/mednafen/ss/cart.h @@ -71,24 +71,29 @@ static INLINE void CART_CS2_Read16_DB(uint32 A, uint16* DB) { extern CartInfo C static INLINE void CART_CS2_Write8_DB(uint32 A, uint16* DB) { extern CartInfo Cart; Cart.CS2M_RW[(A >> 1) & 0x1F].Write8 (A, DB); } static INLINE void CART_CS2_Write16_DB(uint32 A, uint16* DB) { extern CartInfo Cart; Cart.CS2M_RW[(A >> 1) & 0x1F].Write16(A, DB); } +// +// Don't change the values for existing cart types, or a save state sanity check will break. +// enum { - CART__RESERVED = -1, - CART_NONE = 0, - CART_BACKUP_MEM, - CART_EXTRAM_1M, - CART_EXTRAM_4M, + CART__RESERVED = -1, + CART_NONE = 0x000, - CART_KOF95, - CART_ULTRAMAN, + CART_BACKUP_MEM = 0x100, - CART_AR4MP, + CART_EXTRAM_1M = 0x200, + CART_EXTRAM_4M = 0x201, - CART_CS1RAM_16M, + CART_KOF95 = 0x300, + CART_ULTRAMAN = 0x301, - CART_NLMODEM, + CART_AR4MP = 0x400, - CART_MDFN_DEBUG + CART_CS1RAM_16M = 0x500, + + CART_NLMODEM = 0x600, + + CART_MDFN_DEBUG = 0xF00 }; void CART_Init(const int cart_type, Stream* rom_stream) MDFN_COLD; diff --git a/mednafen/ss/cart/debug.cpp b/mednafen/ss/cart/debug.cpp index 81d1783..d8a44e8 100644 --- a/mednafen/ss/cart/debug.cpp +++ b/mednafen/ss/cart/debug.cpp @@ -39,7 +39,7 @@ static void Debug_RW_DB(uint32 A, uint16* DB) { if(A == 0x02100001) { -#ifdef MDFN_SS_DEV_BUILD +#ifdef MDFN_ENABLE_DEV_BUILD fputc(*DB, stderr); fflush(stderr); #endif diff --git a/mednafen/ss/cdb.cpp b/mednafen/ss/cdb.cpp index 0916fce..5b5d48c 100644 --- a/mednafen/ss/cdb.cpp +++ b/mednafen/ss/cdb.cpp @@ -1005,7 +1005,7 @@ static bool FLS_Run(void) FLS_READ(&FLS.record[0], 1); if(!FLS.record[0]) continue; - FLS_READ(&FLS.record[1], FLS.record[0] - 1); + FLS_READ(&FLS.record[1], (unsigned)(FLS.record[0] - 1)); if(FLS.finfo_offs < 256) { @@ -1265,10 +1265,97 @@ static INLINE void RecalcIRQOut(void) void CDB_Reset(bool powering_up) { + if(powering_up) + { + // + // + // + GetSecLen = 0; + PutSecLen = 0; + + AuthDiscType = 0; + + HIRQ = 0; + HIRQ_Mask = 0; + memset(CData, 0x00, sizeof(CData)); + memset(Results, 0x00, sizeof(Results)); + CommandPending = false; + SWResetHIRQDeferred = 0; + SWResetPending = false; + + CDDevConn = 0; + LastBufDest = 0; + + memset(Buffers, 0x00, sizeof(Buffers)); + memset(Filters, 0x00, sizeof(Filters)); + memset(Partitions, 0x00, sizeof(Partitions)); + FirstFreeBuf = 0; + FreeBufferCount = 0; + memset(&FADSearch, 0x00, sizeof(FADSearch)); + + CalcedActualSize = 0; + //static bool TrayOpen; + //static CDInterface* Cur_CDIF; + //static CDUtility::TOC toc; + //static sscpu_timestamp_t lastts; + CommandPhase = 0; + CommandClockCounter = 0; + //static uint32 CDB_ClockRatio; + + memset(&CTR, 0x00, sizeof(CTR)); + memset(&DT, 0x00, sizeof(DT)); + + StandbyTime = 0; + ECCEnable = 0; + RetryCount = 0; + ResultsRead = 0; + SeekIndexPhase = 0; + CurSector = 0; + DrivePhase = 0; + DriveCounter = 0; + PeriodicIdleCounter = 0; + + PlayRepeatCounter = 0; + CurPlayRepeat = 0; + + CurPlayStart = 0; + CurPlayEnd = 0; + PlayEndIRQType = 0; + + PlayCmdStartPos = 0; + PlayCmdEndPos = 0; + PlayCmdRepCnt = 0; + + memset(CDDABuf, 0x00, sizeof(CDDABuf)); + CDDABuf_RP = 0; + CDDABuf_WP = 0; + CDDABuf_Count = 0; + + memset(SecPreBuf, 0x00, sizeof(SecPreBuf)); + SecPreBuf_In = 0; + memset(TOC_Buffer, 0x00, sizeof(TOC_Buffer)); + + memset(&CurPosInfo, 0x00, sizeof(CurPosInfo)); + memset(SubCodeQBuf, 0x00, sizeof(SubCodeQBuf)); + memset(SubCodeRWBuf, 0x00, sizeof(SubCodeRWBuf)); + memset(SubQBuf, 0x00, sizeof(SubQBuf)); + memset(SubQBuf_Safe, 0x00, sizeof(SubQBuf_Safe)); + SubQBuf_Safe_Valid = false; + + memset(FileInfo, 0x00, sizeof(FileInfo)); + FileInfoValid = false; + memset(&RootDirInfo, 0x00, sizeof(RootDirInfo)); + RootDirInfoValid = false; + + memset(&FLS, 0x00, sizeof(FLS)); + } + // + // HIRQ = 0; HIRQ_Mask = 0; RecalcIRQOut(); - + // + // CDB_ResetCD(); } @@ -1887,7 +1974,7 @@ static void Drive_Run(int64 clocks) else { const unsigned start_track = std::min(toc.last_track, std::max(toc.first_track, (CurPlayStart >> 8) & 0xFF)); - const unsigned start_index = std::min(99, std::max(1, CurPlayStart & 0xFF)); + //const unsigned start_index = std::min(99, std::max(1, CurPlayStart & 0xFF)); end_met |= (CurPosInfo.tno < start_track); //|| (CurPosInfo.tno == start_track && CurPosInfo.idx < start_index); } diff --git a/mednafen/ss/db.cpp b/mednafen/ss/db.cpp index 026c51f..3053ea8 100644 --- a/mednafen/ss/db.cpp +++ b/mednafen/ss/db.cpp @@ -2,7 +2,7 @@ /* Mednafen Sega Saturn Emulation Module */ /******************************************************************************/ /* db.cpp: -** Copyright (C) 2016-2017 Mednafen Team +** Copyright (C) 2016-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -19,6 +19,16 @@ ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/* + Grandia could use full cache emulation to fix a hang at the end of disc 1, but + it glitches graphically during gameplay with it enabled, possibly from + VDP1 drawing completing too fast relative to the CPU... Also it makes + emulator CPU usage too high. + + Lost World(Jurassic Park) could use full cache emulation to fix some disappearing background graphics(at least mostly), but + it makes emulator CPU usage borderline too high. +*/ + #include #include @@ -34,150 +44,261 @@ static const struct { uint8 id[16]; unsigned area; + const char* game_name; } regiondb[] = { - { { 0x10, 0x8f, 0xe1, 0xaf, 0x55, 0x5a, 0x95, 0x42, 0x04, 0x85, 0x7e, 0x98, 0x8c, 0x53, 0x6a, 0x31, }, SMPC_AREA_EU_PAL }, // Preview Sega Saturn Vol. 1 (Europe) - { { 0xed, 0x4c, 0x0b, 0x87, 0x35, 0x37, 0x86, 0x76, 0xa0, 0xf6, 0x32, 0xc6, 0xa4, 0xc3, 0x99, 0x88, }, SMPC_AREA_EU_PAL }, // Primal Rage (Europe) (En,Fr,De,Es,It,Pt) - { { 0x15, 0xfc, 0x3a, 0x82, 0x16, 0xa9, 0x85, 0xa5, 0xa8, 0xad, 0x30, 0xaf, 0x9a, 0xff, 0x03, 0xa9, }, SMPC_AREA_JP }, // Race Drivin' (Japan) (2M) - { { 0xe1, 0xdd, 0xfd, 0xa1, 0x8b, 0x47, 0x02, 0x21, 0x36, 0x1e, 0x5a, 0xae, 0x20, 0xc0, 0x59, 0x9f, }, SMPC_AREA_CSA_NTSC }, // Riven - A Sequencia de Myst (Brazil) (Disc 1) - { { 0xbf, 0x5f, 0xf8, 0x5f, 0xf2, 0x0c, 0x35, 0xf6, 0xc9, 0x8d, 0x03, 0xbc, 0x34, 0xd9, 0xda, 0x7f, }, SMPC_AREA_CSA_NTSC }, // Riven - A Sequencia de Myst (Brazil) (Disc 2) - { { 0x98, 0xb6, 0x6e, 0x09, 0xe6, 0xdc, 0x30, 0xe6, 0x55, 0xdb, 0x85, 0x01, 0x33, 0x0c, 0x0b, 0x9c, }, SMPC_AREA_CSA_NTSC }, // Riven - A Sequencia de Myst (Brazil) (Disc 3) - { { 0xa2, 0x34, 0xb0, 0xb9, 0xaa, 0x47, 0x74, 0x1f, 0xd4, 0x1e, 0x35, 0xda, 0x3d, 0xe7, 0x4d, 0xe3, }, SMPC_AREA_CSA_NTSC }, // Riven - A Sequencia de Myst (Brazil) (Disc 4) - { { 0xf7, 0xe9, 0x23, 0x0a, 0x9e, 0x92, 0xf1, 0x93, 0x16, 0x43, 0xf8, 0x6c, 0xe8, 0x21, 0x50, 0x66, }, SMPC_AREA_JP }, // Sega International Victory Goal (Japan) (5M) - { { 0x64, 0x75, 0x25, 0x0c, 0xa1, 0x9b, 0x6c, 0x5e, 0x4e, 0xa0, 0x6d, 0x69, 0xd9, 0x0f, 0x32, 0xca, }, SMPC_AREA_EU_PAL }, // Virtua Racing (Europe) - { { 0x0d, 0xe3, 0xfa, 0xfb, 0x2b, 0xb9, 0x6d, 0x79, 0xe0, 0x3a, 0xb7, 0x6d, 0xcc, 0xbf, 0xb0, 0x2c, }, SMPC_AREA_JP }, // Virtua Racing (Japan) - { { 0x6b, 0x29, 0x33, 0xfc, 0xdd, 0xad, 0x8e, 0x0d, 0x95, 0x81, 0xa6, 0xee, 0xfd, 0x90, 0x4b, 0x43, }, SMPC_AREA_EU_PAL }, // Winter Heat (Europe) (Demo) - { { 0x73, 0x91, 0x4b, 0xe1, 0xad, 0x4d, 0xaf, 0x69, 0xc3, 0xeb, 0xb8, 0x43, 0xee, 0x3e, 0xb5, 0x09, }, SMPC_AREA_EU_PAL }, // WWF WrestleMania - The Arcade Game (Europe) (Demo) + { { 0x10, 0x8f, 0xe1, 0xaf, 0x55, 0x5a, 0x95, 0x42, 0x04, 0x85, 0x7e, 0x98, 0x8c, 0x53, 0x6a, 0x31, }, SMPC_AREA_EU_PAL, "Preview Sega Saturn Vol. 1 (Europe)" }, + { { 0xed, 0x4c, 0x0b, 0x87, 0x35, 0x37, 0x86, 0x76, 0xa0, 0xf6, 0x32, 0xc6, 0xa4, 0xc3, 0x99, 0x88, }, SMPC_AREA_EU_PAL, "Primal Rage (Europe)" }, + { { 0x15, 0xfc, 0x3a, 0x82, 0x16, 0xa9, 0x85, 0xa5, 0xa8, 0xad, 0x30, 0xaf, 0x9a, 0xff, 0x03, 0xa9, }, SMPC_AREA_JP, "Race Drivin' (Japan)" }, + { { 0xe1, 0xdd, 0xfd, 0xa1, 0x8b, 0x47, 0x02, 0x21, 0x36, 0x1e, 0x5a, 0xae, 0x20, 0xc0, 0x59, 0x9f, }, SMPC_AREA_CSA_NTSC, "Riven - A Sequencia de Myst (Brazil) (Disc 1)" }, + { { 0xbf, 0x5f, 0xf8, 0x5f, 0xf2, 0x0c, 0x35, 0xf6, 0xc9, 0x8d, 0x03, 0xbc, 0x34, 0xd9, 0xda, 0x7f, }, SMPC_AREA_CSA_NTSC, "Riven - A Sequencia de Myst (Brazil) (Disc 2)" }, + { { 0x98, 0xb6, 0x6e, 0x09, 0xe6, 0xdc, 0x30, 0xe6, 0x55, 0xdb, 0x85, 0x01, 0x33, 0x0c, 0x0b, 0x9c, }, SMPC_AREA_CSA_NTSC, "Riven - A Sequencia de Myst (Brazil) (Disc 3)" }, + { { 0xa2, 0x34, 0xb0, 0xb9, 0xaa, 0x47, 0x74, 0x1f, 0xd4, 0x1e, 0x35, 0xda, 0x3d, 0xe7, 0x4d, 0xe3, }, SMPC_AREA_CSA_NTSC, "Riven - A Sequencia de Myst (Brazil) (Disc 4)" }, + { { 0xf7, 0xe9, 0x23, 0x0a, 0x9e, 0x92, 0xf1, 0x93, 0x16, 0x43, 0xf8, 0x6c, 0xe8, 0x21, 0x50, 0x66, }, SMPC_AREA_JP, "Sega International Victory Goal (Japan)" }, + { { 0x64, 0x75, 0x25, 0x0c, 0xa1, 0x9b, 0x6c, 0x5e, 0x4e, 0xa0, 0x6d, 0x69, 0xd9, 0x0f, 0x32, 0xca, }, SMPC_AREA_EU_PAL, "Virtua Racing (Europe)" }, + { { 0x0d, 0xe3, 0xfa, 0xfb, 0x2b, 0xb9, 0x6d, 0x79, 0xe0, 0x3a, 0xb7, 0x6d, 0xcc, 0xbf, 0xb0, 0x2c, }, SMPC_AREA_JP, "Virtua Racing (Japan)" }, + { { 0x6b, 0x29, 0x33, 0xfc, 0xdd, 0xad, 0x8e, 0x0d, 0x95, 0x81, 0xa6, 0xee, 0xfd, 0x90, 0x4b, 0x43, }, SMPC_AREA_EU_PAL, "Winter Heat (Europe) (Demo)" }, + { { 0x73, 0x91, 0x4b, 0xe1, 0xad, 0x4d, 0xaf, 0x69, 0xc3, 0xeb, 0xb8, 0x43, 0xee, 0x3e, 0xb5, 0x09, }, SMPC_AREA_EU_PAL, "WWF WrestleMania - The Arcade Game (Europe) (Demo)" }, }; static const struct { const char* sgid; int cart_type; + const char* game_name; + const char* purpose; uint8 fd_id[16]; } cartdb[] = { -#if 0 - { "T-19708G", CART_NONE }, // Pia Carrot e Youkoso - { "T-32901G", CART_NONE }, // Silhouette Mirage - { "MK-81086", CART_NONE }, // Tomb Raider (Europe) - { "T-7910H", CART_NONE }, // Tomb Raider (USA) - { "T-6010G", CART_NONE }, // Tomb Raiders -#endif - // // // // NetLink Modem TODO: - { "MK-81218", CART_NONE }, // Daytona USA CCE Net Link Edition - { "MK-81071", CART_NONE }, // Duke Nukem 3D - { "T-319-01H", CART_NONE }, // PlanetWeb Browser (multiple versions) - { "MK-81070", CART_NONE }, // Saturn Bomberman - { "MK-81215", CART_NONE }, // Sega Rally Championship Plus NetLink Edition - { "MK-81072", CART_NONE }, // Virtual On NetLink Edition + { "MK-81218", CART_NONE, "Daytona USA CCE Net Link Edition", gettext_noop("Reserved for future modem support.") }, + { "MK-81071", CART_NONE, "Duke Nukem 3D", gettext_noop("Reserved for future modem support.") }, + { "T-319-01H", CART_NONE, "PlanetWeb Browser (multiple versions)", gettext_noop("Reserved for future modem support.") }, + { "MK-81070", CART_NONE, "Saturn Bomberman", gettext_noop("Reserved for future modem support.") }, + { "MK-81215", CART_NONE, "Sega Rally Championship Plus NetLink Edition", gettext_noop("Reserved for future modem support.") }, + { "MK-81072", CART_NONE, "Virtual On NetLink Edition", gettext_noop("Reserved for future modem support.") }, // // // Japanese modem TODO: - { "GS-7106", CART_NONE }, // Dennou Senki Virtual On (SegaNet) - { "GS-7105", CART_NONE }, // Habitat II - { "GS-7101", CART_NONE }, // Pad Nifty - { "GS-7113", CART_NONE }, // Puzzle Bobble 3 (SegaNet) - { "T-14305G", CART_NONE }, // Saturn Bomberman (SegaNet) - { "T-31301G", CART_NONE }, // SegaSaturn Internet Vol. 1 - // - // - // - { "T-16804G", CART_BACKUP_MEM },// Dezaemon 2 + { "GS-7106", CART_NONE, "Dennou Senki Virtual On (SegaNet)", gettext_noop("Reserved for future modem support.") }, + { "GS-7114", CART_NONE, "Dragon's Dream (Japan)", gettext_noop("Reserved for future modem support.") }, + { "GS-7105", CART_NONE, "Habitat II (Japan)", gettext_noop("Reserved for future modem support.") }, + { "GS-7101", CART_NONE, "Pad Nifty (Japan)", gettext_noop("Reserved for future modem support.") }, + { "GS-7113", CART_NONE, "Puzzle Bobble 3 (SegaNet)", gettext_noop("Reserved for future modem support.") }, + { "T-14305G", CART_NONE, "Saturn Bomberman (SegaNet)", gettext_noop("Reserved for future modem support.") }, + { "T-31301G", CART_NONE, "SegaSaturn Internet Vol. 1 (Japan)", gettext_noop("Reserved for future modem support.") }, // // + // ROM carts: + { "MK-81088", CART_KOF95, "King of Fighters '95, The (Europe)", gettext_noop("Game requirement.") }, + { "T-3101G", CART_KOF95, "King of Fighters '95, The (Japan)", gettext_noop("Game requirement.") }, + { "T-13308G", CART_ULTRAMAN, "Ultraman - Hikari no Kyojin Densetsu (Japan)", gettext_noop("Game requirement.") }, // - { "MK-81088", CART_KOF95 }, // The King of Fighters '95 (Europe) - { "T-3101G", CART_KOF95 }, // The King of Fighters '95 - { "T-13308G", CART_ULTRAMAN },// Ultraman: Hikari no Kyojin Densetsu // + // 1MiB RAM cart: + { "T-1521G", CART_EXTRAM_1M, "Astra Superstars (Japan)" }, // Would 4MiB be better? + { "T-9904G", CART_EXTRAM_1M, "Cotton 2 (Japan)" }, + { "T-1217G", CART_EXTRAM_1M, "Cyberbots (Japan)" }, + { "GS-9107", CART_EXTRAM_1M, "Fighter's History Dynamite (Japan)", gettext_noop("Game requirement.") }, + { "T-20109G", CART_EXTRAM_1M, "Friends (Japan)" }, // Would 4MiB be better? + { "T-14411G", CART_EXTRAM_1M, "Groove on Fight (Japan)", gettext_noop("Game requirement.") }, + { "T-7032H-50", CART_EXTRAM_1M, "Marvel Super Heroes (Europe)" }, + { "T-1215G", CART_EXTRAM_1M, "Marvel Super Heroes (Japan)" }, + { "T-3111G", CART_EXTRAM_1M, "Metal Slug (Japan)", gettext_noop("Game requirement.") }, + { "T-22205G", CART_EXTRAM_1M, "NOël 3 (Japan)" }, + { "T-20114G", CART_EXTRAM_1M, "Pia Carrot e Youkoso!! 2 (Japan)" }, + { "T-3105G", CART_EXTRAM_1M, "Real Bout Garou Densetsu (Japan)", gettext_noop("Game requirement.") }, // Incompatible with 4MiB extended RAM cart. + { "T-3119G", CART_EXTRAM_1M, "Real Bout Garou Densetsu Special (Japan)", gettext_noop("Game requirement.") }, + { "T-3116G", CART_EXTRAM_1M, "Samurai Spirits - Amakusa Kourin (Japan)", gettext_noop("Game requirement.") }, // Incompatible with 4MiB extended RAM cart. + { "T-3104G", CART_EXTRAM_1M, "Samurai Spirits - Zankurou Musouken (Japan)", gettext_noop("Game requirement.") }, + { "610636008",CART_EXTRAM_1M,"Tech Saturn 1997.6 (Japan)", gettext_noop("Required by \"Groove on Fight\" demo.") }, + { "T-16509G", CART_EXTRAM_1M, "Super Real Mahjong P7 (Japan) (TODO: Test)" }, + { "T-16510G", CART_EXTRAM_1M, "Super Real Mahjong P7 (Japan)" }, // Would 4MiB be better? + { "T-3108G", CART_EXTRAM_1M, "The King of Fighters '96 (Japan)", gettext_noop("Game requirement.") }, + { "T-3121G", CART_EXTRAM_1M, "The King of Fighters '97 (Japan)", gettext_noop("Game requirement.") }, + { "T-1515G", CART_EXTRAM_1M, "Waku Waku 7 (Japan)", gettext_noop("Game requirement.") }, // // - { "T-1521G", CART_EXTRAM_1M }, // Astra Superstars - { "T-9904G", CART_EXTRAM_1M }, // Cotton 2 - { "T-1217G", CART_EXTRAM_1M }, // Cyberbots - { "GS-9107", CART_EXTRAM_1M }, // Fighter's History Dynamite - { "T-20109G", CART_EXTRAM_1M },// Friends - { "T-14411G", CART_EXTRAM_1M },// Groove on Fight - { "T-7032H-50", CART_EXTRAM_1M },// Marvel Super Heroes (Europe) - { "T-1215G", CART_EXTRAM_1M }, // Marvel Super Heroes (Japan) - { "T-3111G", CART_EXTRAM_1M }, // Metal Slug - { "T-22205G", CART_EXTRAM_1M },// Noel 3 - { "T-22206G", CART_EXTRAM_1M },// Noel 3 (TODO: Test) - { "T-20114G", CART_EXTRAM_1M },// Pia Carrot e Youkoso!! 2 (TODO: Test) - { "T-20121M", CART_EXTRAM_1M },// Pia Carrot e Youkoso!! 2 (TODO: Test) - { "T-3105G", CART_EXTRAM_1M }, // Real Bout Garou Densetsu - { "T-3119G", CART_EXTRAM_1M }, // Real Bout Garou Densetsu Special - { "T-3116G", CART_EXTRAM_1M }, // Samurai Spirits - Amakusa Kourin - { "T-3104G", CART_EXTRAM_1M }, // Samurai Spirits - Zankurou Musouken - { "T-16509G", CART_EXTRAM_1M },// Super Real Mahjong P7 (TODO: Test) - { "T-16510G", CART_EXTRAM_1M },// Super Real Mahjong P7 (TODO: Test) - { "T-3108G", CART_EXTRAM_1M }, // The King of Fighters '96 - { "T-3121G", CART_EXTRAM_1M }, // The King of Fighters '97 - { "T-1515G", CART_EXTRAM_1M }, // Waku Waku 7 + // 4MiB RAM cart: + { "T-1245G", CART_EXTRAM_4M, "Dungeons and Dragons Collection (Japan)", gettext_noop("Game requirement(\"Shadow over Mystara\").") }, + { "T-1248G", CART_EXTRAM_4M, "Final Fight Revenge (Japan)", gettext_noop("Game requirement.") }, + { "T-1238G", CART_EXTRAM_4M, "Marvel Super Heroes vs. Street Fighter (Japan)", gettext_noop("Game requirement.") }, + { "T-1230G", CART_EXTRAM_4M, "Pocket Fighter (Japan)" }, + { "T-1246G", CART_EXTRAM_4M, "Street Fighter Zero 3 (Japan)", gettext_noop("Game requirement.") }, + { "T-1229G", CART_EXTRAM_4M, "Vampire Savior (Japan)", gettext_noop("Game requirement.") }, + { "T-1226G", CART_EXTRAM_4M, "X-Men vs. Street Fighter (Japan)", gettext_noop("Game requirement.") }, // // // - { "T-1245G", CART_EXTRAM_4M }, // D&D Collection - { "T-1248G", CART_EXTRAM_4M }, // Final Fight Revenge - { "T-1238G", CART_EXTRAM_4M }, // Marvel Super Heroes vs. Street Fighter - { "T-1230G", CART_EXTRAM_4M }, // Pocket Fighter - { "T-1246G", CART_EXTRAM_4M }, // Street Fighter Zero 3 - { "T-1229G", CART_EXTRAM_4M }, // Vampire Savior - { "T-1226G", CART_EXTRAM_4M }, // X-Men vs. Street Fighter + { nullptr, CART_CS1RAM_16M, "Heart of Darkness (Prototype)", gettext_noop("Game requirement(though it's probable the original dev cart was only around 6 to 8MiB)."), { 0x4a, 0xf9, 0xff, 0x30, 0xea, 0x54, 0xfe, 0x3a, 0x79, 0xa7, 0x68, 0x69, 0xae, 0xde, 0x55, 0xbb } }, + { nullptr, CART_CS1RAM_16M, "Heart of Darkness (Prototype)", gettext_noop("Game requirement(though it's probable the original dev cart was only around 6 to 8MiB)."), { 0xf1, 0x71, 0xc3, 0xe4, 0x69, 0xd5, 0x99, 0x93, 0x94, 0x09, 0x05, 0xfc, 0x29, 0xd3, 0x8a, 0x59 } }, // // - // - { nullptr, CART_CS1RAM_16M, { 0x4a, 0xf9, 0xff, 0x30, 0xea, 0x54, 0xfe, 0x3a, 0x79, 0xa7, 0x68, 0x69, 0xae, 0xde, 0x55, 0xbb } }, // Heart of Darkness (Prototype) - { nullptr, CART_CS1RAM_16M, { 0xf1, 0x71, 0xc3, 0xe4, 0x69, 0xd5, 0x99, 0x93, 0x94, 0x09, 0x05, 0xfc, 0x29, 0xd3, 0x8a, 0x59 } }, // Heart of Darkness (Prototype) + // Backup memory cart: + { "T-16804G", CART_BACKUP_MEM, "Dezaemon 2 (Japan)", gettext_noop("Allows saving.") }, // ! + { "GS-9123", CART_BACKUP_MEM, "Die Hard Trilogy (Japan)", gettext_noop("Game will crash when running with a RAM expansion cart.") }, // ! + { "T-16103H", CART_BACKUP_MEM, "Die Hard Trilogy (Europe/USA)", gettext_noop("Game will crash when running with a RAM expansion cart.") }, // ! + { "T-26104G", CART_BACKUP_MEM, "Kouryuu Sangoku Engi (Japan)" }, // ! + { "GS-9197", CART_BACKUP_MEM, "Sega Ages - Galaxy Force II", gettext_noop("Allows saving replay data.") }, // ! +#if 0 + { "T-9527G", CART_BACKUP_MEM, "Akumajou Dracula X - Gekka no Yasoukyoku (Japan)" }, + { "T-1507G", CART_BACKUP_MEM, "Albert Odyssey (Japan)" }, + { "T-12705H", CART_BACKUP_MEM, "Albert Odyssey (USA)" }, + { "T-1209G", CART_BACKUP_MEM, "Arthur to Astaroth no Nazomakaimura - Incredible Toons (Japan)" }, + { "T-33901G", CART_BACKUP_MEM, "Baroque (Japan)" }, + { "T-20113G", CART_BACKUP_MEM, "Black Matrix (Japan)" }, + { "T-20115G", CART_BACKUP_MEM, "Black Matrix (Japan)" }, + { "T-4315G", CART_BACKUP_MEM, "Blue Breaker (Japan)" }, + { "GS-9174", CART_BACKUP_MEM, "Burning Rangers (Japan)" }, + { "MK-81803", CART_BACKUP_MEM, "Burning Rangers (Europe/USA)" }, + { "610-6431", CART_BACKUP_MEM, "Christmas NiGHTS into Dreams (Japan)" }, + { "610-6483", CART_BACKUP_MEM, "Christmas NiGHTS into Dreams (Europe)" }, + { "MK-81067", CART_BACKUP_MEM, "Christmas NiGHTS into Dreams (USA)" }, + { "T-22101G", CART_BACKUP_MEM, "Dark Savior (Japan)" }, + { "MK-81304", CART_BACKUP_MEM, "Dark Savior (Europe/USA)" }, + { "GS-9028", CART_BACKUP_MEM, "Dragon Force (Japan)" }, // ~ + { "T-12703H", CART_BACKUP_MEM, "Dragon Force (USA)" }, // ~ + { "MK-8138250", CART_BACKUP_MEM,"Dragon Force (Europe)" }, // ~ + { "GS-9184", CART_BACKUP_MEM, "Dragon Force II (Japan)" }, // ~ + { "T-31503G", CART_BACKUP_MEM, "Falcom Classics (Japan)" }, + { "T-31504G", CART_BACKUP_MEM, "Falcom Classics II Genteiban (Japan)" }, + { "T-31505G", CART_BACKUP_MEM, "Falcom Classics II (Japan)" }, + { "T-9525G", CART_BACKUP_MEM, "Gensou Suikoden (Japan)" }, + { "T-4507G", CART_BACKUP_MEM, "Grandia (Japan)" }, + { "T-4512G", CART_BACKUP_MEM, "Grandia - Digital Museum (Japan)" }, + { "T-19710G", CART_BACKUP_MEM, "GunBlaze-S (Japan)" }, + { "T-18612G", CART_BACKUP_MEM, "Hexen (Japan)", gettext_noop("Allows saving.") }, // ! + { "T-25406H", CART_BACKUP_MEM, "Hexen (USA)", gettext_noop("Allows saving.") }, // ! + { "T-25405H50", CART_BACKUP_MEM,"Hexen (Europe)", gettext_noop("Allows saving.") }, // ! + { "T-2502G", CART_BACKUP_MEM, "Langrisser III (Japan)" }, + { "T-2505G", CART_BACKUP_MEM, "Langrisser IV (Japan)" }, + { "T-2509G", CART_BACKUP_MEM, "Langrisser V (Japan)" }, + { "T-37101G", CART_BACKUP_MEM, "Legend of Heroes I & II, The - Eiyuu Densetsu (Japan)" }, + { "MK-81302", CART_BACKUP_MEM, "Legend of Oasis, The (USA) / Story of Thor 2, The (Europe)" }, + { "GS-9053", CART_BACKUP_MEM, "Thor - Seireioukiden (Japan)" }, + { "T-27901G", CART_BACKUP_MEM, "Lunar - Silver Star Story (Japan)" }, + { "T-27904G", CART_BACKUP_MEM, "Lunar - Silver Star Story MPEG (Japan)" }, + { "T-27906G", CART_BACKUP_MEM, "Lunar 2 - Eternal Blue (Japan)" }, + { "T-6607G", CART_BACKUP_MEM, "Madou Monogatari (Japan)" }, + { "GS-9018", CART_BACKUP_MEM, "Magic Knight Rayearth (Japan)" }, + { "T-12706H", CART_BACKUP_MEM, "Magic Knight Rayearth (USA)" }, + { "T-27902G", CART_BACKUP_MEM, "Mahou Gakuen Lunar (Japan)" }, + { "T-1214G", CART_BACKUP_MEM, "Rockman 8 (Japan)" }, + { "T-1216H", CART_BACKUP_MEM, "Mega Man 8 (USA)" }, + { "T-1210G", CART_BACKUP_MEM, "Rockman X3 (Japan)" }, + { "T-7029H-50", CART_BACKUP_MEM,"Mega Man X3 (Europe)" }, + { "T-1221G", CART_BACKUP_MEM, "Rockman X4 (Japan)" }, + { "T-1219H", CART_BACKUP_MEM, "Mega Man X4 (USA)" }, + { "T-1501G", CART_BACKUP_MEM, "Myst (Japan)" }, + { "T-26801H08", CART_BACKUP_MEM,"Myst (Korea)" }, + { "T-8101H", CART_BACKUP_MEM, "Myst (USA)" }, + { "MK-81081", CART_BACKUP_MEM, "Myst (Europe)" }, + { "GS-9046", CART_BACKUP_MEM, "NiGHTS into Dreams (Japan)" }, + { "MK-81020", CART_BACKUP_MEM, "NiGHTS into Dreams (Europe/USA)" }, + { "GS-9076", CART_BACKUP_MEM, "Panzer Dragoon RPG (Japan)" }, + { "MK-81307", CART_BACKUP_MEM, "Panzer Dragoon Saga (Europe/USA)" }, + { "T-26112G", CART_BACKUP_MEM, "Prisoner of Ice (Japan)" }, // ~ + { "T-1219G", CART_BACKUP_MEM, "Bio Hazard (Japan)" }, + { "T-1221H", CART_BACKUP_MEM, "Resident Evil (USA)" }, + { "MK-81092", CART_BACKUP_MEM, "Resident Evil (Europe)" }, + { "MK-81383", CART_BACKUP_MEM, "Shining Force III (Europe/USA)" }, // ~ + { "GS-9175", CART_BACKUP_MEM, "Shining Force III - Scenario 1 (Japan)" }, // ~ + { "GS-9188", CART_BACKUP_MEM, "Shining Force III - Scenario 2 (Japan)" }, // ~ + { "GS-9203", CART_BACKUP_MEM, "Shining Force III - Scenario 3 (Japan)" }, // ~ + { "T-33101G", CART_BACKUP_MEM, "Shining the Holy Ark (Japan)" }, + { "MK-81306", CART_BACKUP_MEM, "Shining the Holy Ark (Europe/USA)" }, + { "GS-9057", CART_BACKUP_MEM, "Shining Wisdom (Japan)" }, + { "T-12702H", CART_BACKUP_MEM, "Shining Wisdom (USA)" }, + { "MK-81381", CART_BACKUP_MEM, "Shining Wisdom (Europe)" }, + { "T-14322G", CART_BACKUP_MEM, "Shiroki Majo - Mou Hitotsu no Eiyuu Densetsu (Japan)" }, + { "GS-9027", CART_BACKUP_MEM, "SimCity 2000 (Japan)" }, // ~ + { "T-12601H", CART_BACKUP_MEM, "SimCity 2000 (USA)" }, // ~ + { "MK-81580", CART_BACKUP_MEM, "SimCity 2000 (Europe)" }, // ~ + { "T-27903G", CART_BACKUP_MEM, "Slayers Royal (Japan)" }, + { "T-27907G", CART_BACKUP_MEM, "Slayers Royal 2 (Japan)" }, + { "GS-9170", CART_BACKUP_MEM, "Sonic R (Japan)" }, + { "MK-81800", CART_BACKUP_MEM, "Sonic R (Europe/USA)" }, + { "T-16609G", CART_BACKUP_MEM, "Sorvice (Japan)" }, + { "T-9526G", CART_BACKUP_MEM, "Vandal Hearts - Ushinawareta Kodai Bunmei (Japan)" }, + { "T-10623G", CART_BACKUP_MEM, "WarCraft II (Japan)" }, // ~ + { "T-5023H", CART_BACKUP_MEM, "WarCraft II (USA)" }, // ~ + { "T-5023H-50", CART_BACKUP_MEM,"WarCraft II (Europe)" }, // ~ +#endif }; static const struct { const char* sgid; unsigned mode; + const char* game_name; + const char* purpose; uint8 fd_id[16]; } cemdb[] = { - { "T-9705H", CPUCACHE_EMUMODE_DATA_CB }, // Area 51 (USA) - { "T-25408H", CPUCACHE_EMUMODE_DATA_CB }, // Area 51 (Europe) - { "MK-81036", CPUCACHE_EMUMODE_DATA_CB }, // Clockwork Knight 2 (USA) - { "T-30304G", CPUCACHE_EMUMODE_DATA_CB }, // DeJig - Lassen Art Collection (Japan) - { "T-18504G", CPUCACHE_EMUMODE_DATA_CB }, // Father Christmas (Japan) - { "GS-9101", CPUCACHE_EMUMODE_DATA_CB }, // Fighting Vipers (Japan) - { "MK-81041", CPUCACHE_EMUMODE_DATA_CB }, // Fighting Vipers (Europe/USA) - { "MK-81045", CPUCACHE_EMUMODE_DATA_CB }, // Golden Axe - The Duel (Europe) (and USA too?) - { "GS-9041", CPUCACHE_EMUMODE_DATA_CB }, // Golden Axe - The Duel (Japan) - { "GS-9173", CPUCACHE_EMUMODE_DATA_CB }, // House of the Dead (Japan) - { "GS-9055", CPUCACHE_EMUMODE_DATA_CB }, // Linkle Liver Story - { "81600", CPUCACHE_EMUMODE_DATA_CB }, // Sega Saturn Choice Cuts (USA) - { "610680501",CPUCACHE_EMUMODE_DATA_CB }, // Segakore Sega Bible Mogitate SegaSaturn - { "T-7001H", CPUCACHE_EMUMODE_DATA_CB }, // Spot Goes to Hollywood (USA) - { "T-7014G", CPUCACHE_EMUMODE_DATA_CB }, // Spot Goes to Hollywood (Japan) - // Nooo, causes glitches: { "T-7001H-50",CPUCACHE_EMUMODE_DATA_CB }, // Spot Goes to Hollywood (Europe) - { "T-1206G", CPUCACHE_EMUMODE_DATA_CB }, // Street Fighter Zero (Japan) - { "T-1246G", CPUCACHE_EMUMODE_DATA_CB }, // Street Fighter Zero 3 (Japan) - { "T-1215H", CPUCACHE_EMUMODE_DATA_CB }, // Super Puzzle Fighter II Turbo (USA) - { "T-5001H", CPUCACHE_EMUMODE_DATA_CB }, // Theme Park (Europe) - { "GS-9113", CPUCACHE_EMUMODE_DATA_CB }, // Virtua Fighter Kids (Java Tea Original) - { "T-15005G", CPUCACHE_EMUMODE_DATA_CB }, // Virtual Volleyball (Japan) - { "T-18601H", CPUCACHE_EMUMODE_DATA_CB }, // WipEout (USA) - { "T-18603G", CPUCACHE_EMUMODE_DATA_CB }, // WipEout (Japan) - { "T-11301H", CPUCACHE_EMUMODE_DATA_CB }, // WipEout (Europe) - { "GS-9061", CPUCACHE_EMUMODE_DATA_CB }, // (Hideo Nomo) World Series Baseball (Japan) - { "MK-81109", CPUCACHE_EMUMODE_DATA_CB }, // World Series Baseball (Europe/USA) + { "T-9705H", CPUCACHE_EMUMODE_DATA_CB, "Area 51 (USA)", gettext_noop("Fixes game hang.") }, + { "T-25408H", CPUCACHE_EMUMODE_DATA_CB, "Area 51 (Europe)", gettext_noop("Fixes game hang.") }, + { "MK-81036", CPUCACHE_EMUMODE_DATA_CB, "Clockwork Knight 2 (USA)", gettext_noop("Fixes game hang that occurred when some FMVs were played.") }, + { "T-30304G", CPUCACHE_EMUMODE_DATA_CB, "DeJig - Lassen Art Collection (Japan)", gettext_noop("Fixes graphical glitches.") }, + { "GS-9184", CPUCACHE_EMUMODE_DATA_CB, "Dragon Force II (Japan)", gettext_noop("Fixes math and game logic errors during battles.") }, + { "T-18504G", CPUCACHE_EMUMODE_DATA_CB, "Father Christmas (Japan)", gettext_noop("Fixes stuck music and voice acting.") }, + { "GS-9101", CPUCACHE_EMUMODE_DATA_CB, "Fighting Vipers (Japan)", gettext_noop("Fixes computer-controlled opponent turning into a ghost statue.") }, + { "MK-81041", CPUCACHE_EMUMODE_DATA_CB, "Fighting Vipers (Europe/USA)", gettext_noop("Fixes computer-controlled opponent turning into a ghost statue.") }, + { "T-7309G", CPUCACHE_EMUMODE_DATA_CB, "Formula Grand Prix - Team Unei Simulation (Japan)", gettext_noop("Fixes game hang.") }, + { "MK-81045", CPUCACHE_EMUMODE_DATA_CB, "Golden Axe - The Duel (Europe/USA)", gettext_noop("Fixes flickering title screen.") }, + { "GS-9041", CPUCACHE_EMUMODE_DATA_CB, "Golden Axe - The Duel (Japan)", gettext_noop("Fixes flickering title screen.") }, + { "GS-9173", CPUCACHE_EMUMODE_DATA_CB, "House of the Dead (Japan)", gettext_noop("Fixes game crash on lightgun calibration screen.") }, + { "GS-9055", CPUCACHE_EMUMODE_DATA_CB, "Linkle Liver Story (Japan)", gettext_noop("Fixes game crash when going to the world map.") }, + { "T-14415G", CPUCACHE_EMUMODE_DATA_CB, "Ronde (Japan)", gettext_noop("Fixes missing graphics on the title screen, main menu, and elsewhere.") }, + { "81600", CPUCACHE_EMUMODE_DATA_CB, "Sega Saturn Choice Cuts (USA)", gettext_noop("Fixes FMV playback hangs and playback failures.") }, + { "610680501",CPUCACHE_EMUMODE_DATA_CB, "Segakore Sega Bible Mogitate SegaSaturn (Japan)", gettext_noop("") }, // ? ? ? + { "T-18703G", CPUCACHE_EMUMODE_DATA_CB, "Shunsai (Japan)", gettext_noop("Fixes various graphical glitches.") }, + { "T-7001H", CPUCACHE_EMUMODE_DATA_CB, "Spot Goes to Hollywood (USA)", gettext_noop("Fixes hang at corrupted \"Burst\" logo.") }, + { "T-7014G", CPUCACHE_EMUMODE_DATA_CB, "Spot Goes to Hollywood (Japan)", gettext_noop("Fixes hang at corrupted \"Burst\" logo.") }, + // Nooo, causes glitches: { "T-7001H-50",CPUCACHE_EMUMODE_DATA_CB, "Spot Goes to Hollywood (Europe) + { "T-1206G", CPUCACHE_EMUMODE_DATA_CB, "Street Fighter Zero (Japan)", gettext_noop("Fixes weird color/palette issues during game startup.") }, + { "T-1246G", CPUCACHE_EMUMODE_DATA_CB, "Street Fighter Zero 3 (Japan)", gettext_noop("") }, // ? ? ? + { "T-1215H", CPUCACHE_EMUMODE_DATA_CB, "Super Puzzle Fighter II Turbo (USA)", gettext_noop("Fixes color/brightness and other graphical issues.") }, + { "T-5001H", CPUCACHE_EMUMODE_DATA_CB, "Theme Park (Europe)", gettext_noop("Fixes hang during FMV.") }, + { "T-1807G", CPUCACHE_EMUMODE_DATA_CB, "Thunder Force Gold Pack 1 (Japan)", gettext_noop("Fixes explosion graphic glitches in \"Thunder Force III\".") }, + { "T-1808G", CPUCACHE_EMUMODE_DATA_CB, "Thunder Force Gold Pack 2 (Japan)", gettext_noop("Fixes hang when pausing the game under certain conditions in \"Thunder Force AC\".") }, + { "GS-9113", CPUCACHE_EMUMODE_DATA_CB, "Virtua Fighter Kids (Java Tea Original)", gettext_noop("Fixes malfunction of computer-controlled player.") }, + { "T-2206G", CPUCACHE_EMUMODE_DATA_CB, "Virtual Mahjong (Japan)", gettext_noop("Fixes graphical glitches on the character select screen.") }, + { "T-15005G", CPUCACHE_EMUMODE_DATA_CB, "Virtual Volleyball (Japan)", gettext_noop("Fixes invisible menu items and hang.") }, + { "T-18601H", CPUCACHE_EMUMODE_DATA_CB, "WipEout (USA)", gettext_noop("Fixes hang when trying to exit gameplay back to the main menu.") }, + { "T-18603G", CPUCACHE_EMUMODE_DATA_CB, "WipEout (Japan)", gettext_noop("Fixes hang when trying to exit gameplay back to the main menu.") }, + { "T-11301H", CPUCACHE_EMUMODE_DATA_CB, "WipEout (Europe)", gettext_noop("Fixes hang when trying to exit gameplay back to the main menu.") }, + { "GS-9061", CPUCACHE_EMUMODE_DATA_CB, "Hideo Nomo World Series Baseball (Japan)", gettext_noop("Fixes severe gameplay logic glitches.") }, + { "MK-81109", CPUCACHE_EMUMODE_DATA_CB, "World Series Baseball (Europe/USA)", gettext_noop("Fixes severe gameplay logic glitches.") }, //{ "MK-81019", CPUCACHE_EMUMODE_DATA }, // Astal (USA) //{ "GS-9019", CPUCACHE_EMUMODE_DATA }, // Astal (Japan) - { "T-36102G", CPUCACHE_EMUMODE_FULL }, // Whizz (Japan) - { "T-9515H-50", CPUCACHE_EMUMODE_FULL }, // Whizz (Europe) + { "T-1507G", CPUCACHE_EMUMODE_FULL, "Albert Odyssey (Japan)", gettext_noop("") }, + { "T-12705H", CPUCACHE_EMUMODE_FULL, "Albert Odyssey (USA)", gettext_noop("Fixes battle text truncation.") }, + { "GS-9123", CPUCACHE_EMUMODE_FULL, "Die Hard Trilogy (Japan)", gettext_noop("Fixes game hang.") }, + { "T-16103H", CPUCACHE_EMUMODE_FULL, "Die Hard Trilogy (Europe/USA)", gettext_noop("Fixes game hang.") }, + { "T-13331G", CPUCACHE_EMUMODE_FULL, "Digital Monster Version S (Japan)", gettext_noop("Fixes game hang.") }, + //{ "T-20502G", CPUCACHE_EMUMODE_FULL, "Discworld (Japan) (still broken...)" }, + { "T-13310G", CPUCACHE_EMUMODE_FULL, "GeGeGe no Kitarou (Japan)", gettext_noop("Fixes game hang.") }, + { "T-15904G", CPUCACHE_EMUMODE_FULL, "Gex (Japan)", gettext_noop("Fixes minor FMV glitches.") }, + { "T-15904H", CPUCACHE_EMUMODE_FULL, "Gex (USA)", gettext_noop("Fixes minor FMV glitches.") }, + { "T-15904H50", CPUCACHE_EMUMODE_FULL, "Gex (Europe)", gettext_noop("Fixes minor FMV glitches.") }, + { "T-27901G", CPUCACHE_EMUMODE_FULL, "Lunar - Silver Star Story (Japan)", gettext_noop("Fixes FMV flickering with alternative BIOS.") }, + { "T-7664G", CPUCACHE_EMUMODE_FULL, "Nobunaga no Yabou Shouseiroku (Japan)", gettext_noop("Fixes game hang.") }, + { "T-9510G", CPUCACHE_EMUMODE_FULL, "Policenauts (Japan)", gettext_noop("Fixes screen flickering on disc 2.") }, + { "T-25416H50", CPUCACHE_EMUMODE_FULL, "Rampage - World Tour (Europe)", gettext_noop("Fixes game hang.") }, + { "T-159056", CPUCACHE_EMUMODE_FULL, "Slam 'n Jam 96 (Japan)", gettext_noop("Fixes minor FMV glitches.") }, + { "T-159028H", CPUCACHE_EMUMODE_FULL, "Slam 'n Jam 96 (USA)", gettext_noop("Fixes minor FMV glitches.") }, + { "T-15902H50", CPUCACHE_EMUMODE_FULL, "Slam 'n Jam 96 (Europe)", gettext_noop("Fixes minor FMV glitches.") }, + { "T-8119G", CPUCACHE_EMUMODE_FULL, "Space Jam (Japan)", gettext_noop("Fixes game crash.") }, + { "T-8125H", CPUCACHE_EMUMODE_FULL, "Space Jam (USA)", gettext_noop("Fixes game crash.") }, + { "T-8125H-50", CPUCACHE_EMUMODE_FULL, "Space Jam (Europe)", gettext_noop("Fixes game crash.") }, + { "T-36102G", CPUCACHE_EMUMODE_FULL, "Whizz (Japan)", gettext_noop("Fixes quasi-random hangs during startup.") }, + { "T-9515H-50", CPUCACHE_EMUMODE_FULL, "Whizz (Europe)", gettext_noop("Fixes quasi-random hangs during startup.") }, }; - void DB_Lookup(const char* path, const char* sgid, const uint8* fd_id, unsigned* const region, int* const cart_type, unsigned* const cpucache_emumode) { for(auto& re : regiondb) @@ -206,27 +327,199 @@ void DB_Lookup(const char* path, const char* sgid, const uint8* fd_id, unsigned* break; } } +} + +static const struct +{ + const char* sgid; + unsigned horrible_hacks; + const char* game_name; + const char* purpose; + uint8 fd_id[16]; +} hhdb[] = +{ + { "GS-9126", HORRIBLEHACK_NOSH2DMAPENALTY, "Fighters Megamix (Japan)", gettext_noop("Fixes hang after watching or aborting FMV playback.") }, + { "MK-81073", HORRIBLEHACK_NOSH2DMAPENALTY, "Fighters Megamix (Europe/USA)", gettext_noop("Fixes hang after watching or aborting FMV playback.") }, + { "T-22403G", HORRIBLEHACK_NOSH2DMAPENALTY, "Irem Arcade Classics (Japan)", gettext_noop("Fixes hang when trying to start \"Zippy Race\".") }, // (way too finicky...) + + { "T-4507G", HORRIBLEHACK_VDP1VRAM5000FIX, "Grandia (Japan)", gettext_noop("Fixes hang at end of first disc.") }, + + { "T-1507G", HORRIBLEHACK_VDP1RWDRAWSLOWDOWN,"Albert Odyssey (Japan)", gettext_noop("Partially fixes battle text truncation.") }, + { "T-12705H", HORRIBLEHACK_VDP1RWDRAWSLOWDOWN,"Albert Odyssey (USA)", gettext_noop("Partially fixes battle text truncation.") }, + { "T-8150H", HORRIBLEHACK_VDP1RWDRAWSLOWDOWN, "All-Star Baseball 97 (USA)", gettext_noop("Fixes texture glitches.") }, + { "T-9703H", HORRIBLEHACK_VDP1RWDRAWSLOWDOWN, "Arcade's Greatest Hits (USA)", gettext_noop("Fixes flickering credits text.") }, + { "T-9706H", HORRIBLEHACK_VDP1RWDRAWSLOWDOWN, "Arcade's Greatest Hits - Atari Collection 1 (USA)", gettext_noop("Fixes flickering credits text.") }, + { "6106856", HORRIBLEHACK_VDP1RWDRAWSLOWDOWN, "Burning Rangers Taikenban (Japan)", gettext_noop("Fixes flickering rescue text.") }, + { "GS-9174", HORRIBLEHACK_VDP1RWDRAWSLOWDOWN, "Burning Rangers (Japan)", gettext_noop("Fixes flickering rescue text.") }, + { "MK-81803", HORRIBLEHACK_VDP1RWDRAWSLOWDOWN, "Burning Rangers (Europe/USA)", gettext_noop("Fixes flickering rescue text.") }, + { "T-8111G", HORRIBLEHACK_VDP1RWDRAWSLOWDOWN, "Frank Thomas Big Hurt Baseball (Japan)", gettext_noop("Reduces graphical glitches.") }, + { "T-8138H", HORRIBLEHACK_VDP1RWDRAWSLOWDOWN, "Frank Thomas Big Hurt Baseball (USA)", gettext_noop("Reduces graphical glitches.") }, // Probably need more-accurate VDP1 draw timings to fix the glitches completely. + { "T-36102G", HORRIBLEHACK_VDP1RWDRAWSLOWDOWN, "Whizz (Japan)", gettext_noop("Fixes major graphical issues during gameplay.") }, + { "T-9515H-50", HORRIBLEHACK_VDP1RWDRAWSLOWDOWN,"Whizz (Europe)", gettext_noop("Fixes major graphical issues during gameplay.") }, + + // Still random hangs...wtf is this game doing... + { "T-6006G", HORRIBLEHACK_NOSH2DMALINE106 | HORRIBLEHACK_VDP1INSTANT, "Thunderhawk II (Japan)", gettext_noop("Fixes hangs just before and during gameplay.") }, + { "T-11501H00", HORRIBLEHACK_NOSH2DMALINE106 | HORRIBLEHACK_VDP1INSTANT, "Thunderstrike II (USA)", gettext_noop("Fixes hangs just before and during gameplay.") }, +}; + +uint32 DB_LookupHH(const char* sgid, const uint8* fd_id) +{ + for(auto& hh : hhdb) + { + if((hh.sgid && !strcmp(hh.sgid, sgid)) || (!hh.sgid && !memcmp(hh.fd_id, fd_id, 16))) + { + return hh.horrible_hacks; + } + } + + return 0; +} + +static std::string FDIDToString(const uint8 (&fd_id)[16]) +{ + return MDFN_sprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", fd_id[0], fd_id[1], fd_id[2], fd_id[3], fd_id[4], fd_id[5], fd_id[6], fd_id[7], fd_id[8], fd_id[9], fd_id[10], fd_id[11], fd_id[12], fd_id[13], fd_id[14], fd_id[15]); +} + +void DB_GetInternalDB(std::vector* databases) +{ + databases->push_back({ + "region", + gettext_noop("Region"), + gettext_noop("This database is used in conjunction with a game's internal header and the \"ss.region_default\" setting to automatically select the region of Saturn to emulate when the \"ss.region_autodetect\" setting is set to \"1\", the default.") + }); + + for(auto& re : regiondb) + { + const char* sv = nullptr; + + switch(re.area) + { + default: assert(0); break; + case SMPC_AREA_JP: sv = _("Japan"); break; + case SMPC_AREA_ASIA_NTSC: sv = _("Asia NTSC"); break; + case SMPC_AREA_NA: sv = _("North America"); break; + case SMPC_AREA_CSA_NTSC: sv = _("Brazil"); break; + case SMPC_AREA_KR: sv = _("South Korea"); break; + case SMPC_AREA_ASIA_PAL: sv = _("Asia PAL"); break; + case SMPC_AREA_EU_PAL: sv = _("Europe"); break; + } + // + // + GameDB_Entry e; + + e.GameID = FDIDToString(re.id); + e.GameIDIsHash = true; + e.Name = re.game_name; + e.Setting = sv; + e.Purpose = ""; //ca.purpose ? _(ca.purpose) : ""; + + databases->back().Entries.push_back(e); + } + // + // + // + databases->push_back({ + "cart", + gettext_noop("Cart"), + gettext_noop("This database is used to automatically select the type of cart to emulate when the \"ss.cart\" setting is set to \"auto\", the default. If a game is not found in the database when auto selection is enabled, then the cart used is specified by the \"ss.cart.auto_default\" setting, default \"backup\"(a backup memory cart).") + }); + + for(auto& ca : cartdb) + { + const char* sv = nullptr; + + switch(ca.cart_type) + { + default: assert(0); break; + case CART_NONE: sv = "None"; break; + case CART_BACKUP_MEM: sv = "Backup Memory"; break; + case CART_EXTRAM_1M: sv = "1MiB Extended RAM"; break; + case CART_EXTRAM_4M: sv = "4MiB Extended RAM"; break; + case CART_KOF95: sv = "King of Fighters 95 ROM"; break; + case CART_ULTRAMAN: sv = "Ultraman ROM"; break; + case CART_NLMODEM: sv = "Netlink Modem"; break; + case CART_CS1RAM_16M: sv = "16MiB A-bus CS1 RAM"; break; + } + // + // + GameDB_Entry e; + + e.GameID = ca.sgid ? ca.sgid : FDIDToString(ca.fd_id); + e.GameIDIsHash = !ca.sgid; + e.Name = ca.game_name; + e.Setting = sv; + e.Purpose = ca.purpose ? _(ca.purpose) : ""; + databases->back().Entries.push_back(e); + } // // // -#if 0 - try + databases->push_back({ + "cachemode", + gettext_noop("Cache Mode"), + gettext_noop("This database is used to automatically select cache emulation mode, to fix various logic and timing issues in games. The default cache mode is data-only(with no high-level bypass).\n\nThe cache mode \"Data-only, with high-level bypass\" is a hack of sorts, to work around cache coherency bugs in games. These bugs are typically masked on a real Saturn due to the effects of instruction fetches on the cache, but become a problem when only data caching is emulated.\n\nFull cache emulation is not enabled globally due to the large increase in host CPU usage, along with the potential of causing games that fully utilize both SH-2 CPUs to run significantly slower than they should due to inadequate emulation of bus sharing/contention.") + }); + for(auto& c : cemdb) { - FileStream fp(path, FileStream::MODE_READ); - std::string linebuf; + const char* sv = nullptr; - while(fp.get_line(linebuf) >= 0) + switch(c.mode) { - + default: assert(0); break; + case CPUCACHE_EMUMODE_DATA_CB: sv = _("Data only, with high-level bypass"); break; + case CPUCACHE_EMUMODE_FULL: sv = _("Full"); break; } + GameDB_Entry e; + + e.GameID = c.sgid ? c.sgid : FDIDToString(c.fd_id); + e.GameIDIsHash = !c.sgid; + e.Name = c.game_name; + e.Setting = sv; + e.Purpose = c.purpose ? _(c.purpose) : ""; + + databases->back().Entries.push_back(e); } - catch(MDFN_Error& e) + // + // + // + databases->push_back({ + "horriblehacks", + gettext_noop("Horrible Hacks"), + gettext_noop("This database is used to automatically enable various horrible hacks to fix issues in certain games.\n\nNote that slowing down VDP1 command execution due to SH-2 CPU reads/writes isn't a horrible hack per-se, but it's activated on a per-game basis to avoid the likelihood of breaking some games due to overall Saturn emulation timing inaccuracies.") + }); + for(auto& hh : hhdb) { - if(e.errno() != ENOENT) - throw; + std::string sv; + unsigned hhv = hh.horrible_hacks; + + if(hhv & HORRIBLEHACK_NOSH2DMALINE106) + sv += "Block SH-2 DMA on last line of frame. "; + + if(hhv & HORRIBLEHACK_NOSH2DMAPENALTY) + sv += "Disable slowing down of SH-2 CPU reads/writes during SH-2 DMA. "; + + if(hhv & HORRIBLEHACK_VDP1VRAM5000FIX) + sv += "Patch VDP1 VRAM to break an infinite loop. "; + + if(hhv & HORRIBLEHACK_VDP1RWDRAWSLOWDOWN) + sv += "SH-2 CPU reads/writes from/to VDP1 slow down command execution. "; + + if(hhv & HORRIBLEHACK_VDP1INSTANT) + sv += "Execute VDP1 commands instantly. "; + // + // + // + GameDB_Entry e; + + e.GameID = hh.sgid ? hh.sgid : FDIDToString(hh.fd_id); + e.GameIDIsHash = !hh.sgid; + e.Name = hh.game_name; + e.Setting = sv; + e.Purpose = hh.purpose ? _(hh.purpose) : ""; + + databases->back().Entries.push_back(e); } -#endif } } diff --git a/mednafen/ss/db.h b/mednafen/ss/db.h index 1af1242..a393fd9 100644 --- a/mednafen/ss/db.h +++ b/mednafen/ss/db.h @@ -2,7 +2,7 @@ /* Mednafen Sega Saturn Emulation Module */ /******************************************************************************/ /* db.h: -** Copyright (C) 2016-2017 Mednafen Team +** Copyright (C) 2016-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -33,6 +33,9 @@ enum }; void DB_Lookup(const char* path, const char* sgid, const uint8* fd_id, unsigned* const region, int* const cart_type, unsigned* const cpucache_emumode); +uint32 DB_LookupHH(const char* sgid, const uint8* fd_id); +void DB_GetInternalDB(std::vector* databases) MDFN_COLD; + } #endif diff --git a/mednafen/ss/debug.inc b/mednafen/ss/debug.inc index 3c3a793..ff1ce40 100644 --- a/mednafen/ss/debug.inc +++ b/mednafen/ss/debug.inc @@ -54,7 +54,7 @@ static struct DBGS unsigned ActiveCPU; } DBG; -static void DBG_Break(void) +static MDFN_NOWARN_UNUSED void DBG_Break(void) { DBG.FoundBPoint = true; } @@ -650,6 +650,23 @@ static const RegType DBG_Regs_SCU_CDB_VDP1[] = { 0, "------", "", 0xFFFF }, + { SCU_GSREG_D0MD, "D0MD", "D0MD", 4 }, + { SCU_GSREG_D1MD, "D1MD", "D1MD", 4 }, + { SCU_GSREG_D2MD, "D2MD", "D2MD", 4 }, + + { 0, "------", "", 0xFFFF }, + + { SCU_GSREG_ASR0_CS0, "ASR0_CS0", "A-bus CS0 Config", 2 }, + { SCU_GSREG_ASR0_CS1, "ASR0_CS1", "A-bus CS1 Config", 2 }, + { SCU_GSREG_ASR1_CS2, "ASR1_CS2", "A-bus CS2 Config", 2 }, + { SCU_GSREG_ASR1_CSD, "ASR1_CSD", "A-bus Dummy Config", 2 }, + + { SCU_GSREG_AREF, "AREF", "A-bus Refresh Config", 1 }, + + { SCU_GSREG_RSEL, "RSEL", "SDRAM Size Config", 0x100 | 1 }, + + { 0, "------", "", 0xFFFF }, + { SCU_GSREG_TENBL, "TENBL", "Timers Enable", 0x100 | 1 }, { SCU_GSREG_T0CNT, "T0CNT", "Timer0 Counter", 0x100 | 10 }, @@ -694,6 +711,11 @@ static const RegType DBG_Regs_SCU_CDB_VDP1[] = { (2 << 16) | VDP1::GSREG_LOCALX, "LocalX", "LocalX", 2 }, { (2 << 16) | VDP1::GSREG_LOCALY, "LocalY", "LocalY", 2 }, + { (2 << 16) | VDP1::GSREG_TVMR, "TVMR", "TVMR", 1 }, + { (2 << 16) | VDP1::GSREG_FBCR, "FBCR", "FBCR", 1 }, + { (2 << 16) | VDP1::GSREG_EWDR, "EWDR", "EWDR", 2 }, + { (2 << 16) | VDP1::GSREG_EWLR, "EWLR", "EWLR", 2 }, + { (2 << 16) | VDP1::GSREG_EWRR, "EWRR", "EWRR", 2 }, { 0, "", "", 0 }, }; diff --git a/mednafen/ss/input/3dpad.h b/mednafen/ss/input/3dpad.h index 3656993..a8687d1 100644 --- a/mednafen/ss/input/3dpad.h +++ b/mednafen/ss/input/3dpad.h @@ -33,7 +33,7 @@ class IODevice_3DPad final : public IODevice virtual void Power(void) override MDFN_COLD; virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; - virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override; + virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override MDFN_COLD; virtual uint8 UpdateBus(const sscpu_timestamp_t timestamp, const uint8 smpc_out, const uint8 smpc_out_asserted) override; diff --git a/mednafen/ss/input/gamepad.h b/mednafen/ss/input/gamepad.h index 2451c3d..4e14053 100644 --- a/mednafen/ss/input/gamepad.h +++ b/mednafen/ss/input/gamepad.h @@ -33,7 +33,7 @@ class IODevice_Gamepad final : public IODevice virtual void Power(void) override MDFN_COLD; virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; - virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override; + virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override MDFN_COLD; virtual uint8 UpdateBus(const sscpu_timestamp_t timestamp, const uint8 smpc_out, const uint8 smpc_out_asserted) override; diff --git a/mednafen/ss/input/gun.h b/mednafen/ss/input/gun.h index e7e3dac..ded0fe5 100644 --- a/mednafen/ss/input/gun.h +++ b/mednafen/ss/input/gun.h @@ -34,7 +34,7 @@ class IODevice_Gun final : public IODevice virtual void Power(void) override MDFN_COLD; virtual void TransformInput(uint8* const data, float gun_x_scale, float gun_x_offs) const override; virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; - virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override; + virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override MDFN_COLD; virtual void Draw(MDFN_Surface* surface, const MDFN_Rect& drect, const int32* lw, int ifield, float gun_x_scale, float gun_x_offs) const override; virtual uint8 UpdateBus(const sscpu_timestamp_t timestamp, const uint8 smpc_out, const uint8 smpc_out_asserted) override; diff --git a/mednafen/ss/input/jpkeyboard.h b/mednafen/ss/input/jpkeyboard.h index 39d9641..f0f23db 100644 --- a/mednafen/ss/input/jpkeyboard.h +++ b/mednafen/ss/input/jpkeyboard.h @@ -33,7 +33,7 @@ class IODevice_JPKeyboard final : public IODevice virtual void Power(void) override MDFN_COLD; virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; - virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override; + virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override MDFN_COLD; virtual uint8 UpdateBus(const sscpu_timestamp_t timestamp, const uint8 smpc_out, const uint8 smpc_out_asserted) override; diff --git a/mednafen/ss/input/keyboard.h b/mednafen/ss/input/keyboard.h index ba5275e..857e9f5 100644 --- a/mednafen/ss/input/keyboard.h +++ b/mednafen/ss/input/keyboard.h @@ -34,7 +34,7 @@ class IODevice_Keyboard final : public IODevice virtual void Power(void) override MDFN_COLD; virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; virtual void UpdateOutput(uint8* data) override; - virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override; + virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override MDFN_COLD; virtual uint8 UpdateBus(const sscpu_timestamp_t timestamp, const uint8 smpc_out, const uint8 smpc_out_asserted) override; diff --git a/mednafen/ss/input/mission.h b/mednafen/ss/input/mission.h index aa5f41d..3410848 100644 --- a/mednafen/ss/input/mission.h +++ b/mednafen/ss/input/mission.h @@ -33,7 +33,7 @@ class IODevice_Mission final : public IODevice virtual void Power(void) override MDFN_COLD; virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; - virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override; + virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override MDFN_COLD; virtual uint8 UpdateBus(const sscpu_timestamp_t timestamp, const uint8 smpc_out, const uint8 smpc_out_asserted) override; diff --git a/mednafen/ss/input/mouse.h b/mednafen/ss/input/mouse.h index 6aa4738..1c4fd4f 100644 --- a/mednafen/ss/input/mouse.h +++ b/mednafen/ss/input/mouse.h @@ -33,7 +33,7 @@ class IODevice_Mouse final : public IODevice virtual void Power(void) override MDFN_COLD; virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; - virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override; + virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override MDFN_COLD; virtual uint8 UpdateBus(const sscpu_timestamp_t timestamp, const uint8 smpc_out, const uint8 smpc_out_asserted) override; diff --git a/mednafen/ss/input/multitap.h b/mednafen/ss/input/multitap.h index 41716da..a063633 100644 --- a/mednafen/ss/input/multitap.h +++ b/mednafen/ss/input/multitap.h @@ -32,7 +32,7 @@ class IODevice_Multitap final : public IODevice virtual ~IODevice_Multitap() override MDFN_COLD; virtual void Power(void) override MDFN_COLD; - virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override; + virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override MDFN_COLD; virtual void Draw(MDFN_Surface* surface, const MDFN_Rect& drect, const int32* lw, int ifield, float gun_x_scale, float gun_x_offs) const override; virtual uint8 UpdateBus(const sscpu_timestamp_t timestamp, const uint8 smpc_out, const uint8 smpc_out_asserted) override; virtual void LineHook(const sscpu_timestamp_t timestamp, int32 out_line, int32 div, int32 coord_adj) override; diff --git a/mednafen/ss/input/wheel.h b/mednafen/ss/input/wheel.h index b0f7f71..910bcab 100644 --- a/mednafen/ss/input/wheel.h +++ b/mednafen/ss/input/wheel.h @@ -33,7 +33,7 @@ class IODevice_Wheel final : public IODevice virtual void Power(void) override MDFN_COLD; virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; - virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override; + virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override MDFN_COLD; virtual uint8 UpdateBus(const sscpu_timestamp_t timestamp, const uint8 smpc_out, const uint8 smpc_out_asserted) override; diff --git a/mednafen/ss/notes/PROBLEMATIC-GAMES b/mednafen/ss/notes/PROBLEMATIC-GAMES index 870ba9b..3e5be1c 100644 --- a/mednafen/ss/notes/PROBLEMATIC-GAMES +++ b/mednafen/ss/notes/PROBLEMATIC-GAMES @@ -5,15 +5,23 @@ cache line replacement(or something roughly similar) :( Area 51 (USA/Europe) Clockwork Knight 2 (USA) DeJig - Lassen Art Collection (Japan) +Dragon Force II (Japan) - Battles(broken math) Father Christmas (Japan) +Fighting Vipers (Japan/Europe/USA) Golden Axe The Duel (Japan/Europe/USA) +House of the Dead (Japan) +Linkle Liver Story (Japan) Sega Saturn Choice Cuts (USA) - Broken FMV playback(except intro FMV). Segakore Sega Bible Mogitate SegaSaturn - Zero Divide demo, especially. Spot Goes to Hollywood (USA/Japan) Street Fighter Zero (Japan) Street Fighter Zero 3 (Japan) Super Puzzle Fighter II Turbo (USA) +Theme Park (Europe) +Virtua Fighter Kids (Java Tea Original) Virtual Volleyball (Japan) +WipEout (Japan/Europe/USA) +World Series Baseball (USA/Japan) ------------------------------------------------------------------------------- @@ -35,6 +43,7 @@ Device Reign Real Sound Resident Evil SD Gundam G Century S +Shienryu Super Tempo Tennis Arena Tilk @@ -60,6 +69,14 @@ Virtua Cop Virtua Cop 2 +------------------------------------------------------------------------------- +Rely on SH-2 CPU writes/reads to/from VDP1 RAM slowing VDP1 command execution +------------------------------------------------------------------------------- +Arcade's Greatest Hits - Credits +Burning Rangers - Victim transfer text +Whizz - Gameplay + + ------------------------------------------------------------------------------- Rely on VDP1 register writes via SCU DMA being ignored under certain conditions ------------------------------------------------------------------------------- diff --git a/mednafen/ss/notes/SCSP-FM-GAMES b/mednafen/ss/notes/SCSP-FM-GAMES new file mode 100644 index 0000000..8cfb944 --- /dev/null +++ b/mednafen/ss/notes/SCSP-FM-GAMES @@ -0,0 +1,18 @@ +---------------------------------------------------------------- +Incomplete list of games that use SCSP FM capabilities in music: +---------------------------------------------------------------- + +Assault Suit Leynos 2 +Dragon Force - "Desert", "Snow Land" +Game Basic for SegaSaturn - Music demos, especially the "Thexder 2" and "Veigues" music. +Kaitou Saint Tail +Langrisser III +Magic Knight Rayearth - "Tokyo Tower", "Flash's Theme", "Mysterious Cephiro Lecture", "Great Whirlpool", "Rainbow Junction Shop", "Sea of Trees" +Minnesota Fats - "Your Dime" +Nights into Dreams - Used extensively. +Sakura Taisen - "The Three Gunners of the End of the Century", "Farewell..." +Sakura Taisen 2 - Kanna minigame. +Shinobi X - Used extensively. +Taito Chase HQ + S.C.I - Used extensively. +Virtua Fighter Kids - Synthy-sounding instrument in the (non-FMV) character demo/intro. + diff --git a/mednafen/ss/scsp.inc b/mednafen/ss/scsp.inc index 302247f..ab0dd2f 100644 --- a/mednafen/ss/scsp.inc +++ b/mednafen/ss/scsp.inc @@ -39,7 +39,7 @@ SS_SCSP::SS_SCSP() { - memset(&RAM[0x40000], 0x00, 0x80000); // Zero out dummy part. + memset(&RAM[0x40000], 0x00, 0x40000 * sizeof(uint16)); // Zero out dummy part. Reset(true); } @@ -114,12 +114,15 @@ void SS_SCSP::Reset(bool powering_up) Slots[i].LFOTimeCounter = 1; } + for(unsigned i = 0; i < 2; i++) + EXTS[i] = 0; + memset(SoundStack, 0, sizeof(SoundStack)); memset(SoundStackDelayer, 0, sizeof(SoundStackDelayer)); if(powering_up) { - memset(RAM, 0x00, 0x80000); // or something else? + memset(RAM, 0x00, 0x40000 * sizeof(uint16)); // or something else? } // @@ -154,6 +157,7 @@ void SS_SCSP::Reset(bool powering_up) Timers[i].Control = 0; Timers[i].Counter = 0; Timers[i].PrevClockIn = false; + Timers[i].Reload = -1; } // diff --git a/mednafen/ss/scu.h b/mednafen/ss/scu.h index 4e38880..0553fc0 100644 --- a/mednafen/ss/scu.h +++ b/mednafen/ss/scu.h @@ -69,6 +69,19 @@ enum SCU_GSREG_IPENDING, SCU_GSREG_IMASK, + SCU_GSREG_D0MD, + SCU_GSREG_D1MD, + SCU_GSREG_D2MD, + + SCU_GSREG_ASR0_CS0, + SCU_GSREG_ASR0_CS1, + SCU_GSREG_ASR1_CS2, + SCU_GSREG_ASR1_CSD, + + SCU_GSREG_AREF, + + SCU_GSREG_RSEL, + SCU_GSREG_T0CNT, SCU_GSREG_T0CMP, SCU_GSREG_T0MET, diff --git a/mednafen/ss/scu.inc b/mednafen/ss/scu.inc index 150ec7c..3936462 100644 --- a/mednafen/ss/scu.inc +++ b/mednafen/ss/scu.inc @@ -2,7 +2,7 @@ /* Mednafen Sega Saturn Emulation Module */ /******************************************************************************/ /* scu.inc - SCU Emulation -** Copyright (C) 2015-2018 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -164,6 +164,7 @@ static struct DMALevelS static sscpu_timestamp_t SCU_DMA_TimeCounter; static sscpu_timestamp_t SCU_DMA_RunUntil; static int32 SCU_DMA_ReadOverhead; // range -whatever to 0. +static uint32 SCU_DMA_SDRAM_Slowdown_Counter; static uint32 SCU_DMA_VDP1WriteIgnoreKludge; @@ -177,6 +178,8 @@ static uint32 IPending; static uint32 IMask; static uint32 ABusIProhibit; +static uint32 ASR0, ASR1; +static uint8 AREF; static bool RSEL; static uint8 ILevel, IVec; @@ -482,6 +485,18 @@ static INLINE void SCU_RegRW_DB(uint32 A, uint32* DB) } break; + case 0xB0: + ASR0 = (ASR0 &~ mask) | (*DB & mask & 0xFFFDFFFD); + break; + + case 0xB4: + ASR1 = (ASR1 &~ mask) | (*DB & mask & 0xF00DFFFD); + break; + + case 0xB8: + AREF = (AREF &~ mask) | (*DB & mask & 0x1F); + break; + case 0xC4: RSEL = (RSEL &~ mask) | (*DB & mask & 0x1); if(MDFN_UNLIKELY(!RSEL)) @@ -801,6 +816,9 @@ static INLINE void BBusRW_DB(uint32 A, uint16* DB, int32* time_thing, int32* dma if(IsWrite) { + if(time_thing != NULL) + VDP1::Write_CheckDrawSlowdown(A, *time_thing); + if(sizeof(T) == 1) VDP1::Write8_DB(A, *DB); else @@ -808,6 +826,9 @@ static INLINE void BBusRW_DB(uint32 A, uint16* DB, int32* time_thing, int32* dma } else { + if(time_thing != NULL) + VDP1::Read_CheckDrawSlowdown(A, *time_thing); + *DB = VDP1::Read16_DB(A); } @@ -825,6 +846,8 @@ static INLINE void BBusRW_DB(uint32 A, uint16* DB, int32* time_thing, int32* dma if(dma_time_thing != NULL) { *dma_time_thing -= 1; + //if(A & 0x00100000) + // *dma_time_thing -= 1; } if(time_thing != NULL) @@ -922,13 +945,38 @@ static INLINE void ABusRW_DB(uint32 A, uint16* DB, int32* time_thing, int32* dma // if(A >= 0x02000000 && A <= 0x04FFFFFF) { - // [(bool)(A & 0x04000000)] + { + const unsigned buscfg = ASR0 >> ((A & 0x04000000) ? 0 : 16); - if(sh2_dma_time_thing != NULL) - *sh2_dma_time_thing -= 1; // TODO + if(time_thing != NULL) + { + if(!IsWrite && ((buscfg >> 15) & 0x1)) + { + // TODO/FIXME + *time_thing += 2; + } + else + { + if(!SH32 || !((buscfg >> 2) & 0x3)) + *time_thing += 5 + ((buscfg >> 4) & 0xF) + ((buscfg >> (13 + IsWrite)) & 1); + else + *time_thing += 2 + ((buscfg >> 8) & 0xF); + } + } - if(dma_time_thing != NULL) - *dma_time_thing -= 1; // TODO + // TODO: SCU seems to have its own internal write buffering...or something else complex going on, that complicates + // getting the SH-2 DMA timing right. + if(sh2_dma_time_thing != NULL) + *sh2_dma_time_thing -= 1; + + if(dma_time_thing != NULL) + { + if((buscfg >> 2) & 0x3) + *dma_time_thing -= 2 + ((buscfg >> 8) & 0xF); + else + *dma_time_thing -= 5 + ((buscfg >> 4) & 0xF) + ((buscfg >> (13 + IsWrite)) & 1); + } + } if(IsWrite) { @@ -1186,6 +1234,16 @@ static uint32 DMA_ReadBBus(uint32 offset) static uint32 DMA_ReadCBus(uint32 offset) { + // + // TODO: Determine the nature of this slowdown/overhead. + // + SCU_DMA_SDRAM_Slowdown_Counter++; + if(SCU_DMA_SDRAM_Slowdown_Counter >= 31) + { + SCU_DMA_SDRAM_Slowdown_Counter = 0; + SCU_DMA_ReadOverhead -= 6; + } + return ne16_rbo_be(WorkRAMH, offset & 0xFFFFC); } @@ -1919,8 +1977,28 @@ void SCU_Reset(bool powering_up) IMask = 0xBFFF; IPending = 0; ABusIProhibit = 0; + ASR0 = 0; + ASR1 = 0; + AREF = 0; RSEL = 0; + // + // + if(powering_up) + { + // TODO: check if only power-on, or reset too. + Timer0_Counter = 0; + Timer0_Compare = 0; + Timer0_Met = false; + Timer1_Reload = 0; + Timer1_Counter = 0; + Timer1_Mode = 0; + Timer1_Met = false; + + Timer_Enable = false; + } + // + // if(powering_up) memset(DMALevel, 0x00, sizeof(DMALevel)); @@ -1936,7 +2014,7 @@ void SCU_Reset(bool powering_up) d.Indirect = false; d.ReadUpdate = false; d.WriteUpdate = false; - d.SF = 0; + d.SF = 0x7; d.WATable = &dma_write_tab.acb[0][0][0][0][0]; d.ReadFunc = rftab[0]; @@ -1944,6 +2022,8 @@ void SCU_Reset(bool powering_up) } //SCU_DMA_CycleCounter = 0; SCU_DMA_ReadOverhead = 0; + + SCU_DMA_SDRAM_Slowdown_Counter = 0; SCU_DMA_VDP1WriteIgnoreKludge = 0; @@ -2032,7 +2112,7 @@ static MDFN_COLD void SCU_StateAction(StateMem* sm, const unsigned load, const b SFVAR(SCU_DMA_TimeCounter), SFVAR(SCU_DMA_RunUntil), SFVAR(SCU_DMA_ReadOverhead), - + SFVAR(SCU_DMA_SDRAM_Slowdown_Counter), SFVAR(SCU_DMA_VDP1WriteIgnoreKludge), SFVAR(IAsserted), @@ -2040,6 +2120,9 @@ static MDFN_COLD void SCU_StateAction(StateMem* sm, const unsigned load, const b SFVAR(IMask), SFVAR(ABusIProhibit), + SFVAR(ASR0), + SFVAR(ASR1), + SFVAR(AREF), SFVAR(RSEL), SFVAR(ILevel), @@ -2114,11 +2197,22 @@ static MDFN_COLD void SCU_StateAction(StateMem* sm, const unsigned load, const b // // // + if(load) + { + // For old save states that didn't save these variables. + ASR0 = 0x03301FF0; + ASR1 = 0x10001FF0; + AREF = 0x13; + RSEL = 0x1; + } MDFNSS_StateAction(sm, load, data_only, StateRegs, "SCU"); if(load) { + ILevel &= 0xF; + // + // for(unsigned i = 0; i < 256; i++) DSP.ProgRAM[i] = DSP_DecodeInstruction(DSP_ProgRAM[i]); @@ -2157,7 +2251,10 @@ static MDFN_COLD void SCU_StateAction(StateMem* sm, const unsigned load, const b uint32 index = DMALevel_WATable[level] & 0x7FFFFFFF; if(index >= dwt_counts[which]) // || !dwt_ptrs[which][index].write_size) - printf("bad watable %08x %zu %08x\n", DMALevel_WATable[level], dwt_counts[which], dwt_ptrs[which][index].write_size); + { + //printf("bad watable %08x %zu %08x\n", DMALevel_WATable[level], dwt_counts[which], dwt_ptrs[which][index].write_size); + printf("bad watable %08x %zu\n", DMALevel_WATable[level], dwt_counts[which]); + } else d.WATable = dwt_ptrs[which] + index; } @@ -2215,7 +2312,68 @@ uint32 SCU_GetRegister(const unsigned id, char* const special, const uint32 spec case SCU_GSREG_IMASK: ret = IMask; break; + // + // + // + case SCU_GSREG_D0MD: + case SCU_GSREG_D1MD: + case SCU_GSREG_D2MD: + { + auto& d = DMALevel[id - SCU_GSREG_D0MD]; + + ret = (d.Indirect << 24) | (d.ReadUpdate << 16) | (d.WriteUpdate << 8) | (d.SF << 0); + } + break; + // + // + // + case SCU_GSREG_ASR0_CS0: + case SCU_GSREG_ASR0_CS1: + case SCU_GSREG_ASR1_CS2: + case SCU_GSREG_ASR1_CSD: + { + const unsigned v[4] = { (uint16)(ASR0 >> 16), (uint16)(ASR0 >> 0), (uint16)(ASR1 >> 16), (uint16)(ASR1 >> 0) }; + + ret = v[id - SCU_GSREG_ASR0_CS0]; + + if(special) + { + if(id == SCU_GSREG_ASR1_CS2) + { + trio_snprintf(special, special_len, "Width: %u-bit; Burst: len=%u; Ext wait: %s; Precharge delay: rd=%d; wr=%d; Seq read opt: %s", + ((ret >> 0) & 1) ? 8 : 16, + (ret >> 2) & 0x3, + ((ret >> 12) & 1) ? "On" : "Off", + (ret >> 13) & 1, + (ret >> 14) & 1, + ((ret >> 15) & 1) ? "On" : "Off"); + } + else + { + trio_snprintf(special, special_len, "Width: %u-bit; Norm wait: %u; Burst: len=%u, wait=%u; Ext wait: %s; Precharge delay: rd=%d; wr=%d; Seq read opt: %s", + ((ret >> 0) & 1) ? 8 : 16, + (ret >> 4) & 0xF, + (ret >> 2) & 0x3, + (ret >> 8) & 0xF, + ((ret >> 12) & 1) ? "On" : "Off", + (ret >> 13) & 1, + (ret >> 14) & 1, + ((ret >> 15) & 1) ? "On" : "Off"); + } + } + } + break; + + case SCU_GSREG_AREF: + ret = AREF; + break; + case SCU_GSREG_RSEL: + ret = RSEL; + break; + // + // + // case SCU_GSREG_T0CNT: ret = Timer0_Counter; break; @@ -2279,6 +2437,32 @@ void SCU_SetRegister(const unsigned id, const uint32 value) IMask = value & 0xBFFF; break; // + // + case SCU_GSREG_ASR0_CS0: + ASR0 = (ASR0 & 0x0000FFFF) | ((value & 0xFFFD) << 16); + break; + + case SCU_GSREG_ASR0_CS1: + ASR0 = (ASR0 & 0xFFFF0000) | ((value & 0xFFFD) << 0); + break; + + case SCU_GSREG_ASR1_CS2: + ASR1 = (ASR1 & 0x0000FFFF) | ((value & 0xF00D) << 16); + break; + + case SCU_GSREG_ASR1_CSD: + ASR1 = (ASR1 & 0xFFFF0000) | ((value & 0xFFFD) << 0); + break; + + case SCU_GSREG_AREF: + AREF = value & 0x1F; + break; + + case SCU_GSREG_RSEL: + RSEL = value & 0x1; + break; + // + // case SCU_GSREG_T0CNT: //Timer0_Counter = value & 0x1FF; break; diff --git a/mednafen/ss/sh7095.h b/mednafen/ss/sh7095.h index 1421405..4e70586 100644 --- a/mednafen/ss/sh7095.h +++ b/mednafen/ss/sh7095.h @@ -32,6 +32,7 @@ class SH7095 final void Init(const bool CacheBypassHack) MDFN_COLD; void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname) MDFN_COLD; + void FixupICacheModeState(void) MDFN_COLD; void ForceInternalEventUpdates(void); void AdjustTS(int32 delta, bool force_set = false); @@ -51,12 +52,18 @@ class SH7095 final if(ExtHalt) SetPEX(PEX_PSEUDO_EXTHALT); // Only SetPEX() here, ClearPEX() is called in the pseudo exception handling code as necessary. + + ExtHaltDMA = (ExtHaltDMA & ~1) | state; + } + + INLINE void SetExtHaltDMAKludgeFromVDP2(bool state) + { + ExtHaltDMA = (ExtHaltDMA & ~2) | (state << 1); } template void Step(void); - //private: uint32 R[16]; uint32 PC; @@ -77,9 +84,6 @@ class SH7095 final sscpu_timestamp_t MA_until; sscpu_timestamp_t MM_until; sscpu_timestamp_t write_finish_timestamp; -#if 0 - sscpu_timestamp_t WB_until[16]; -#endif INLINE void SetT(bool new_value) { SR &= ~1; SR |= new_value; } INLINE bool GetT(void) { return SR & 1; } @@ -192,6 +196,8 @@ class SH7095 final void (MDFN_FASTCALL *MWFP16[8])(uint32 A, uint16); void (MDFN_FASTCALL *MWFP32[8])(uint32 A, uint32); + sscpu_timestamp_t WB_until[16]; + // // // Cache: @@ -386,12 +392,11 @@ class SH7095 final void SCI_Reset(void) MDFN_COLD; - const char* const cpu_name; - // // // bool ExtHalt; + uint8 ExtHaltDMA; uint8 (*const ExIVecFetch)(void); uint8 GetPendingInt(uint8*); @@ -547,6 +552,7 @@ class SH7095 final void CheckRWBreakpoints(void (*MRead)(unsigned len, uint32 addr), void (*MWrite)(unsigned len, uint32 addr)) const; static void Disassemble(const uint16 instr, const uint32 PC, char* buffer, uint16 (*DisPeek16)(uint32), uint32 (*DisPeek32)(uint32)); private: + const char* const cpu_name; bool CBH_Setting; uint32 PC_IF, PC_ID; // Debug-related variables. }; diff --git a/mednafen/ss/sh7095.inc b/mednafen/ss/sh7095.inc index dd746d4..c69a2ad 100644 --- a/mednafen/ss/sh7095.inc +++ b/mednafen/ss/sh7095.inc @@ -23,6 +23,8 @@ Instruction cache emulation shouldn't be enabled globally for all games until we resolve timestamp vs mem_timestamp issues in regards to bus contention and time sharing, or else emulated dual-CPU programs may run slower than they should and probably glitch out(and also until 5GHz desktop CPUs are the norm ;)). + + Also...the emulated overhead is a little too high when executing a branch with no delay slot from non-cacheable memory. */ /* @@ -87,7 +89,7 @@ #define NE32ASU8_IDX_ADJ(T, idx) ( ((idx) & ~(sizeof(T) - 1)) ^ (4 - (sizeof(T))) ) #endif -SH7095::SH7095(const char* const name_arg, const unsigned event_id_dma_arg, uint8 (*exivecfn_arg)(void)) : event_id_dma(event_id_dma_arg), cpu_name(name_arg), ExIVecFetch(exivecfn_arg) +SH7095::SH7095(const char* const name_arg, const unsigned event_id_dma_arg, uint8 (*exivecfn_arg)(void)) : event_id_dma(event_id_dma_arg), ExIVecFetch(exivecfn_arg), cpu_name(name_arg) { Init(false); } @@ -148,6 +150,7 @@ void SH7095::Init(const bool cbh) NMILevel = false; BSC.BCR1 &= 0x7FFF; //MD5Level = false; ExtHalt = false; + ExtHaltDMA = false; TruePowerOn(); } @@ -166,10 +169,8 @@ void SH7095::AdjustTS(int32 delta, bool force_set) MA_until = delta; MM_until = delta; -#if 0 for(unsigned i = 0; i < 16; i++) WB_until[i] = delta; -#endif write_finish_timestamp = delta; divide_finish_timestamp = delta; @@ -188,13 +189,11 @@ void SH7095::AdjustTS(int32 delta, bool force_set) if(!(MM_until & 0x40000000)) MM_until += delta; -#if 0 for(unsigned i = 0; i < 16; i++) { if(!(WB_until[i] & 0x40000000)) WB_until[i] += delta; } -#endif if(!(write_finish_timestamp & 0x40000000)) write_finish_timestamp += delta; @@ -218,10 +217,8 @@ void SH7095::TruePowerOn(void) for(unsigned i = 0; i < 16; i++) R[i] = 0; -#if 0 for(unsigned i = 0; i < 16; i++) WB_until[i] = 0; -#endif PC = 0; @@ -236,6 +233,7 @@ void SH7095::TruePowerOn(void) EPending = 0; Pipe_ID = 0; Pipe_IF = 0; + IBuffer = 0; PC_IF = PC_ID = 0; @@ -466,8 +464,9 @@ sscpu_timestamp_t SH7095::DMA_Update(sscpu_timestamp_t et) if(et < dma_lastts) SS_DBG(SS_DBG_WARNING | SS_DBG_SH2, "[%s] DMA_Update called with et(%u) < dma_lastts(%u).\n", cpu_name, et, dma_lastts); } - else if(MDFN_UNLIKELY(ExtHalt)) + else if(MDFN_UNLIKELY(ExtHaltDMA)) { + //printf("%s ExtHaltDMA 0x%02x!\n", cpu_name, ExtHaltDMA); dma_lastts = et; return dma_lastts + 128; } @@ -542,12 +541,37 @@ void SH7095::DMA_StartSG(void) } // Must be called after DMACH[0].CHCR or DMACH[1].CHCR or DMAOR changes. -INLINE void SH7095::DMA_RecalcRunning(void) +NO_INLINE void SH7095::DMA_RecalcRunning(void) { DMA_PenaltyKludgeAmount = 0; - if(DMA_RunCond(0) || DMA_RunCond(1)) - DMA_PenaltyKludgeAmount = 18; + for(unsigned ch = 0; ch < 2; ch++) + { + if(DMA_RunCond(ch)) + { + const int32 npka = (((DMACH[ch].CHCR >> 10) & 3) == 3 && (DMACH[ch].SAR & DMACH[ch].DAR & 0x06000000) != 0x06000000) ? 23 : 18; + + DMA_PenaltyKludgeAmount = std::max(DMA_PenaltyKludgeAmount, npka); + } + } + +#if 1 + if(MDFN_UNLIKELY(ss_horrible_hacks & HORRIBLEHACK_NOSH2DMAPENALTY)) + DMA_PenaltyKludgeAmount = 0; +#endif + // + // + // + if(ss_dbg_mask & (SS_DBG_WARNING | SS_DBG_SH2)) + { + for(unsigned ch = 0; ch < 2; ch++) + { + if(DMA_RunCond(ch) && ((DMACH[ch].CHCR >> 10) & 3) == 3 && ((DMACH[ch].SAR | DMACH[ch].DAR) & 0xF)) + { + SS_DBG(SS_DBG_WARNING | SS_DBG_SH2, "[%s] DMA channel %u, 16-byte transfer size address misalignment, SAR=0x%08x DAR=0x%08x", cpu_name, ch, DMACH[ch].SAR, DMACH[ch].DAR); + } + } + } } INLINE void SH7095::DMA_BusTimingKludge(void) @@ -1961,7 +1985,7 @@ INLINE T SH7095::MemReadRT(uint32 A) else timestamp = std::max(MA_until, timestamp); -#ifdef MDFN_SS_DEV_BUILD +#ifdef MDFN_ENABLE_DEV_BUILD if((A & 0xC7FFFFFF) >= 0x06000200 && (A & 0xC7FFFFFF) <= 0x060003FF) { const uint32 pcm = PC & 0x07FFFFFF; @@ -2153,7 +2177,7 @@ INLINE void SH7095::MemWriteRT(uint32 A, T V) MA_until = std::max(MA_until, timestamp + 1); -#ifdef MDFN_SS_DEV_BUILD +#ifdef MDFN_ENABLE_DEV_BUILD if((A & 0xC7FFFFFF) >= 0x06000200 && (A & 0xC7FFFFFF) <= 0x060003FF) { const uint32 pcm = PC & 0x07FFFFFF; @@ -2754,6 +2778,7 @@ uint32 NO_INLINE SH7095::Exception(const unsigned exnum, const unsigned vecnum) uint32 new_PC; timestamp += 2; + timestamp = std::max(MA_until, timestamp); if(exnum == EXCEPTION_RESET || exnum == EXCEPTION_POWERON) { @@ -2839,14 +2864,8 @@ INLINE void SH7095::Step(void) #define END_OP } break; -#if 0 - #define WB_EX_CHECK(r) { if(timestamp < WB_until[(r)]) timestamp = WB_until[(r)]; } - - #define WB_WRITE(r, v) { R[(r)] = (v); WB_until[(r)] = MA_until + 1; } -#else - #define WB_EX_CHECK(r) { } - #define WB_WRITE(r, v) { R[(r)] = (v); } -#endif + #define WB_EX_CHECK(r) { if(EmulateICache) { if(timestamp < WB_until[(r)]) timestamp = WB_until[(r)]; } } + #define WB_WRITE(r, v) { R[(r)] = (v); if(EmulateICache) { WB_until[(r)] = MA_until + 1; } } // // // @@ -4838,9 +4857,7 @@ void SH7095::StateAction(StateMem* sm, const unsigned load, const bool data_only SFVAR(MA_until), SFVAR(MM_until), SFVAR(write_finish_timestamp), -#if 0 - sscpu_timestamp_t WB_until[16]; -#endif + SFVAR(WB_until), SFVAR(SysRegs), SFVAR(EPending), @@ -4947,6 +4964,7 @@ void SH7095::StateAction(StateMem* sm, const unsigned load, const bool data_only SFVAR(SCI.TSR), SFVAR(ExtHalt), + SFVAR(ExtHaltDMA), SFVAR(PC_IF), SFVAR(PC_ID), @@ -4959,9 +4977,35 @@ void SH7095::StateAction(StateMem* sm, const unsigned load, const bool data_only if(load) { SetCCR(CCR); + + if(load < 0x00102300) + { + ExtHaltDMA = ExtHalt; + } } } +// +// Called after loading a state where instruction cache emulation was not previously enabled in the emulator, but is enabled now(e.g. via database). +// +// May not cover all cases, needs more testing. +// +void SH7095::FixupICacheModeState(void) +{ + for(unsigned i = 0; i < 16; i++) + WB_until[i] = 0; + // + //const uint32 old_IBuffer = IBuffer; + const uint32 A = (PC - 2) & ~3; + + if((int32)A < 0) + IBuffer = MDFN_densb(&Cache[(A >> 4) & 0x3F].Data[(A >> 10) & 0x3][NE32ASU8_IDX_ADJ(uint32, A & 0x0F)]); + else + IBuffer = ne16_rbo_be(SH7095_FastMap[A >> SH7095_EXT_MAP_GRAN_BITS], A); + + //printf("[%s] PC=0x%08x, IBuffer=0x%08x old_IBuffer=0x%08x --- 0x%08x\n", cpu_name, PC, IBuffer, old_IBuffer, ne16_rbo_be(SH7095_FastMap[A >> SH7095_EXT_MAP_GRAN_BITS], A)); +} + // // // diff --git a/mednafen/ss/smpc.cpp b/mednafen/ss/smpc.cpp index d41c4c4..df07085 100644 --- a/mednafen/ss/smpc.cpp +++ b/mednafen/ss/smpc.cpp @@ -367,6 +367,8 @@ void SMPC_SaveNV(Stream* s) void SMPC_SetRTC(const struct tm* ht, const uint8 lang) { + RTC.ClockAccum = 0; + if(!ht) { RTC.Valid = false; @@ -405,7 +407,9 @@ void SMPC_Init(const uint8 area_code_arg, const int32 master_clock_arg) { AreaCode = area_code_arg; MasterClock = master_clock_arg; + SMPC_ClockRatio = 0; + ResetButtonPhysStatus = false; ResetPending = false; vb = false; vsync = false; @@ -473,6 +477,7 @@ void SMPC_Reset(bool powering_up) memset(OREG, 0, sizeof(OREG)); PendingCommand = -1; ExecutingCommand = -1; + SR = 0x00; SF = 0; BusBuffer = 0x00; diff --git a/mednafen/ss/smpc_iodevice.h b/mednafen/ss/smpc_iodevice.h index be377e0..3a4d7fb 100644 --- a/mednafen/ss/smpc_iodevice.h +++ b/mednafen/ss/smpc_iodevice.h @@ -41,7 +41,7 @@ class IODevice // virtual void UpdateInput(const uint8* data, const int32 time_elapsed); virtual void UpdateOutput(uint8* data); - virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix); + virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) MDFN_COLD; virtual void Draw(MDFN_Surface* surface, const MDFN_Rect& drect, const int32* lw, int ifield, float gun_x_scale, float gun_x_offs) const; diff --git a/mednafen/ss/ss.cpp b/mednafen/ss/ss.cpp index 3e84add..b8faded 100644 --- a/mednafen/ss/ss.cpp +++ b/mednafen/ss/ss.cpp @@ -55,10 +55,11 @@ namespace MDFN_IEN_SS static sscpu_timestamp_t MidSync(const sscpu_timestamp_t timestamp); -#ifdef MDFN_SS_DEV_BUILD +#ifdef MDFN_ENABLE_DEV_BUILD uint32 ss_dbg_mask; static std::bitset<0x200> BWMIgnoreAddr[2]; // 0=read, 1=write #endif +uint32 ss_horrible_hacks; static bool NeedEmuICache; static const uint8 BRAM_Init_Data[0x10] = { 0x42, 0x61, 0x63, 0x6b, 0x55, 0x70, 0x52, 0x61, 0x6d, 0x20, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74 }; @@ -101,6 +102,7 @@ static uint32 SH7095_DB; #include "debug.inc" static sha256_digest BIOS_SHA256; // SHA-256 hash of the currently-loaded BIOS; used for save state sanity checks. +static int ActiveCartType; // Used in save states. static std::vector *cdifs = NULL; static std::bitset<1U << (27 - SH7095_EXT_MAP_GRAN_BITS)> FMIsWriteable; @@ -634,14 +636,14 @@ static INLINE bool EventHandler(const sscpu_timestamp_t timestamp) while(timestamp >= (e = events[SS_EVENT__SYNFIRST].next)->event_time) // If Running = 0, EventHandler() may be called even if there isn't an event per-se, so while() instead of do { ... } while { -#ifdef MDFN_SS_DEV_BUILD +#ifdef MDFN_ENABLE_DEV_BUILD const sscpu_timestamp_t etime = e->event_time; #endif sscpu_timestamp_t nt; nt = e->event_handler(e->event_time); -#ifdef MDFN_SS_DEV_BUILD +#ifdef MDFN_ENABLE_DEV_BUILD if(MDFN_UNLIKELY(nt <= etime)) { fprintf(stderr, "which=%d event_time=%d nt=%d timestamp=%d\n", (int)(e - events), etime, nt, timestamp); @@ -1067,7 +1069,7 @@ static INLINE bool DetectRegion(unsigned* const region) return false; } - +#if 0 static MDFN_COLD bool DetectRegionByFN(const std::string& fn, unsigned* const region) { std::string ss = fn; @@ -1134,12 +1136,12 @@ static MDFN_COLD bool DetectRegionByFN(const std::string& fn, unsigned* const re return false; } - -static void MDFN_COLD InitCommon(const unsigned cpucache_emumode, const unsigned cart_type, const unsigned smpc_area, Stream* dbg_cart_rom_stream) +#endif +static void MDFN_COLD InitCommon(const unsigned cpucache_emumode, const unsigned horrible_hacks, const unsigned cart_type, const unsigned smpc_area, Stream* dbg_cart_rom_stream) { const char* cart_rom_path_sname = nullptr; -#ifdef MDFN_SS_DEV_BUILD +#ifdef MDFN_ENABLE_DEV_BUILD ss_dbg_mask = SS_DBG_ERROR; { std::vector dms = MDFN_GetSettingMultiUI("ss.dbg_mask"); @@ -1188,6 +1190,9 @@ static void MDFN_COLD InitCommon(const unsigned cpucache_emumode, const unsigned MDFN_printf(_("CPU Cache Emulation Mode: %s\n"), cem); } // + if(horrible_hacks) + MDFN_printf(_("Horrible hacks: 0x%08x\n"), horrible_hacks); + // { MDFN_printf(_("Region: 0x%01x\n"), smpc_area); const struct @@ -1228,6 +1233,10 @@ static void MDFN_COLD InitCommon(const unsigned cpucache_emumode, const unsigned CPU[c].Init(cpucache_emumode == CPUCACHE_EMUMODE_DATA_CB); CPU[c].SetMD5((bool)c); } + SH7095_mem_timestamp = 0; + SH7095_DB = 0; + + ss_horrible_hacks = horrible_hacks; // // Initialize backup memory. @@ -1255,6 +1264,7 @@ static void MDFN_COLD InitCommon(const unsigned cpucache_emumode, const unsigned } CART_Init(cart_type, cart_rom_stream ? cart_rom_stream.get() : dbg_cart_rom_stream); + ActiveCartType = cart_type; } // // @@ -1509,8 +1519,17 @@ static MDFN_COLD void Load(GameFile* gf) CDInterfaces.push_back(CDInterface::Open(&NVFS, MDFN_GetSettingS("ss.dbg_exe_cdpath"), false)); cdifs = &CDInterfaces; } + // + // + uint32 horrible_hacks = 0; + { + std::vector dhhs = MDFN_GetSettingMultiUI("ss.dbg_exe_hh"); + + for(uint64 dhhse : dhhs) + horrible_hacks |= dhhse; + } - InitCommon(CPUCACHE_EMUMODE_DATA, CART_MDFN_DEBUG, MDFN_GetSettingUI("ss.region_default"), gf->stream); + InitCommon(MDFN_GetSettingUI("ss.dbg_exe_cem"), horrible_hacks, CART_MDFN_DEBUG, MDFN_GetSettingUI("ss.region_default"), gf->stream); } catch(...) { @@ -1604,6 +1623,7 @@ static MDFN_COLD void LoadCD(std::vector* CDInterfaces) unsigned region; int cart_type; unsigned cpucache_emumode; + unsigned horrible_hacks; uint8 fd_id[16]; char sgid[16 + 1] = { 0 }; cdifs = CDInterfaces; @@ -1617,6 +1637,7 @@ static MDFN_COLD void LoadCD(std::vector* CDInterfaces) DetectRegion(®ion); DB_Lookup(nullptr, sgid, fd_id, ®ion, &cart_type, &cpucache_emumode); + horrible_hacks = DB_LookupHH(sgid, fd_id); // if(!MDFN_GetSettingB("ss.region_autodetect")) region = region_default; @@ -1631,7 +1652,7 @@ static MDFN_COLD void LoadCD(std::vector* CDInterfaces) // TODO: auth ID calc - InitCommon(cpucache_emumode, cart_type, region, nullptr); + InitCommon(cpucache_emumode, horrible_hacks, cart_type, region, nullptr); } catch(...) { @@ -1642,7 +1663,7 @@ static MDFN_COLD void LoadCD(std::vector* CDInterfaces) static MDFN_COLD void CloseGame(void) { -#ifdef MDFN_SS_DEV_BUILD +#ifdef MDFN_ENABLE_DEV_BUILD VDP1::MakeDump("/tmp/vdp1_dump.h"); VDP2::MakeDump("/tmp/vdp2_dump.h"); #endif @@ -1854,19 +1875,38 @@ static MDFN_COLD void StateAction(StateMem* sm, const unsigned load, const bool if(!data_only) { sha256_digest sr_dig = BIOS_SHA256; + int cart_type = ActiveCartType; SFORMAT SRDStateRegs[] = { SFPTR8(sr_dig.data(), sr_dig.size()), + SFVAR(cart_type), SFEND }; - MDFNSS_StateAction(sm, load, data_only, SRDStateRegs, "BIOS_HASH", true); + MDFNSS_StateAction(sm, load, data_only, SRDStateRegs, "BIOS_HASH"); - if(load && sr_dig != BIOS_SHA256) - throw MDFN_Error(0, _("BIOS hash mismatch(save state created under a different BIOS)!")); - } + if(load) + { + if(sr_dig != BIOS_SHA256) + throw MDFN_Error(0, _("BIOS hash mismatch(save state created under a different BIOS)!")); +/* + if(load < 0x00102300) + { + SFORMAT DummyStateRegs[] = { SFEND }; + if(MDFNSS_StateAction(sm, load, data_only, DummyStateRegs, "CART_BACKUP", true)) + cart_type = CART_BACKUP_MEM; + } +*/ + if(cart_type != ActiveCartType) + throw MDFN_Error(0, _("Cart type mismatch(save state created with a different cart)!")); + } + } + // + // + // + bool RecordedNeedEmuICache = load ? false : NeedEmuICache; EventsPacker ep; ep.Save(); @@ -1887,6 +1927,8 @@ static MDFN_COLD void StateAction(StateMem* sm, const unsigned load, const bool SFVAR(WorkRAMH), SFVAR(BackupRAM), + SFVAR(RecordedNeedEmuICache), + SFEND }; @@ -1913,6 +1955,14 @@ static MDFN_COLD void StateAction(StateMem* sm, const unsigned load, const bool printf("Bad state events data."); InitEvents(); } + + if(NeedEmuICache && !RecordedNeedEmuICache) + { + //printf("NeedEmuICache=%d, RecordedNeedEmuICache=%d\n", NeedEmuICache, RecordedNeedEmuICache); + + for(size_t i = 0; i < 2; i++) + CPU[i].FixupICacheModeState(); // Only call it after all RAM has been loaded from the save state. + } } } @@ -2005,7 +2055,7 @@ static const MDFNSetting_EnumList CartAD_List[] = { NULL, 0 }, }; -#ifdef MDFN_SS_DEV_BUILD +#ifdef MDFN_ENABLE_DEV_BUILD static const MDFNSetting_EnumList DBGMask_List[] = { { "0", 0 }, @@ -2049,6 +2099,29 @@ static const MDFNSetting_EnumList DBGMask_List[] = }; #endif +static const MDFNSetting_EnumList CEM_List[] = +{ + { "data_cb", CPUCACHE_EMUMODE_DATA_CB, gettext_noop("Data only, with high-level bypass") }, + { "data", CPUCACHE_EMUMODE_DATA, gettext_noop("Data only") }, + { "full", CPUCACHE_EMUMODE_FULL, gettext_noop("Full") }, + + { NULL, 0 }, +}; + +static const MDFNSetting_EnumList HH_List[] = +{ + { "0", 0 }, + { "none", 0, gettext_noop("None") }, + + { "nosh2dmaline106", HORRIBLEHACK_NOSH2DMALINE106, gettext_noop("nosh2dmaline106") }, + { "nosh2dmapenalty", HORRIBLEHACK_NOSH2DMAPENALTY, gettext_noop("nosh2dmapenalty") }, + { "vdp1vram5000fix", HORRIBLEHACK_VDP1VRAM5000FIX, gettext_noop("vdp1vram5000fix") }, + { "vdp1rwdrawslowdown",HORRIBLEHACK_VDP1RWDRAWSLOWDOWN,gettext_noop("vdp1rwdrawslowdown") }, + { "vdp1instant", HORRIBLEHACK_VDP1INSTANT, gettext_noop("vdp1instant") }, + + { NULL, 0 }, +}; + static const MDFNSetting SSSettings[] = { { "ss.bios_jp", MDFNSF_EMU_STATE | MDFNSF_CAT_PATH, gettext_noop("Path to the Japan ROM BIOS"), NULL, MDFNST_STRING, "sega_101.bin" }, @@ -2106,10 +2179,13 @@ static const MDFNSetting SSSettings[] = { "ss.midsync", MDFNSF_NOFLAGS, gettext_noop("Enable mid-frame synchronization."), gettext_noop("Mid-frame synchronization can reduce input latency, but it will increase CPU requirements."), MDFNST_BOOL, "0" }, -#ifdef MDFN_SS_DEV_BUILD +#ifdef MDFN_ENABLE_DEV_BUILD { "ss.dbg_mask", MDFNSF_SUPPRESS_DOC, gettext_noop("Debug printf mask."), NULL, MDFNST_MULTI_ENUM, "none", NULL, NULL, NULL, NULL, DBGMask_List }, #endif + { "ss.dbg_exe_cdpath", MDFNSF_SUPPRESS_DOC | MDFNSF_CAT_PATH, gettext_noop("CD image to use with bootable cart ROM image loading."), NULL, MDFNST_STRING, "" }, + { "ss.dbg_exe_cem", MDFNSF_SUPPRESS_DOC | MDFNSF_NONPERSISTENT, gettext_noop("Cache emulation mode to use with bootable cart ROM image loading."), NULL, MDFNST_ENUM, "data", NULL, NULL, NULL, NULL, CEM_List }, + { "ss.dbg_exe_hh", MDFNSF_SUPPRESS_DOC | MDFNSF_NONPERSISTENT, gettext_noop("Horrible hacks to use with bootable cart ROM image loading."), NULL, MDFNST_MULTI_ENUM, "none", NULL, NULL, NULL, NULL, HH_List }, { NULL }, }; @@ -2143,6 +2219,7 @@ MDFNGI EmulatedSS = NULL, #endif SMPC_PortInfo, + DB_GetInternalDB, Load, TestMagic, LoadCD, diff --git a/mednafen/ss/ss.h b/mednafen/ss/ss.h index fb732d1..3f9838a 100644 --- a/mednafen/ss/ss.h +++ b/mednafen/ss/ss.h @@ -2,7 +2,7 @@ /* Mednafen Sega Saturn Emulation Module */ /******************************************************************************/ /* ss.h: -** Copyright (C) 2015-2017 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -63,12 +63,24 @@ namespace MDFN_IEN_SS SS_DBG_SCSP = (1U << 28), SS_DBG_SCSP_REGW = (1U << 29), }; -#ifdef MDFN_SS_DEV_BUILD +#ifdef MDFN_ENABLE_DEV_BUILD extern uint32 ss_dbg_mask; #else enum { ss_dbg_mask = 0 }; #endif +#if 1 + enum + { + HORRIBLEHACK_NOSH2DMALINE106 = (1U << 0), + HORRIBLEHACK_NOSH2DMAPENALTY = (1U << 1), + HORRIBLEHACK_VDP1VRAM5000FIX = (1U << 2), + HORRIBLEHACK_VDP1RWDRAWSLOWDOWN= (1U << 3), + HORRIBLEHACK_VDP1INSTANT = (1U << 4), + }; + extern uint32 ss_horrible_hacks; +#endif + static INLINE void SS_DBG_Dummy(const char* format, ...) { } #define SS_DBG(which, ...) ((MDFN_UNLIKELY(ss_dbg_mask & (which))) ? (void)trio_printf(__VA_ARGS__) : SS_DBG_Dummy(__VA_ARGS__)) #define SS_DBGTI(which, ...) ((MDFN_UNLIKELY(ss_dbg_mask & (which))) ? ((void)trio_printf(__VA_ARGS__), (void)trio_printf(" @Line=0x%03x, HPos=0x%03x, memts=%d\n", VDP2::PeekLine(), VDP2::PeekHPos(), SH7095_mem_timestamp)) : SS_DBG_Dummy(__VA_ARGS__)) diff --git a/mednafen/ss/ssf.cpp b/mednafen/ss/ssf.cpp index 590dc1e..b0d5b30 100644 --- a/mednafen/ss/ssf.cpp +++ b/mednafen/ss/ssf.cpp @@ -169,6 +169,7 @@ MDFNGI EmulatedSSFPlay = MODPRIO_INTERNAL_HIGH, NULL, DummyPortInfo, + NULL, Load, TestMagic, NULL, diff --git a/mednafen/ss/vdp1.cpp b/mednafen/ss/vdp1.cpp index 7b31369..7ef4487 100644 --- a/mednafen/ss/vdp1.cpp +++ b/mednafen/ss/vdp1.cpp @@ -2,7 +2,7 @@ /* Mednafen Sega Saturn Emulation Module */ /******************************************************************************/ /* vdp1.cpp - VDP1 Emulation -** Copyright (C) 2015-2017 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -19,6 +19,10 @@ ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +// TODO: 32-bit writes from the SH-2 CPUs to VDP1 registers seem to be broken on a Saturn; test, and implement here. + +// TODO: COPR shouldn't be updated(from the view of the program) until the current command finishes. + // TODO: Check to see what registers are reset on reset. // TODO: Fix preclipping when raw system clipping values have bit12==1(sign bit?). @@ -47,6 +51,82 @@ namespace MDFN_IEN_SS namespace VDP1 { +#if 0 +struct VRAMUsageInfo +{ + uint64 earliest; + uint64 latest; +}; + +static VRAMUsageInfo VRAMDrawReads[0x40000]; +static VRAMUsageInfo VRAMWrites[0x40000]; +static uint64 VRAMUsageTSBase; +static uint64 VRAMUsageStartTS; + +static void VRAMUsageInit(void) +{ + VRAMUsageTSBase = 0; +} + +static void VRAMUsageAddBaseTime(int32 amount) +{ + VRAMUsageTSBase += amount; +} + +static void VRAMUsageStart(void) +{ + for(size_t i = 0; i < 0x40000; i++) + { + VRAMDrawReads[i].earliest = ~(uint64)0; + VRAMDrawReads[i].latest = ~(uint64)0; + + VRAMWrites[i].earliest = ~(uint64)0; + VRAMWrites[i].latest = ~(uint64)0; + } + VRAMUsageStartTS = VRAMUsageTSBase; +} + +static void VRAMUsageWrite(uint32 A) +{ + const uint64 fullts = VRAMUsageTSBase + SH7095_mem_timestamp; + const size_t index = (A >> 1) & 0x3FFFF; + + if(VRAMWrites[index].earliest == ~(uint64)0) + VRAMWrites[index].earliest = fullts; + + VRAMWrites[index].latest = fullts; +} + +static void VRAMUsageDrawRead(uint32 A) +{ + const uint64 fullts = VRAMUsageTSBase + SH7095_mem_timestamp; + const size_t index = (A >> 1) & 0x3FFFF; + + if(VRAMDrawReads[index].earliest == ~(uint64)0) + VRAMDrawReads[index].earliest = fullts; + + VRAMDrawReads[index].latest = fullts; +} + +static void VRAMUsageEnd(void) +{ + for(unsigned i = 0; i < 0x40000; i++) + { + if(VRAMWrites[i].latest != ~(uint64)0 && VRAMDrawReads[i].latest != ~(uint64)0) + { + printf("VRAM[0x%06x] Race --- Write, earliest=%llu, latest=%llu --- Draw Read, earliest=%llu, latest=%llu\n", i * 2, (unsigned long long)(VRAMWrites[i].earliest - VRAMUsageStartTS), (unsigned long long)(VRAMWrites[i].latest - VRAMUsageStartTS), (unsigned long long)(VRAMDrawReads[i].earliest - VRAMUsageStartTS), (unsigned long long)(VRAMDrawReads[i].latest - VRAMUsageStartTS)); + } + } +} +#else +static INLINE void VRAMUsageInit(void) { } +static INLINE void VRAMUsageAddBaseTime(int32 amount) { } +static INLINE void VRAMUsageStart(void) { } +static INLINE void VRAMUsageWrite(uint32 A) { } +static INLINE void VRAMUsageDrawRead(uint32 A) { } +static INLINE void VRAMUsageEnd(void) { } +#endif + uint8 spr_w_shift_tab[8]; line_data LineSetup; uint8 gouraud_lut[0x40]; @@ -60,6 +140,7 @@ static bool FBManualPending; static bool FBVBErasePending; static bool FBVBEraseActive; static sscpu_timestamp_t FBVBEraseLastTS; +static sscpu_timestamp_t LastRWTS; // ss_horrible_hacks int32 SysClipX, SysClipY; int32 UserClipX0, UserClipY0, UserClipX1, UserClipY1; @@ -100,6 +181,10 @@ static bool vb_status, hb_status; static sscpu_timestamp_t lastts; static int32 CycleCounter; +#if 1 +static uint32 InstantDrawSanityLimit; // ss_horrible_hacks +#endif + static bool vbcdpending; void Init(void) @@ -126,6 +211,9 @@ void Init(void) hb_status = false; lastts = 0; FBVBEraseLastTS = 0; + LastRWTS = 0; + + VRAMUsageInit(); } void Kill(void) @@ -201,6 +289,7 @@ void Reset(bool powering_up) EraseYCounter = ~0U; CycleCounter = 0; + InstantDrawSanityLimit = 0; } static int32 CMD_SetUserClip(const uint16* cmd_data) @@ -245,6 +334,7 @@ static uint32 MDFN_FASTCALL TexFetch(uint32 x) { case 0: // 16 colors, color bank rtd = (VRAM[(base + (x >> 2)) & 0x3FFFF] >> (((x & 0x3) ^ 0x3) << 2)) & 0xF; + VRAMUsageDrawRead((base + (x >> 2)) & 0x3FFFF); if(!ECD && rtd == 0xF) { @@ -259,6 +349,7 @@ static uint32 MDFN_FASTCALL TexFetch(uint32 x) case 1: // 16 colors, LUT rtd = (VRAM[(base + (x >> 2)) & 0x3FFFF] >> (((x & 0x3) ^ 0x3) << 2)) & 0xF; + VRAMUsageDrawRead((base + (x >> 2)) & 0x3FFFF); if(!ECD && rtd == 0xF) { @@ -272,6 +363,7 @@ static uint32 MDFN_FASTCALL TexFetch(uint32 x) case 2: // 64 colors, color bank rtd = (VRAM[(base + (x >> 1)) & 0x3FFFF] >> (((x & 0x1) ^ 0x1) << 3)) & 0xFF; + VRAMUsageDrawRead((base + (x >> 1)) & 0x3FFFF); if(!ECD && rtd == 0xFF) { @@ -287,6 +379,7 @@ static uint32 MDFN_FASTCALL TexFetch(uint32 x) case 3: // 128 colors, color bank rtd = (VRAM[(base + (x >> 1)) & 0x3FFFF] >> (((x & 0x1) ^ 0x1) << 3)) & 0xFF; + VRAMUsageDrawRead((base + (x >> 1)) & 0x3FFFF); if(!ECD && rtd == 0xFF) { @@ -302,6 +395,7 @@ static uint32 MDFN_FASTCALL TexFetch(uint32 x) case 4: // 256 colors, color bank rtd = (VRAM[(base + (x >> 1)) & 0x3FFFF] >> (((x & 0x1) ^ 0x1) << 3)) & 0xFF; + VRAMUsageDrawRead((base + (x >> 1)) & 0x3FFFF); if(!ECD && rtd == 0xFF) { @@ -322,6 +416,7 @@ static uint32 MDFN_FASTCALL TexFetch(uint32 x) rtd = VRAM[0]; else rtd = VRAM[(base + x) & 0x3FFFF]; + VRAMUsageDrawRead((ColorMode >= 6) ? 0 : ((base + x) & 0x3FFFF)); if(!ECD && (rtd & 0xC000) == 0x4000) { @@ -397,6 +492,11 @@ sscpu_timestamp_t Update(sscpu_timestamp_t timestamp) } else if(DrawingActive) { +#if 1 + if(MDFN_UNLIKELY(ss_horrible_hacks & HORRIBLEHACK_VDP1INSTANT)) + CycleCounter = InstantDrawSanityLimit; +#endif + while(CycleCounter > 0) { uint16 cmd_data[0x10]; @@ -405,6 +505,9 @@ sscpu_timestamp_t Update(sscpu_timestamp_t timestamp) memcpy(cmd_data, &VRAM[CurCommandAddr], sizeof(cmd_data)); CycleCounter -= 16; + for(unsigned i = 0; i < 16; i++) + VRAMUsageDrawRead((CurCommandAddr + i) * 2); + //SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP1, "[VDP1] Command @ 0x%06x: 0x%04x\n", CurCommandAddr, cmd_data[0]); if(MDFN_LIKELY(!(cmd_data[0] & 0xC000))) @@ -414,6 +517,7 @@ sscpu_timestamp_t Update(sscpu_timestamp_t timestamp) if(MDFN_UNLIKELY(cc >= 0xC)) { DrawingActive = false; + VRAMUsageEnd(); break; } else @@ -437,6 +541,7 @@ sscpu_timestamp_t Update(sscpu_timestamp_t timestamp) { SS_DBGTI(SS_DBG_VDP1, "[VDP1] Drawing finished at 0x%05x", CurCommandAddr); DrawingActive = false; + VRAMUsageEnd(); EDSR |= 0x2; // TODO: Does EDSR reflect IRQ out status? @@ -471,6 +576,11 @@ sscpu_timestamp_t Update(sscpu_timestamp_t timestamp) break; } } + +#if 1 + if(MDFN_UNLIKELY(ss_horrible_hacks & HORRIBLEHACK_VDP1INSTANT)) + InstantDrawSanityLimit = CycleCounter; +#endif } return timestamp + (DrawingActive ? std::max(VDP1_UpdateTimingGran, 0 - CycleCounter) : VDP1_IdleTimingGran); @@ -494,6 +604,8 @@ static void StartDrawing(void) CurCommandAddr = 0; RetCommandAddr = -1; DrawingActive = true; + VRAMUsageStart(); + CycleCounter = VDP1_UpdateTimingGran; } @@ -525,6 +637,8 @@ void SetHBVB(const sscpu_timestamp_t event_timestamp, const bool new_hb_status, } else // Leaving v-blank { + InstantDrawSanityLimit = 1000000; + // Run vblank erase at end of vblank all at once(not strictly accurate, but should only have visible side effects wrt the debugger and reset). if(FBVBEraseActive) { @@ -573,10 +687,16 @@ void SetHBVB(const sscpu_timestamp_t event_timestamp, const bool new_hb_status, // if(!(FBCR & FBCR_FCM) || (FBManualPending && (FBCR & FBCR_FCT))) // Swap framebuffers { +#if 1 + if((ss_horrible_hacks & HORRIBLEHACK_VDP1VRAM5000FIX) && DrawingActive && VRAM[0] == 0x5000 && VRAM[1] == 0x0000) + VRAM[0] = 0x8000; +#endif + if(DrawingActive) { SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP1, "[VDP1] Drawing aborted by framebuffer swap."); DrawingActive = false; + VRAMUsageEnd(); } FBDrawWhich = !FBDrawWhich; @@ -607,17 +727,13 @@ void SetHBVB(const sscpu_timestamp_t event_timestamp, const bool new_hb_status, } } + EraseYCounter = ~0U; if(!(FBCR & FBCR_FCM) || (FBManualPending && !(FBCR & FBCR_FCT))) { if(TVMR & TVMR_ROTATE) - { - EraseYCounter = ~0U; FBVBErasePending = true; - } else - { EraseYCounter = EraseParams.y_start; - } } FBManualPending = false; @@ -719,6 +835,11 @@ void AdjustTS(const int32 delta) lastts += delta; if(FBVBEraseActive) FBVBEraseLastTS += delta; + + if(LastRWTS >= 0) + LastRWTS += delta; + + VRAMUsageAddBaseTime(-delta); } static INLINE void WriteReg(const unsigned which, const uint16 value) @@ -768,6 +889,7 @@ static INLINE void WriteReg(const unsigned which, const uint16 value) if(DrawingActive) { DrawingActive = false; + VRAMUsageEnd(); if(CycleCounter < 0) CycleCounter = 0; nt = SH7095_mem_timestamp + VDP1_IdleTimingGran; @@ -802,12 +924,44 @@ static INLINE uint16 ReadReg(const unsigned which) } } -void Write8_DB(uint32 A, uint16 DB) +// +// Due to the emulated CPUs running faster than they should(due to lack of instruction cache emulation, lack of emulation of some pipeline details, +// lack of memory refresh cycle emulation), there is the potential that a game may write too much data too fast, causing drawing to timeout and abort, +// and the game could subsequently hang waiting for drawing to complete. With this in mind, only selectively enable it for games that are known +// to benefit, via the horrible hacks mechanism. +// +MDFN_FASTCALL void Write_CheckDrawSlowdown(uint32 A, sscpu_timestamp_t time_thing) +{ + if(DrawingActive && (ss_horrible_hacks & HORRIBLEHACK_VDP1RWDRAWSLOWDOWN)) + { + const int32 count = (A & 0x100000) ? 22 : 25; + const uint32 a = std::min(count, time_thing - LastRWTS); + + CycleCounter -= a; + LastRWTS = time_thing; + } +} + +MDFN_FASTCALL void Read_CheckDrawSlowdown(uint32 A, sscpu_timestamp_t time_thing) +{ + //printf("%08x\n", A); + if(!(A & 0x100000) && DrawingActive && (ss_horrible_hacks & HORRIBLEHACK_VDP1RWDRAWSLOWDOWN)) + { + const int32 count = (A & 0x80000) ? 44 : 41; + const uint32 a = std::min(count, time_thing - LastRWTS); + + CycleCounter -= a; + LastRWTS = time_thing; + } +} + +MDFN_FASTCALL void Write8_DB(uint32 A, uint16 DB) { A &= 0x1FFFFF; if(A < 0x80000) { + VRAMUsageWrite(A); SS_DBGTI(SS_DBG_VDP1_VRAMW, "[VDP1] Write to VRAM: 0x%02x->VRAM[0x%05x]", (DB >> (((A & 1) ^ 1) << 3)) & 0xFF, A); ne16_wbo_be(VRAM, A, DB >> (((A & 1) ^ 1) << 3) ); return; @@ -830,12 +984,13 @@ void Write8_DB(uint32 A, uint16 DB) WriteReg((A - 0x100000) >> 1, DB); } -void Write16_DB(uint32 A, uint16 DB) +MDFN_FASTCALL void Write16_DB(uint32 A, uint16 DB) { A &= 0x1FFFFE; if(A < 0x80000) { + VRAMUsageWrite(A); SS_DBGTI(SS_DBG_VDP1_VRAMW, "[VDP1] Write to VRAM: 0x%04x->VRAM[0x%05x]", DB, A); VRAM[A >> 1] = DB; return; @@ -857,7 +1012,7 @@ void Write16_DB(uint32 A, uint16 DB) WriteReg((A - 0x100000) >> 1, DB); } -uint16 Read16_DB(uint32 A) +MDFN_FASTCALL uint16 Read16_DB(uint32 A) { A &= 0x1FFFFE; @@ -935,6 +1090,10 @@ void StateAction(StateMem* sm, const unsigned load, const bool data_only) SFVAR(vbcdpending), + SFVAR(LastRWTS), + + SFVAR(InstantDrawSanityLimit), + SFEND }; @@ -1003,6 +1162,26 @@ uint32 GetRegister(const unsigned id, char* const special, const uint32 special_ case GSREG_LOCALY: ret = LocalY; break; + + case GSREG_TVMR: + ret = TVMR; + break; + + case GSREG_FBCR: + ret = FBCR; + break; + + case GSREG_EWDR: + ret = EWDR; + break; + + case GSREG_EWLR: + ret = EWLR; + break; + + case GSREG_EWRR: + ret = EWRR; + break; } return ret; diff --git a/mednafen/ss/vdp1.h b/mednafen/ss/vdp1.h index ab1494a..d6670b6 100644 --- a/mednafen/ss/vdp1.h +++ b/mednafen/ss/vdp1.h @@ -2,7 +2,7 @@ /* Mednafen Sega Saturn Emulation Module */ /******************************************************************************/ /* vdp1.h: -** Copyright (C) 2015-2017 Mednafen Team +** Copyright (C) 2015-2019 Mednafen Team ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License @@ -32,16 +32,18 @@ namespace VDP1 void Init(void) MDFN_COLD; void Kill(void) MDFN_COLD; -void StateAction(StateMem* sm, const unsigned load, const bool data_only); +void StateAction(StateMem* sm, const unsigned load, const bool data_only) MDFN_COLD; void Reset(bool powering_up) MDFN_COLD; sscpu_timestamp_t Update(sscpu_timestamp_t timestamp); void AdjustTS(const int32 delta); -void Write8_DB(uint32 A, uint16 DB) MDFN_HOT; -void Write16_DB(uint32 A, uint16 DB) MDFN_HOT; -uint16 Read16_DB(uint32 A) MDFN_HOT; +MDFN_FASTCALL void Write_CheckDrawSlowdown(uint32 A, sscpu_timestamp_t time_thing) MDFN_HOT; +MDFN_FASTCALL void Read_CheckDrawSlowdown(uint32 A, sscpu_timestamp_t time_thing) MDFN_HOT; +MDFN_FASTCALL void Write8_DB(uint32 A, uint16 DB) MDFN_HOT; +MDFN_FASTCALL void Write16_DB(uint32 A, uint16 DB) MDFN_HOT; +MDFN_FASTCALL uint16 Read16_DB(uint32 A) MDFN_HOT; void SetHBVB(const sscpu_timestamp_t event_timestamp, const bool new_hb_status, const bool new_vb_status); @@ -90,7 +92,13 @@ enum GSREG_USERCLIPX1, GSREG_USERCLIPY1, GSREG_LOCALX, - GSREG_LOCALY + GSREG_LOCALY, + + GSREG_TVMR, + GSREG_FBCR, + GSREG_EWDR, + GSREG_EWLR, + GSREG_EWRR }; uint32 GetRegister(const unsigned id, char* const special, const uint32 special_len) MDFN_COLD; void SetRegister(const unsigned id, const uint32 value) MDFN_COLD; diff --git a/mednafen/ss/vdp2.cpp b/mednafen/ss/vdp2.cpp index a705be0..b05289f 100644 --- a/mednafen/ss/vdp2.cpp +++ b/mednafen/ss/vdp2.cpp @@ -38,6 +38,7 @@ namespace MDFN_IEN_SS { +#include "sh7095.h" namespace VDP2 { @@ -370,6 +371,16 @@ static INLINE void IncVCounter(const sscpu_timestamp_t event_timestamp) Window[0].YEndMet = Window[1].YEndMet = false; } +#if 1 + if(MDFN_UNLIKELY(ss_horrible_hacks & HORRIBLEHACK_NOSH2DMALINE106)) + { + const bool s = (VCounter == (VTimings[PAL][VRes][VPHASE__COUNT - 1] - 1)); + + for(size_t i = 0; i < 2; i++) + CPU[i].SetExtHaltDMAKludgeFromVDP2(s); + } +#endif + // - 1, so the CPU loop will have plenty of time to exit before we reach non-hblank top border area // (exit granularity could be large if program is executing from SCSP RAM space, for example). if(VCounter == (VTimings[PAL][VRes][VPHASE_TOP_BLANKING] - 1)) @@ -878,6 +889,8 @@ void Init(const bool IsPAL) SurfInterlaceField = -1; PAL = IsPAL; lastts = 0; + CRTLineCounter = 0x80000000U; + Clock28M = false; SS_SetPhysMemMap(0x05E00000, 0x05EFFFFF, VRAM, 0x80000, true); @@ -906,6 +919,8 @@ void Kill(void) // void Reset(bool powering_up) { + memset(RawRegs, 0, sizeof(RawRegs)); + DisplayOn = false; BorderMode = false; ExLatchEnable = false; @@ -924,6 +939,9 @@ void Reset(bool powering_up) VCounter = 0; Odd = true; + for(size_t i = 0; i < 2; i++) + CPU[i].SetExtHaltDMAKludgeFromVDP2(false); + RAMCTL_Raw = 0; CRAM_Mode = 0; diff --git a/mednafen/ss/vdp2_render.cpp b/mednafen/ss/vdp2_render.cpp index f9f0ed4..8493ee5 100644 --- a/mednafen/ss/vdp2_render.cpp +++ b/mednafen/ss/vdp2_render.cpp @@ -3253,7 +3253,7 @@ void VDP2REND_Init(const bool IsPAL) VisibleLines = PAL ? 288 : 240; // UserLayerEnableMask = ~0U; - + Clock28M = false; // WQ_ReadPos = 0; WQ_WritePos = 0; @@ -3262,6 +3262,9 @@ void VDP2REND_Init(const bool IsPAL) WakeupSem = MThreading::CreateSem(); RThread = MThreading::CreateThread(RThreadEntry, NULL, "MDFN VDP2 Render"); + #ifdef MDFN_SS_VDP2_THREAD_AFFINITY + MThreading::SetAffinity(RThread, MDFN_SS_VDP2_THREAD_AFFINITY); + #endif } // Needed for ss.correct_aspect == 0 diff --git a/mednafen/state.cpp b/mednafen/state.cpp index f6104b8..0e28349 100644 --- a/mednafen/state.cpp +++ b/mednafen/state.cpp @@ -44,11 +44,12 @@ struct StateSectionMapEntry struct StateMem { - StateMem(Stream*s, bool svbe_ = false) : st(s), svbe(svbe_) { }; + StateMem(Stream*s, bool svbe_ = false, bool fuzz_ = false) : st(s), svbe(svbe_), fuzz(fuzz_) { }; ~StateMem(); Stream* st = nullptr; bool svbe = false; // State variable data is stored big-endian(for normal-path state loading only). + bool fuzz = false; std::map secmap; // For loads @@ -175,7 +176,7 @@ static void MakeSFMap(const SFORMAT *sf, SFMap_t &sfmap) } } -static void ReadStateChunk(Stream *st, const SFORMAT *sf, uint32 size, const bool svbe, const bool fuzz) +static void ReadStateChunk(Stream *st, const SFORMAT *sf, const char* sname, uint32 size, const bool svbe, const bool fuzz) { SFMap_t sfmap; SFMap_t sfmap_found; // Used for identifying variables that are missing in the save state. @@ -222,25 +223,25 @@ static void ReadStateChunk(Stream *st, const SFORMAT *sf, uint32 size, const boo do { st->read((void*)p, expected_size); -#if 0 + if(MDFN_UNLIKELY(fuzz)) { static uint64 lcg[2] = { 0xDEADBEEFCAFEBABEULL, 0x0123456789ABCDEFULL }; for(unsigned i = 0; i < expected_size; i++) { - ((uint8*)tmp->data)[i] = (lcg[0] ^ lcg[1]) >> 28; + ((uint8*)p)[i] = (lcg[0] ^ lcg[1]) >> 28; lcg[0] = (19073486328125ULL * lcg[0]) + 1; lcg[1] = (6364136223846793005ULL * lcg[1]) + 1442695040888963407ULL; } } -#endif + if(!type) { // Converting downwards is necessary for the case of sizeof(bool) > 1 for(int32 bool_monster = expected_size - 1; bool_monster >= 0; bool_monster--) { - ((bool *)p)[bool_monster] = ((uint8 *)p)[bool_monster]; + ((bool *)p)[bool_monster] = ((uint8 *)p)[bool_monster] & 1; } } else if(svbe != MDFN_IS_BIGENDIAN) @@ -257,7 +258,7 @@ static void ReadStateChunk(Stream *st, const SFORMAT *sf, uint32 size, const boo } else { - printf("Unknown variable in save state: %s\n", toa + 1); + printf("Unknown variable in save state section \"%s\": %s\n", sname, toa + 1); st->seek(recorded_size, SEEK_CUR); } } // while(...) @@ -266,7 +267,7 @@ static void ReadStateChunk(Stream *st, const SFORMAT *sf, uint32 size, const boo { if(sfmap_found.find(it->second->name) == sfmap_found.end()) { - printf("Variable of bytesize %u missing from save state: %s\n", it->second->size * (1 + it->second->repcount), it->second->name); + printf("Variable of bytesize %u missing from save state section \"%s\": %s\n", it->second->size * (1 + it->second->repcount), sname, it->second->name); } } } @@ -385,7 +386,7 @@ bool MDFNSS_StateAction(StateMem *sm, const unsigned load, const bool data_only, { msme->second.used = true; st->seek(msme->second.pos, SEEK_SET); - ReadStateChunk(st, sf, msme->second.size, sm->svbe, (bool)(load & 0x80000000)); + ReadStateChunk(st, sf, sname, msme->second.size, sm->svbe, sm->fuzz); } } else @@ -558,7 +559,7 @@ void MDFNSS_SaveSM(Stream *st, bool data_only, const MDFN_Surface *surface, cons } } -void MDFNSS_LoadSM(Stream *st, bool data_only) +void MDFNSS_LoadSM(Stream *st, bool data_only, bool fuzz) { if(!MDFNGameInfo->StateAction) { @@ -599,7 +600,7 @@ void MDFNSS_LoadSM(Stream *st, bool data_only) st->seek(preview_len, SEEK_CUR); // Skip preview { - StateMem sm(st, svbe); + StateMem sm(st, svbe, fuzz); MakeSectionMap(&sm, start_pos + total_len); diff --git a/mednafen/state.h b/mednafen/state.h index ec919d3..293e315 100644 --- a/mednafen/state.h +++ b/mednafen/state.h @@ -46,7 +46,7 @@ struct StateMem; // throws exceptions on errors. // void MDFNSS_SaveSM(Stream *st, bool data_only = false, const MDFN_Surface *surface = (MDFN_Surface *)NULL, const MDFN_Rect *DisplayRect = (MDFN_Rect*)NULL, const int32 *LineWidths = (int32*)NULL); -void MDFNSS_LoadSM(Stream *st, bool data_only = false); +void MDFNSS_LoadSM(Stream *st, bool data_only = false, const bool fuzz = false); void MDFNSS_CheckStates(void); diff --git a/mednafen/types.h b/mednafen/types.h index db3e051..eddda0c 100644 --- a/mednafen/types.h +++ b/mednafen/types.h @@ -102,7 +102,7 @@ typedef uint64_t uint64; #define HAVE_SSE2_INTRINSICS 1 #endif -#if defined(__ARM_NEON__) || defined(_M_ARM64) +#if defined(__ARM_NEON__) || defined(__ARM_NEON) || defined(_M_ARM64) #define HAVE_NEON_INTRINSICS 1 #endif diff --git a/mednafen/vb/vb.cpp b/mednafen/vb/vb.cpp index fc9b114..4579e39 100644 --- a/mednafen/vb/vb.cpp +++ b/mednafen/vb/vb.cpp @@ -1030,6 +1030,7 @@ MDFNGI EmulatedVB = NULL, // Debug info #endif PortInfo, + NULL, Load, TestMagic, NULL, diff --git a/mednafen/wswan/main.cpp b/mednafen/wswan/main.cpp index 848b6ac..cf8f321 100644 --- a/mednafen/wswan/main.cpp +++ b/mednafen/wswan/main.cpp @@ -664,6 +664,7 @@ MDFNGI EmulatedWSwan = NULL, #endif PortInfo, + NULL, Load, TestMagic, NULL,