(Mednafen PCE) Update to 0.9.33.3

This commit is contained in:
twinaphex 2014-04-20 23:05:37 +02:00
parent f23e446ff8
commit c2adc1c619
53 changed files with 9832 additions and 88 deletions

View File

@ -4,6 +4,7 @@ FRONTEND_SUPPORTS_RGB565 = 1
MEDNAFEN_DIR := mednafen
MEDNAFEN_LIBRETRO_DIR := mednafen-libretro
NEED_TREMOR = 0
LIBRETRO_SOURCES :=
ifeq ($(platform),)
platform = unix
@ -71,7 +72,8 @@ else ifeq ($(core), pce-fast)
ifneq ($(platform), osx)
PTHREAD_FLAGS = -pthread
endif
NEED_BPP = 32
HAVE_HES = 0
NEED_BPP = 16
NEED_TREMOR = 1
NEED_BLIP = 1
NEED_CD = 1
@ -79,15 +81,23 @@ endif
NEED_SCSI_CD = 1
NEED_THREADING = 1
NEED_CRC32 = 1
WANT_NEW_API = 1
CORE_DEFINE := -DWANT_PCE_FAST_EMU
CORE_DIR := $(MEDNAFEN_DIR)/pce_fast
CORE_DIR := $(MEDNAFEN_DIR)/pce_fast-09333
CORE_SOURCES := $(CORE_DIR)/huc.cpp \
CORE_SOURCES := \
$(CORE_DIR)/huc.cpp \
$(CORE_DIR)/huc6280.cpp \
$(CORE_DIR)/input.cpp \
$(CORE_DIR)/pce.cpp \
$(CORE_DIR)/tsushin.cpp \
$(CORE_DIR)/pcecd.cpp \
$(CORE_DIR)/pcecd_drive.cpp \
$(CORE_DIR)/psg.cpp \
$(CORE_DIR)/vdc.cpp
ifeq ($(HAVE_HES),1)
CORE_SOURCES += $(CORE_DIR)/hes.cpp
endif
TARGET_NAME := mednafen_pce_fast_libretro
arch = intel
@ -484,6 +494,7 @@ endif
ifeq ($(NEED_CRC32), 1)
FLAGS += -DWANT_CRC32
LIBRETRO_SOURCES += scrc32.cpp
endif
ifeq ($(NEED_DEINTERLACER), 1)
@ -538,7 +549,7 @@ MEDNAFEN_SOURCES := $(MEDNAFEN_DIR)/mednafen.cpp \
$(MEDNAFEN_DIR)/md5.cpp
LIBRETRO_SOURCES := libretro.cpp stubs.cpp $(THREAD_STUBS)
LIBRETRO_SOURCES += libretro.cpp stubs.cpp $(THREAD_STUBS)
TRIO_SOURCES += $(MEDNAFEN_DIR)/trio/trio.c \
$(MEDNAFEN_DIR)/trio/triostr.c
@ -589,6 +600,10 @@ ifeq ($(CACHE_CD), 1)
FLAGS += -D__LIBRETRO_CACHE_CD__
endif
ifeq ($(NEED_BPP), 8)
FLAGS += -DWANT_8BPP
endif
ifeq ($(NEED_BPP), 16)
FLAGS += -DWANT_16BPP
endif
@ -601,6 +616,9 @@ ifeq ($(NEED_BPP), 32)
FLAGS += -DWANT_32BPP
endif
ifeq ($(WANT_NEW_API), 1)
FLAGS += -DWANT_NEW_API
endif
CXXFLAGS += $(FLAGS)
CFLAGS += $(FLAGS)

View File

@ -92,7 +92,7 @@ static bool is_pal = false;
#include "mednafen/cdrom/pcecd.h"
#define MEDNAFEN_CORE_NAME_MODULE "pce_fast"
#define MEDNAFEN_CORE_NAME "Mednafen PCE Fast"
#define MEDNAFEN_CORE_VERSION "v0.9.28"
#define MEDNAFEN_CORE_VERSION "v0.9.33.3"
#define MEDNAFEN_CORE_EXTENSIONS "pce|sgx|cue"
#define MEDNAFEN_CORE_TIMING_FPS 59.82
#define MEDNAFEN_CORE_GEOMETRY_BASE_W (game->nominal_width)

View File

@ -0,0 +1,4 @@
#ifndef _MEDNAFEN_CPUTEST_H
#define _MEDNAFEN_CPUTEST_H
#endif

View File

@ -104,6 +104,27 @@ typedef struct
const InputPortInfoStruct *Types;
} InputInfoStruct;
struct MemoryPatch;
struct CheatFormatStruct
{
const char *FullName; //"Game Genie", "GameShark", "Pro Action Catplay", etc.
const char *Description; // Whatever?
bool (*DecodeCheat)(const std::string& cheat_string, MemoryPatch* patch); // *patch should be left as initialized by MemoryPatch::MemoryPatch(), unless this is the
// second(or third or whatever) part of a multipart cheat.
//
// Will throw an std::exception(or derivative) on format error.
//
// Will return true if this is part of a multipart cheat.
};
struct CheatFormatInfoStruct
{
unsigned NumFormats;
CheatFormatStruct *Formats;
};
// Miscellaneous system/simple commands(power, reset, dip switch toggles, coin insert, etc.)
// (for DoSimpleCommand() )
@ -302,6 +323,10 @@ typedef struct
void (*RemoveReadPatches)(void);
uint8 (*MemRead)(uint32 addr);
#ifdef WANT_NEW_API
CheatFormatInfoStruct *CheatFormatInfo;
#endif
bool SaveStateAltersState; // true for bsnes and some libco-style emulators, false otherwise.
// Main save state routine, called by the save state code in state.cpp.
// When saving, load is set to 0. When loading, load is set to the version field of the save state being loaded.

View File

@ -28,6 +28,9 @@ void MDFN_DebugPrintReal(const char *file, const int line, const char *format, .
void MDFN_LoadGameCheats(void *override);
void MDFN_FlushGameCheats(int nosave);
void MDFN_MidSync(EmulateSpecStruct *espec);
void MDFN_MidLineUpdate(EmulateSpecStruct *espec, int y);
#include "mednafen-driver.h"
#include "mednafen-endian.h"

4
mednafen/movie.h Normal file
View File

@ -0,0 +1,4 @@
#ifndef _MEDNAFEN_MOVIE_H
#define _MEDNAFEN_MOVIE_H
#endif

View File

@ -0,0 +1,8 @@
AUTOMAKE_OPTIONS = subdir-objects
DEFS = -DLOCALEDIR=\"$(datadir)/locale\" @DEFS@
DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/intl -I$(top_srcdir)/src/hw_misc -I$(top_srcdir)/src/hw_sound
noinst_LIBRARIES = libpce_fast.a
mednafen_SOURCES = huc6280.cpp pce.cpp vdc.cpp input.cpp huc.cpp hes.cpp pcecd.cpp pcecd_drive.cpp psg.cpp
libpce_fast_a_SOURCES = $(mednafen_SOURCES)

View File

@ -0,0 +1,634 @@
# Makefile.in generated by automake 1.11.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__make_dryrun = \
{ \
am__dry=no; \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
*) \
for am__flg in $$MAKEFLAGS; do \
case $$am__flg in \
*=*|--*) ;; \
*n*) am__dry=yes; break;; \
esac; \
done;; \
esac; \
test $$am__dry = yes; \
}
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
subdir = src/pce_fast
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cflags_gcc_option.m4 \
$(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/fcntl-o.m4 \
$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glibc2.m4 \
$(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/iconv.m4 \
$(top_srcdir)/m4/intdiv0.m4 $(top_srcdir)/m4/intl.m4 \
$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intmax.m4 \
$(top_srcdir)/m4/inttypes-pri.m4 \
$(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lcmessage.m4 \
$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/longlong.m4 \
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
$(top_srcdir)/m4/printf-posix.m4 $(top_srcdir)/m4/progtest.m4 \
$(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/stdint_h.m4 \
$(top_srcdir)/m4/threadlib.m4 $(top_srcdir)/m4/uintmax_t.m4 \
$(top_srcdir)/m4/visibility.m4 $(top_srcdir)/m4/wchar_t.m4 \
$(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xsize.m4 \
$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/include/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
LIBRARIES = $(noinst_LIBRARIES)
ARFLAGS = cru
AM_V_AR = $(am__v_AR_@AM_V@)
am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
am__v_AR_0 = @echo " AR " $@;
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
libpce_fast_a_AR = $(AR) $(ARFLAGS)
libpce_fast_a_LIBADD =
am__objects_1 = huc6280.$(OBJEXT) pce.$(OBJEXT) vdc.$(OBJEXT) \
input.$(OBJEXT) huc.$(OBJEXT) hes.$(OBJEXT) pcecd.$(OBJEXT) \
pcecd_drive.$(OBJEXT) psg.$(OBJEXT)
am_libpce_fast_a_OBJECTS = $(am__objects_1)
libpce_fast_a_OBJECTS = $(am_libpce_fast_a_OBJECTS)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_CXX = $(am__v_CXX_@AM_V@)
am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
am__v_CXX_0 = @echo " CXX " $@;
CXXLD = $(CXX)
CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
am__v_CXXLD_0 = @echo " CXXLD " $@;
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
SOURCES = $(libpce_fast_a_SOURCES)
DIST_SOURCES = $(libpce_fast_a_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ALLOCA = @ALLOCA@
ALSA_CFLAGS = @ALSA_CFLAGS@
ALSA_LIBS = @ALSA_LIBS@
AMTAR = @AMTAR@
AM_CFLAGS = @AM_CFLAGS@
AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@
CATOBJEXT = @CATOBJEXT@
CC = @CC@
CCAS = @CCAS@
CCASDEPMODE = @CCASDEPMODE@
CCASFLAGS = @CCASFLAGS@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DATADIRNAME = @DATADIRNAME@
DEFS = -DLOCALEDIR=\"$(datadir)/locale\" @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GBA_EXTRA_FLAGS = @GBA_EXTRA_FLAGS@
GENCAT = @GENCAT@
GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
GLIBC2 = @GLIBC2@
GLIBC21 = @GLIBC21@
GMSGFMT = @GMSGFMT@
GMSGFMT_015 = @GMSGFMT_015@
GREP = @GREP@
HAVE_ASPRINTF = @HAVE_ASPRINTF@
HAVE_NEWLOCALE = @HAVE_NEWLOCALE@
HAVE_POSIX_PRINTF = @HAVE_POSIX_PRINTF@
HAVE_SNPRINTF = @HAVE_SNPRINTF@
HAVE_VISIBILITY = @HAVE_VISIBILITY@
HAVE_WPRINTF = @HAVE_WPRINTF@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
INSTOBJEXT = @INSTOBJEXT@
INTLBISON = @INTLBISON@
INTLLIBS = @INTLLIBS@
INTLOBJS = @INTLOBJS@
INTL_DEFAULT_VERBOSITY = @INTL_DEFAULT_VERBOSITY@
INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@
INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
JACK_CFLAGS = @JACK_CFLAGS@
JACK_LIBS = @JACK_LIBS@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCDIO_CFLAGS = @LIBCDIO_CFLAGS@
LIBCDIO_LIBS = @LIBCDIO_LIBS@
LIBICONV = @LIBICONV@
LIBINTL = @LIBINTL@
LIBMULTITHREAD = @LIBMULTITHREAD@
LIBOBJS = @LIBOBJS@
LIBPTH = @LIBPTH@
LIBPTH_PREFIX = @LIBPTH_PREFIX@
LIBS = @LIBS@
LIBTHREAD = @LIBTHREAD@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBC = @LTLIBC@
LTLIBICONV = @LTLIBICONV@
LTLIBINTL = @LTLIBINTL@
LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
LTLIBOBJS = @LTLIBOBJS@
LTLIBPTH = @LTLIBPTH@
LTLIBTHREAD = @LTLIBTHREAD@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MMX_CFLAGS = @MMX_CFLAGS@
MSGFMT = @MSGFMT@
MSGFMT_015 = @MSGFMT_015@
MSGMERGE = @MSGMERGE@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POSUB = @POSUB@
PRI_MACROS_BROKEN = @PRI_MACROS_BROKEN@
RANLIB = @RANLIB@
SDL_CFLAGS = @SDL_CFLAGS@
SDL_CONFIG = @SDL_CONFIG@
SDL_LIBS = @SDL_LIBS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
SNDFILE_LIBS = @SNDFILE_LIBS@
SNES_EXTRA_CXXFLAGS = @SNES_EXTRA_CXXFLAGS@
SNES_EXTRA_FLAGS = @SNES_EXTRA_FLAGS@
SNES_PERF_EXTRA_CXXFLAGS = @SNES_PERF_EXTRA_CXXFLAGS@
SNES_PERF_EXTRA_FLAGS = @SNES_PERF_EXTRA_FLAGS@
SSE2_CFLAGS = @SSE2_CFLAGS@
SSE3_CFLAGS = @SSE3_CFLAGS@
SSE_CFLAGS = @SSE_CFLAGS@
STRIP = @STRIP@
TRIO_CFLAGS = @TRIO_CFLAGS@
USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
WARNING_FLAGS = @WARNING_FLAGS@
WINDRES = @WINDRES@
WOE32 = @WOE32@
WOE32DLL = @WOE32DLL@
XGETTEXT = @XGETTEXT@
XGETTEXT_015 = @XGETTEXT_015@
XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = subdir-objects
DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/intl -I$(top_srcdir)/src/hw_misc -I$(top_srcdir)/src/hw_sound
noinst_LIBRARIES = libpce_fast.a
mednafen_SOURCES = huc6280.cpp pce.cpp vdc.cpp input.cpp huc.cpp hes.cpp pcecd.cpp pcecd_drive.cpp psg.cpp
libpce_fast_a_SOURCES = $(mednafen_SOURCES)
all: all-am
.SUFFIXES:
.SUFFIXES: .cpp .lo .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/pce_fast/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/pce_fast/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstLIBRARIES:
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
libpce_fast.a: $(libpce_fast_a_OBJECTS) $(libpce_fast_a_DEPENDENCIES) $(EXTRA_libpce_fast_a_DEPENDENCIES)
$(AM_V_at)-rm -f libpce_fast.a
$(AM_V_AR)$(libpce_fast_a_AR) libpce_fast.a $(libpce_fast_a_OBJECTS) $(libpce_fast_a_LIBADD)
$(AM_V_at)$(RANLIB) libpce_fast.a
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hes.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/huc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/huc6280.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/input.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pce.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcecd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcecd_drive.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/psg.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vdc.Po@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
.cpp.obj:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.cpp.lo:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
set x; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(LIBRARIES)
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am:
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
clean-libtool clean-noinstLIBRARIES ctags distclean \
distclean-compile distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
install-html-am install-info install-info-am install-man \
install-pdf install-pdf-am install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags uninstall uninstall-am
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View File

@ -0,0 +1,249 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pce.h"
#include "hes.h"
#include "huc.h"
#include "pcecd.h"
#include "../player.h"
#include "../endian.h"
namespace PCE_Fast
{
static uint8 mpr_start[8];
static uint8 IBP_Bank[0x2000];
static uint8 *rom = NULL, *rom_backup = NULL;
static uint8 CurrentSong;
static bool bootstrap;
static bool ROMWriteWarningGiven;
uint8 ReadIBP(unsigned int A)
{
if(!(A & 0x100))
return(IBP_Bank[0x1C00 + (A & 0xF)]);
if(bootstrap)
{
memcpy(rom + 0x1FF0, rom_backup + 0x1FF0, 16);
bootstrap = false;
return(CurrentSong);
}
return(0xFF);
}
static DECLFW(HESROMWrite)
{
rom[A] = V;
//printf("%08x: %02x\n", A, V);
if(!ROMWriteWarningGiven)
{
MDFN_printf(_("Warning: HES is writing to physical address %08x. Future warnings of this nature are temporarily disabled for this HES file.\n"), A);
ROMWriteWarningGiven = TRUE;
}
}
static DECLFR(HESROMRead)
{
return(rom[A]);
}
int PCE_HESLoad(const uint8 *buf, uint32 size)
{
uint32 LoadAddr, LoadSize;
uint32 CurPos;
uint16 InitAddr;
uint8 StartingSong;
int TotalSongs;
InitAddr = MDFN_de16lsb(&buf[0x6]);
CurPos = 0x10;
if(!(rom = (uint8 *)MDFN_malloc(0x88 * 8192, _("HES ROM"))))
{
return(0);
}
if(!(rom_backup = (uint8 *)MDFN_malloc(0x88 * 8192, _("HES ROM"))))
{
return(0);
}
memset(rom, 0, 0x88 * 8192);
memset(rom_backup, 0, 0x88 * 8192);
while(CurPos < (size - 0x10))
{
LoadSize = MDFN_de32lsb(&buf[CurPos + 0x4]);
LoadAddr = MDFN_de32lsb(&buf[CurPos + 0x8]);
//printf("Size: %08x(%d), Addr: %08x, La: %02x\n", LoadSize, LoadSize, LoadAddr, LoadAddr / 8192);
CurPos += 0x10;
if(((uint64)LoadSize + CurPos) > size)
{
uint32 NewLoadSize = size - CurPos;
MDFN_printf(_("Warning: HES is trying to load more data than is present in the file(%u attempted, %u left)!\n"), LoadSize, NewLoadSize);
LoadSize = NewLoadSize;
}
// 0x88 * 8192 = 0x110000
if(((uint64)LoadAddr + LoadSize) > 0x110000)
{
MDFN_printf(_("Warning: HES is trying to load data past boundary.\n"));
if(LoadAddr >= 0x110000)
break;
LoadSize = 0x110000 - LoadAddr;
}
memcpy(rom + LoadAddr, &buf[CurPos], LoadSize);
CurPos += LoadSize;
}
for(int x = 0; x < 8; x++)
mpr_start[x] = buf[0x8 + x];
memcpy(rom_backup, rom, 0x88 * 8192);
CurrentSong = StartingSong = buf[5];
TotalSongs = 256;
memset(IBP_Bank, 0, 0x2000);
uint8 *IBP_WR = IBP_Bank + 0x1C00;
for(int i = 0; i < 8; i++)
{
*IBP_WR++ = 0xA9; // LDA (immediate)
*IBP_WR++ = mpr_start[i];
*IBP_WR++ = 0x53; // TAM
*IBP_WR++ = 1 << i;
}
*IBP_WR++ = 0xAD; // LDA(absolute)
*IBP_WR++ = 0x00; //
*IBP_WR++ = 0x1D; //
*IBP_WR++ = 0x20; // JSR
*IBP_WR++ = InitAddr; // JSR target LSB
*IBP_WR++ = InitAddr >> 8; // JSR target MSB
*IBP_WR++ = 0x58; // CLI
*IBP_WR++ = 0xFC; // (Mednafen Special)
*IBP_WR++ = 0x80; // BRA
*IBP_WR++ = 0xFD; // -3
Player_Init(TotalSongs, "", "", ""); //NULL, NULL, NULL, NULL); //UTF8 **snames);
for(int x = 0; x < 0x80; x++)
{
HuCPUFastMap[x] = rom;
PCERead[x] = HESROMRead;
PCEWrite[x] = HESROMWrite;
}
HuCPUFastMap[0xFF] = IBP_Bank - (0xFF * 8192);
// FIXME: If a HES rip tries to execute a SCSI command, the CD emulation code will probably crash. Obviously, a HES rip shouldn't do this,
// but Mednafen shouldn't crash either. ;)
PCE_IsCD = 1;
PCE_InitCD();
ROMWriteWarningGiven = FALSE;
return(1);
}
static const uint8 BootROM[16] = { 0xA9, 0xFF, 0x53, 0x01, 0xEA, 0xEA, 0xEA, 0xEA,
0xEA, 0xEA, 0xEA, 0x4C, 0x00, 0x1C, 0xF0, 0xFF };
void HES_Reset(void)
{
memcpy(rom, rom_backup, 0x88 * 8192);
memcpy(rom + 0x1FF0, BootROM, 16);
bootstrap = true;
}
void HES_Draw(MDFN_Surface *surface, MDFN_Rect *DisplayRect, int16 *SoundBuf, int32 SoundBufSize)
{
extern uint16 pce_jp_data[5];
static uint8 last = 0;
bool needreload = 0;
uint8 newset = (pce_jp_data[0] ^ last) & pce_jp_data[0];
if(newset & 0x20)
{
CurrentSong++;
needreload = 1;
}
if(newset & 0x80)
{
CurrentSong--;
needreload = 1;
}
if(newset & 0x08)
needreload = 1;
if(newset & 0x10)
{
CurrentSong += 10;
needreload = 1;
}
if(newset & 0x40)
{
CurrentSong -= 10;
needreload = 1;
}
last = pce_jp_data[0];
if(needreload)
PCE_Power();
Player_Draw(surface, DisplayRect, CurrentSong, SoundBuf, SoundBufSize);
}
void HES_Close(void)
{
PCECD_Close();
if(rom)
{
MDFN_free(rom);
rom = NULL;
}
if(rom_backup)
{
MDFN_free(rom_backup);
rom_backup = NULL;
}
}
};

View File

@ -0,0 +1,11 @@
namespace PCE_Fast
{
uint8 ReadIBP(unsigned int A);
void HES_Draw(MDFN_Surface *surface, MDFN_Rect *DisplayRect, int16 *samples, int32 sampcount);
int PCE_HESLoad(const uint8 *buf, uint32 size) MDFN_COLD;
void HES_Reset(void) MDFN_COLD;
void HES_Close(void) MDFN_COLD;
};

View File

@ -0,0 +1,409 @@
/* Mednafen - Multi-system Emulator
*
* Portions of this file Copyright (C) 2004 Ki
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pce.h"
#include <errno.h>
#include "pcecd.h"
#include "arcade_card/arcade_card.h"
#include "../md5.h"
#include "../file.h"
#include "../cdrom/cdromif.h"
#include "../mempatcher.h"
namespace PCE_Fast
{
static const uint8 BRAM_Init_String[8] = { 'H', 'U', 'B', 'M', 0x00, 0x88, 0x10, 0x80 }; //"HUBM\x00\x88\x10\x80";
ArcadeCard *arcade_card = NULL;
static uint8 *HuCROM = NULL;
static bool IsPopulous;
bool PCE_IsCD;
static uint8 SaveRAM[2048];
static DECLFW(ACPhysWrite)
{
arcade_card->PhysWrite(A, V);
}
static DECLFR(ACPhysRead)
{
return(arcade_card->PhysRead(A));
}
static DECLFR(SaveRAMRead)
{
if((!PCE_IsCD || PCECD_IsBRAMEnabled()) && (A & 8191) < 2048)
return(SaveRAM[A & 2047]);
else
return(0xFF);
}
static DECLFW(SaveRAMWrite)
{
if((!PCE_IsCD || PCECD_IsBRAMEnabled()) && (A & 8191) < 2048)
SaveRAM[A & 2047] = V;
}
static DECLFR(HuCRead)
{
return ROMSpace[A];
}
static DECLFW(HuCRAMWrite)
{
ROMSpace[A] = V;
}
static DECLFW(HuCRAMWriteCDSpecial) // Hyper Dyne Special hack
{
BaseRAM[0x2000 | (A & 0x1FFF)] = V;
ROMSpace[A] = V;
}
static uint8 HuCSF2Latch = 0;
static DECLFR(HuCSF2Read)
{
return(HuCROM[(A & 0x7FFFF) + 0x80000 + HuCSF2Latch * 0x80000 ]); // | (HuCSF2Latch << 19) ]);
}
static DECLFW(HuCSF2Write)
{
if((A & 0x1FFC) == 0x1FF0)
{
HuCSF2Latch = (A & 0x3);
}
}
int HuCLoad(const uint8 *data, uint32 len, uint32 crc32)
{
uint32 sf2_threshold = 2048 * 1024;
uint32 sf2_required_size = 2048 * 1024 + 512 * 1024;
uint32 m_len = (len + 8191)&~8191;
bool sf2_mapper = FALSE;
if(m_len >= sf2_threshold)
{
sf2_mapper = TRUE;
if(m_len != sf2_required_size)
m_len = sf2_required_size;
}
IsPopulous = 0;
PCE_IsCD = 0;
md5_context md5;
md5.starts();
md5.update(data, len);
md5.finish(MDFNGameInfo->MD5);
MDFN_printf(_("ROM: %dKiB\n"), (len + 1023) / 1024);
MDFN_printf(_("ROM CRC32: 0x%04x\n"), crc32);
MDFN_printf(_("ROM MD5: 0x%s\n"), md5_context::asciistr(MDFNGameInfo->MD5, 0).c_str());
if(!(HuCROM = (uint8 *)MDFN_malloc(m_len, _("HuCard ROM"))))
{
return(0);
}
memset(HuCROM, 0xFF, m_len);
memcpy(HuCROM, data, (m_len < len) ? m_len : len);
memset(ROMSpace, 0xFF, 0x88 * 8192 + 8192);
if(m_len == 0x60000)
{
memcpy(ROMSpace + 0x00 * 8192, HuCROM, 0x20 * 8192);
memcpy(ROMSpace + 0x20 * 8192, HuCROM, 0x20 * 8192);
memcpy(ROMSpace + 0x40 * 8192, HuCROM + 0x20 * 8192, 0x10 * 8192);
memcpy(ROMSpace + 0x50 * 8192, HuCROM + 0x20 * 8192, 0x10 * 8192);
memcpy(ROMSpace + 0x60 * 8192, HuCROM + 0x20 * 8192, 0x10 * 8192);
memcpy(ROMSpace + 0x70 * 8192, HuCROM + 0x20 * 8192, 0x10 * 8192);
}
else if(m_len == 0x80000)
{
memcpy(ROMSpace + 0x00 * 8192, HuCROM, 0x40 * 8192);
memcpy(ROMSpace + 0x40 * 8192, HuCROM + 0x20 * 8192, 0x20 * 8192);
memcpy(ROMSpace + 0x60 * 8192, HuCROM + 0x20 * 8192, 0x20 * 8192);
}
else
{
memcpy(ROMSpace + 0x00 * 8192, HuCROM, (m_len < 1024 * 1024) ? m_len : 1024 * 1024);
}
for(int x = 0x00; x < 0x80; x++)
{
HuCPUFastMap[x] = ROMSpace;
PCERead[x] = HuCRead;
}
if(!memcmp(HuCROM + 0x1F26, "POPULOUS", strlen("POPULOUS")))
{
uint8 *PopRAM = ROMSpace + 0x40 * 8192;
FILE *fp;
memset(PopRAM, 0xFF, 32768);
if((fp = (FILE*)fopen(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), "rb")))
{
gzread(fp, PopRAM, 32768);
fclose(fp);
}
IsPopulous = 1;
MDFN_printf("Populous\n");
for(int x = 0x40; x < 0x44; x++)
{
HuCPUFastMap[x] = &PopRAM[(x & 3) * 8192] - x * 8192;
PCERead[x] = HuCRead;
PCEWrite[x] = HuCRAMWrite;
}
MDFNMP_AddRAM(32768, 0x40 * 8192, PopRAM);
}
else
{
FILE *fp;
memset(SaveRAM, 0x00, 2048);
memcpy(SaveRAM, BRAM_Init_String, 8); // So users don't have to manually intialize the file cabinet
// in the CD BIOS screen.
if((fp = (FILE*)fopen(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), "rb")))
{
gzread(fp, SaveRAM, 2048);
fclose(fp);
}
PCEWrite[0xF7] = SaveRAMWrite;
PCERead[0xF7] = SaveRAMRead;
MDFNMP_AddRAM(2048, 0xF7 * 8192, SaveRAM);
}
// 0x1A558
//if(len >= 0x20000 && !memcmp(HuCROM + 0x1A558, "STREET FIGHTER#", strlen("STREET FIGHTER#")))
if(sf2_mapper)
{
for(int x = 0x40; x < 0x80; x++)
{
// FIXME: PCE_FAST
HuCPUFastMap[x] = NULL; // Make sure our reads go through our read function, and not a table lookup
PCERead[x] = HuCSF2Read;
}
PCEWrite[0] = HuCSF2Write;
MDFN_printf("Street Fighter 2 Mapper\n");
HuCSF2Latch = 0;
}
return(1);
}
bool IsBRAMUsed(void)
{
if(memcmp(SaveRAM, BRAM_Init_String, 8)) // HUBM string is modified/missing
return(1);
for(int x = 8; x < 2048; x++)
if(SaveRAM[x]) return(1);
return(0);
}
int HuCLoadCD(const char *bios_path)
{
static const FileExtensionSpecStruct KnownBIOSExtensions[] =
{
{ ".pce", gettext_noop("PC Engine ROM Image") },
{ ".bin", gettext_noop("PC Engine ROM Image") },
{ ".bios", gettext_noop("BIOS Image") },
{ NULL, NULL }
};
MDFNFILE fp;
if(!fp.Open(bios_path, KnownBIOSExtensions, _("CD BIOS")))
{
return(0);
}
memset(ROMSpace, 0xFF, 262144);
memcpy(ROMSpace, GET_FDATA(fp) + (GET_FSIZE(fp) & 512), ((GET_FSIZE(fp) & ~512) > 262144) ? 262144 : (GET_FSIZE(fp) &~ 512) );
fp.Close();
PCE_IsCD = 1;
PCE_InitCD();
md5_context md5;
md5.starts();
// md5_update(&md5, HuCROM, 262144);
#if 0
int32 track = CDIF_GetFirstTrack();
int32 last_track = CDIF_GetLastTrack();
bool DTFound = 0;
for(; track <= last_track; track++)
{
CDIF_Track_Format format;
if(CDIF_GetTrackFormat(track, format) && format == CDIF_FORMAT_MODE1)
{
DTFound = 1;
break;
}
}
if(DTFound) // Only add the MD5 hash if we were able to find a data track.
{
uint32 start_sector = CDIF_GetTrackStartPositionLBA(track);
uint8 sector_buffer[2048];
for(int x = 0; x < 128; x++)
{
memset(sector_buffer, 0, 2048);
CDIF_ReadSector(sector_buffer, NULL, start_sector + x, 1);
md5.update(sector_buffer, 2048);
}
}
md5.finish(MDFNGameInfo->MD5);
MDFN_printf(_("CD MD5(first 256KiB): 0x%s\n"), md5_context::asciistr(MDFNGameInfo->MD5, 0).c_str());
#endif
MDFN_printf(_("Arcade Card Emulation: %s\n"), PCE_ACEnabled ? _("Enabled") : _("Disabled"));
for(int x = 0; x < 0x40; x++)
{
HuCPUFastMap[x] = ROMSpace;
PCERead[x] = HuCRead;
}
for(int x = 0x68; x < 0x88; x++)
{
HuCPUFastMap[x] = ROMSpace;
PCERead[x] = HuCRead;
PCEWrite[x] = HuCRAMWrite;
}
PCEWrite[0x80] = HuCRAMWriteCDSpecial; // Hyper Dyne Special hack
MDFNMP_AddRAM(262144, 0x68 * 8192, ROMSpace + 0x68 * 8192);
if(PCE_ACEnabled)
{
try
{
arcade_card = new ArcadeCard();
}
catch(std::exception &e)
{
MDFN_PrintError(_("Error creating %s object: %s"), "ArcadeCard", e.what());
//Cleanup(); // TODO
return(0);
}
for(int x = 0x40; x < 0x44; x++)
{
HuCPUFastMap[x] = NULL;
PCERead[x] = ACPhysRead;
PCEWrite[x] = ACPhysWrite;
}
}
FILE *srp;
memset(SaveRAM, 0x00, 2048);
memcpy(SaveRAM, BRAM_Init_String, 8); // So users don't have to manually intialize the file cabinet
// in the CD BIOS screen.
if((srp = (FILE*)fopen(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), "rb")))
{
gzread(srp, SaveRAM, 2048);
fclose(srp);
}
PCEWrite[0xF7] = SaveRAMWrite;
PCERead[0xF7] = SaveRAMRead;
MDFNMP_AddRAM(2048, 0xF7 * 8192, SaveRAM);
return(1);
}
int HuC_StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT StateRegs[] =
{
SFARRAY(ROMSpace + 0x40 * 8192, IsPopulous ? 32768 : 0),
SFARRAY(SaveRAM, IsPopulous ? 0 : 2048),
SFARRAY(ROMSpace + 0x68 * 8192, PCE_IsCD ? 262144 : 0),
SFVAR(HuCSF2Latch),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "HuC");
if(load)
HuCSF2Latch &= 0x3;
if(PCE_IsCD)
{
ret &= PCECD_StateAction(sm, load, data_only);
if(arcade_card)
ret &= arcade_card->StateAction(sm, load, data_only);
}
return(ret);
}
void HuCClose(void)
{
if(IsPopulous)
{
MDFN_DumpToFile(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), 6, ROMSpace + 0x40 * 8192, 32768);
}
else if(IsBRAMUsed())
{
MDFN_DumpToFile(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), 0, SaveRAM, 2048);
}
if(arcade_card)
{
delete arcade_card;
arcade_card = NULL;
}
if(PCE_IsCD)
{
PCECD_Close();
}
if(HuCROM)
{
MDFN_free(HuCROM);
HuCROM = NULL;
}
}
void HuC_Power(void)
{
if(PCE_IsCD)
memset(ROMSpace + 0x68 * 8192, 0x00, 262144);
if(arcade_card)
arcade_card->Power();
}
};

View File

@ -0,0 +1,16 @@
namespace PCE_Fast
{
int HuCLoad(const uint8 *data, uint32 len, uint32 crc32) MDFN_COLD;
int HuCLoadCD(const char *bios_path) MDFN_COLD;
void HuCClose(void) MDFN_COLD;
int HuC_StateAction(StateMem *sm, int load, int data_only);
void HuC_Power(void) MDFN_COLD;
DECLFR(PCE_ACRead);
DECLFW(PCE_ACWrite);
extern bool PCE_IsCD;
};

View File

@ -0,0 +1,785 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pce.h"
#include "vdc.h"
namespace PCE_Fast
{
HuC6280 HuCPU;
uint8 *HuCPUFastMap[0x100];
#define HU_PC PC_local //HuCPU.PC
#define HU_PC_base HuCPU.PC_base
#define HU_A HuCPU.A
#define HU_X X_local //HuCPU.X
#define HU_Y Y_local //HuCPU.Y
#define HU_S HuCPU.S
#define HU_P P_local //HuCPU.P
#define HU_PI HuCPU.mooPI
#define HU_IRQlow HuCPU.IRQlow
#define HU_Page1 Page1_local
//HuCPU.Page1
//Page1_local //HuCPU.Page1
#ifdef HUC6280_LAZY_FLAGS
#define HU_ZNFlags HuCPU.ZNFlags
#endif
#ifdef HUC6280_CRAZY_VERSION
#define LOAD_LOCALS_PC() register uint8 *PC_local = HuCPU.PC;
#else
#define LOAD_LOCALS_PC() register uint32 PC_local /*asm ("edi")*/ = HuCPU.PC; // asm ("edi") = HuCPU.PC;
#endif
#define LOAD_LOCALS() \
LOAD_LOCALS_PC(); \
uint8 X_local = HuCPU.X; \
uint8 Y_local = HuCPU.Y; \
uint8 P_local = HuCPU.P; \
uint8 *Page1_local = HuCPU.Page1;
#define SAVE_LOCALS() HuCPU.PC = PC_local; \
HuCPU.X = X_local; \
HuCPU.Y = Y_local; \
HuCPU.P = P_local; \
HuCPU.Page1 = Page1_local;
#ifdef HUC6280_LAZY_FLAGS
#define COMPRESS_FLAGS() HU_P &= ~(N_FLAG | Z_FLAG); HU_P |= ((HU_ZNFlags >> 24) & 0x80) | ((HU_ZNFlags & 0xFF) ? 0 : Z_FLAG);
//((((HU_ZNFlags & 0xFF) - 1) >> 8) & Z_FLAG);
#define EXPAND_FLAGS() HU_ZNFlags = (HU_P << 24) | ((HU_P & Z_FLAG) ^ Z_FLAG);
#else
#define COMPRESS_FLAGS()
#define EXPAND_FLAGS()
#endif
#ifdef HUC6280_CRAZY_VERSION
#define GetRealPC() ((unsigned int)(HU_PC - HU_PC_base))
#define GetRealPC_EXTERNAL() ((unsigned int)(HuCPU.PC - HuCPU.PC_base))
#else
#define GetRealPC() (HU_PC)
#define GetRealPC_EXTERNAL() (HuCPU.PC)
#endif
#ifdef HUC6280_CRAZY_VERSION
#define SetPC(value) { unsigned int tempmoo = value; HU_PC = &HuCPU.FastPageR[tempmoo >> 13][tempmoo]; \
HU_PC_base = HU_PC - tempmoo; }
#define SetPC_EXTERNAL(value) { unsigned int tempmoo = value; \
HuCPU.PC = &HuCPU.FastPageR[tempmoo >> 13][tempmoo]; HuCPU.PC_base = HuCPU.PC - tempmoo; }
#else
#define SetPC(value) { HU_PC = (value); }
#define SetPC_EXTERNAL(value) { HuCPU.PC = (value); }
#endif
// Page change PC, GET IT?!
#ifdef HUC6280_CRAZY_VERSION
#define FixPC_PC() SetPC(GetRealPC());
#else
#define FixPC_PC()
#endif
//#define IncPC() { HU_PC++; if(!(GetRealPC() & 0x1FFF)) printf("Bank crossing: %04x\n", GetRealPC()); }
//#define IncPC() HU_PC++;
#if 0
#define IncPC() { HU_PC++; if(!(GetRealPC() & 0x1FFF) && \
HuCPU.MPR[(GetRealPC() - 1) >> 13] != (HuCPU.MPR[(GetRealPC()) >> 13] - 1)) \
printf("Bank crossing: %04x, %02x, %02x\n", GetRealPC(), HuCPU.MPR[(GetRealPC() - 1) >> 13], \
HuCPU.MPR[GetRealPC() >> 13]); }
#else
#define IncPC() HU_PC++;
#endif
#ifdef HUC6280_CRAZY_VERSION
#define RdAtPC() (*HU_PC)
//#define RdAtAndIncPC_16() (HU_PC += 2, *(uint16 *)(HU_PC - 2))
#else
#define RdAtPC() RdOp(HU_PC)
//#define RdAtAndIncPC_16() (RdOp(HU_PC++) | ((RdOp(HU_PC++) << 8)))
#endif
// If we change this definition, we'll need to also fix HuC6280_StealCycle() in huc6280.h
#define ADDCYC(x) { HuCPU.timestamp += x; }
static uint8 dummy_bank[8192 + 8192]; // + 8192 for PC-as-ptr safety padding
#define SET_MPR(arg_i, arg_v) \
{ \
const unsigned int wmpr = arg_i, wbank = arg_v; \
if(wmpr == 1) \
{ \
if(wbank != 0xF8 || !HuCPUFastMap[wbank]) \
printf("Crazy page 1: %02x\n", wbank); \
HU_Page1 = HuCPUFastMap[wbank] ? HuCPUFastMap[wbank] + wbank * 8192 : dummy_bank; \
} \
HuCPU.MPR[wmpr] = wbank; \
HuCPU.FastPageR[wmpr] = HuCPUFastMap[wbank] ? (HuCPUFastMap[wbank] + wbank * 8192) - wmpr * 8192 : (dummy_bank - wmpr * 8192); \
}
void HuC6280_SetMPR(int i, int v)
{
uint8 *Page1_local = HuCPU.Page1;
SET_MPR(i, v);
HuCPU.Page1 = Page1_local;
}
static void HuC6280_FlushMPRCache(void)
{
for(int x = 0; x < 9; x++)
HuC6280_SetMPR(x, HuCPU.MPR[x & 0x7]);
}
static INLINE uint8 RdMem(unsigned int A)
{
uint8 wmpr = HuCPU.MPR[A >> 13];
return(PCERead[wmpr]((wmpr << 13) | (A & 0x1FFF)));
}
static INLINE uint16 RdMem16(unsigned int A)
{
return(RdMem(A) | (RdMem(A + 1) << 8));
}
static INLINE void WrMem(unsigned int A, uint8 V)
{
uint8 wmpr = HuCPU.MPR[A >> 13];
PCEWrite[wmpr]((wmpr << 13) | (A & 0x1FFF), V);
}
static INLINE uint8 RdOp(unsigned int A)
{
return(HuCPU.FastPageR[A >> 13][A]);
}
#define PUSH(V) \
{ \
HU_Page1[0x100 + HU_S] = V; \
HU_S--; \
}
#define PUSH_PC() \
{ \
unsigned int real_pc = GetRealPC(); \
PUSH(real_pc >> 8); \
PUSH(real_pc); \
}
#define POP() HU_Page1[0x100 + ++HU_S]
#define POP_PC() \
{ \
unsigned int npc; \
npc = POP(); \
npc |= POP() << 8; \
SetPC(npc); \
}
// Hopefully we never RTS to 0x0000. ;)
#define POP_PC_AP() \
{ \
uint32 npc; \
npc = POP(); \
npc |= POP() << 8; \
npc++; \
SetPC(npc); \
}
/* Some of these operations will only make sense if you know what the flag
constants are. */
#ifdef HUC6280_LAZY_FLAGS
#define X_ZN(zort) { HU_ZNFlags = (int32)(int8)(uint8)(zort); }
#define X_ZN_BIT(opres, argie) { HU_ZNFlags = (opres) | ((argie) << 24); }
#else
static uint8 ZNTable[256];
#define X_ZN(zort) HU_P&=~(Z_FLAG|N_FLAG);HU_P|=ZNTable[zort]
#define X_ZN_BIT(opres, argie) { HU_P &= ~(Z_FLAG | N_FLAG); HU_P |= ZNTable[opres] & Z_FLAG; HU_P |= argie & N_FLAG; }
#endif
#define JR(cond) \
{ \
if(cond) \
{ \
int32 disp; \
disp = 1 + (int8)RdAtPC(); \
ADDCYC(2); \
HU_PC+=disp; \
} \
else IncPC(); \
}
#define BRA \
{ \
int32 disp; \
disp = 1 + (int8)RdAtPC(); \
HU_PC+=disp; \
}
#define BBRi(bitto) JR(!(x & (1 << bitto)))
#define BBSi(bitto) JR(x & (1 << bitto))
#define ST0 VDC_Write_ST(0, x)
#define ST1 VDC_Write_ST(2, x)
#define ST2 VDC_Write_ST(3, x)
#define LDA HU_A=x;X_ZN(HU_A)
#define LDX HU_X=x;X_ZN(HU_X)
#define LDY HU_Y=x;X_ZN(HU_Y)
/* All of the freaky arithmetic operations. */
#define AND HU_A&=x;X_ZN(HU_A);
// FIXME:
#define BIT HU_P&=~V_FLAG; X_ZN_BIT(x & HU_A, x); HU_P |= x & V_FLAG;
#define EOR HU_A^=x;X_ZN(HU_A);
#define ORA HU_A|=x;X_ZN(HU_A);
#define ADC { \
if(HU_P & D_FLAG) \
{ \
uint32 low = (HU_A & 0x0F) + (x & 0x0F) + (HU_P & 1); \
uint32 high = (HU_A & 0xF0) + (x & 0xF0); \
HU_P &= ~C_FLAG; \
if(low > 0x09) { high += 0x10; low += 0x06; } \
if(high > 0x90) { high += 0x60; } \
HU_P |= (high >> 8) & C_FLAG; \
HU_A = (low & 0x0F) | (high & 0xF0); \
X_ZN(HU_A); \
} \
else \
{ \
uint32 l=HU_A+x+(HU_P&1); \
HU_P&=~(C_FLAG|V_FLAG); \
HU_P|=((((HU_A^x)&0x80)^0x80) & ((HU_A^l)&0x80))>>1; \
HU_P|=(l>>8)&C_FLAG; \
HU_A=l; \
X_ZN(HU_A); \
} \
}
#define SBC if(HU_P & D_FLAG) \
{ \
uint32 c = (HU_P & 1) ^ 1; \
uint32 l = HU_A - x - c; \
uint32 low = (HU_A & 0x0f) - (x & 0x0f) - c; \
uint32 high = (HU_A & 0xf0) - (x & 0xf0); \
HU_P &= ~(C_FLAG); \
if(low & 0xf0) low -= 0x06; \
if(low & 0x80) high -= 0x10; \
if(high & 0x0f00) high -= 0x60; \
HU_P |= ((l >> 8) & C_FLAG) ^ C_FLAG; \
HU_A = (low & 0x0F) | (high & 0xf0); \
X_ZN(HU_A); \
} else { \
uint32 l=HU_A-x-((HU_P&1)^1); \
HU_P&=~(C_FLAG|V_FLAG); \
HU_P|=((HU_A^l)&(HU_A^x)&0x80)>>1; \
HU_P|=((l>>8)&C_FLAG)^C_FLAG; \
HU_A=l; \
X_ZN(HU_A); \
}
#define CMPL(a1,a2) { \
uint32 t=a1-a2; \
X_ZN(t&0xFF); \
HU_P&=~C_FLAG; \
HU_P|=((t>>8)&C_FLAG)^C_FLAG; \
}
#define TAM for(int i = 0; i < 8; i ++) { \
if(x & (1 << i)) \
{ \
SET_MPR(i, HU_A); \
} \
} SET_MPR(8, HuCPU.MPR[0]);
#define TMA for(int i = 0; i < 8; i ++) { \
if(x & (1 << i)) \
HU_A = HuCPU.MPR[i]; \
}
#define CSL
#define CSH
#define RMB(bitto) x &= ~(1 << (bitto & 7))
#define SMB(bitto) x |= 1 << (bitto & 7)
// FIXME
#define TSB { HU_P &= ~V_FLAG; X_ZN_BIT(x | HU_A, x); HU_P |= x & V_FLAG; x |= HU_A; }
#define TRB { HU_P &= ~V_FLAG; X_ZN_BIT(x & ~HU_A, x); HU_P |= x & V_FLAG; x &= ~HU_A; }
#define TST { HU_P &= ~V_FLAG; X_ZN_BIT(x & zoomhack, x); HU_P |= x & V_FLAG; }
#define CMP CMPL(HU_A,x)
#define CPX CMPL(HU_X,x)
#define CPY CMPL(HU_Y,x)
/* The following operations modify the byte being worked on. */
#define DEC x--;X_ZN(x)
#define INC x++;X_ZN(x)
#define ASL HU_P&=~C_FLAG;HU_P|=x>>7;x<<=1;X_ZN(x)
#define LSR HU_P&=~C_FLAG;HU_P|=x&1;x>>=1;X_ZN(x)
#define ROL { \
uint8 l=x>>7; \
x<<=1; \
x|=HU_P&C_FLAG; \
HU_P&=~C_FLAG; \
HU_P|=l; \
X_ZN(x); \
}
#define ROR { \
uint8 l=x&1; \
x>>=1; \
x|=(HU_P&C_FLAG)<<7; \
HU_P&=~C_FLAG; \
HU_P|=l; \
X_ZN(x); \
}
/* Absolute */
#define GetAB(target) \
{ \
target=RdAtPC(); \
IncPC(); \
target|=RdAtPC()<<8; \
IncPC(); \
}
/* Absolute Indexed(for reads) */
#define GetABI(target, i) \
{ \
unsigned int tmp; \
GetAB(tmp); \
target=tmp; \
target+=i; \
}
/* Zero Page */
#define GetZP(target) \
{ \
target=RdAtPC(); \
IncPC(); \
}
/* Zero Page Indexed */
#define GetZPI(target,i) \
{ \
target=i+RdAtPC(); \
IncPC(); \
}
/* Indirect */
#define GetIND(target) \
{ \
uint8 tmp; \
tmp=RdAtPC(); \
IncPC(); \
target=HU_Page1[tmp]; \
tmp++; \
target|=HU_Page1[tmp]<<8; \
}
/* Indexed Indirect */
#define GetIX(target) \
{ \
uint8 tmp; \
tmp=RdAtPC(); \
IncPC(); \
tmp+=HU_X; \
target=HU_Page1[tmp]; \
tmp++; \
target|=HU_Page1[tmp] <<8; \
}
/* Indirect Indexed(for reads) */
#define GetIY(target) \
{ \
unsigned int rt; \
uint8 tmp; \
tmp=RdAtPC(); \
rt=HU_Page1[tmp]; \
tmp++; \
rt|=HU_Page1[tmp]<<8; \
target = (rt + HU_Y); \
IncPC(); \
}
/* Now come the macros to wrap up all of the above stuff addressing mode functions
and operation macros. Note that operation macros will always operate(redundant
redundant) on the variable "x".
*/
#define RMW_A(op) {uint8 x=HU_A; op; HU_A=x; break; } /* Meh... */
#define RMW_AB(op) {unsigned int EA; uint8 x; GetAB(EA); x=RdMem(EA); op; WrMem(EA,x); break; }
#define RMW_ABI(reg,op) {unsigned int EA; uint8 x; GetABI(EA,reg); x=RdMem(EA); op; WrMem(EA,x); break; }
#define RMW_ABX(op) RMW_ABI(HU_X,op)
#define RMW_ABY(op) RMW_ABI(HU_Y,op)
#define RMW_IND(op) { unsigned int EA; uint8 x; GetIND(EA); x = RdMem(EA); op; WrMem(EA, x); break; }
#define RMW_IX(op) { unsigned int EA; uint8 x; GetIX(EA); x=RdMem(EA); op; WrMem(EA,x); break; }
#define RMW_IY(op) { unsigned int EA; uint8 x; GetIY(EA); x=RdMem(EA); op; WrMem(EA,x); break; }
#define RMW_ZP(op) { uint8 EA; uint8 x; GetZP(EA); x=HU_Page1[EA]; op; HU_Page1[EA] = x; break; }
#define RMW_ZPX(op) { uint8 EA; uint8 x; GetZPI(EA,HU_X); x=HU_Page1[EA]; op; HU_Page1[EA] = x; break;}
#define LD_IM(op) { uint8 x; x=RdAtPC(); IncPC(); op; break; }
#define LD_ZP(op) { uint8 EA; uint8 x; GetZP(EA); x=HU_Page1[EA]; op; break; }
#define LD_ZPX(op) { uint8 EA; uint8 x; GetZPI(EA,HU_X); x=HU_Page1[EA]; op; break; }
#define LD_ZPY(op) { uint8 EA; uint8 x; GetZPI(EA,HU_Y); x=HU_Page1[EA]; op; break; }
#define LD_AB(op) { unsigned int EA; uint8 x; GetAB(EA); x=RdMem(EA); op; break; }
#define LD_ABI(reg,op) { unsigned int EA; uint8 x; GetABI(EA,reg); x=RdMem(EA); op; break; }
#define LD_ABX(op) LD_ABI(HU_X,op)
#define LD_ABY(op) LD_ABI(HU_Y,op)
#define LD_IND(op) { unsigned int EA; uint8 x; GetIND(EA); x=RdMem(EA); op; break; }
#define LD_IX(op) { unsigned int EA; uint8 x; GetIX(EA); x=RdMem(EA); op; break; }
#define LD_IY(op) { unsigned int EA; uint8 x; GetIY(EA); x=RdMem(EA); op; break; }
#define BMT_PREHONK(pork) HuCPU.in_block_move = IBM_##pork;
#define BMT_HONKHONK(pork) if(HuCPU.timestamp >= next_user_event) goto GetOutBMT; continue_the_##pork:
#define BMT_TDD BMT_PREHONK(TDD); do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src--; HuCPU.bmt_dest--; BMT_HONKHONK(TDD); HuCPU.bmt_length--; } while(HuCPU.bmt_length);
#define BMT_TAI BMT_PREHONK(TAI); {HuCPU.bmt_alternate = 0; do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src + HuCPU.bmt_alternate)); HuCPU.bmt_dest++; HuCPU.bmt_alternate ^= 1; BMT_HONKHONK(TAI); HuCPU.bmt_length--; } while(HuCPU.bmt_length); }
#define BMT_TIA BMT_PREHONK(TIA); {HuCPU.bmt_alternate = 0; do { ADDCYC(6); WrMem(HuCPU.bmt_dest + HuCPU.bmt_alternate, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src++; HuCPU.bmt_alternate ^= 1; BMT_HONKHONK(TIA); HuCPU.bmt_length--; } while(HuCPU.bmt_length); }
#define BMT_TII BMT_PREHONK(TII); do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src++; HuCPU.bmt_dest++; BMT_HONKHONK(TII); HuCPU.bmt_length--; } while(HuCPU.bmt_length);
#define BMT_TIN BMT_PREHONK(TIN); do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src++; BMT_HONKHONK(TIN); HuCPU.bmt_length--; } while(HuCPU.bmt_length);
// Block memory transfer load
#define LD_BMT(op) { PUSH(HU_Y); PUSH(HU_A); PUSH(HU_X); GetAB(HuCPU.bmt_src); GetAB(HuCPU.bmt_dest); GetAB(HuCPU.bmt_length); op; HuCPU.in_block_move = 0; HU_X = POP(); HU_A = POP(); HU_Y = POP(); break; }
#define ST_ZP(r) {uint8 EA; GetZP(EA); HU_Page1[EA] = r; break;}
#define ST_ZPX(r) {uint8 EA; GetZPI(EA,HU_X); HU_Page1[EA] = r; break;}
#define ST_ZPY(r) {uint8 EA; GetZPI(EA,HU_Y); HU_Page1[EA] = r; break;}
#define ST_AB(r) {unsigned int EA; GetAB(EA); WrMem(EA, r); break;}
#define ST_ABI(reg,r) {unsigned int EA; GetABI(EA,reg); WrMem(EA,r); break; }
#define ST_ABX(r) ST_ABI(HU_X,r)
#define ST_ABY(r) ST_ABI(HU_Y,r)
#define ST_IND(r) {unsigned int EA; GetIND(EA); WrMem(EA,r); break; }
#define ST_IX(r) {unsigned int EA; GetIX(EA); WrMem(EA,r); break; }
#define ST_IY(r) {unsigned int EA; GetIY(EA); WrMem(EA,r); break; }
static const uint8 CycTable[256] =
{
/*0x00*/ 8, 7, 3, 4, 6, 4, 6, 7, 3, 2, 2, 2, 7, 5, 7, 6,
/*0x10*/ 2, 7, 7, 4, 6, 4, 6, 7, 2, 5, 2, 2, 7, 5, 7, 6,
/*0x20*/ 7, 7, 3, 4, 4, 4, 6, 7, 4, 2, 2, 2, 5, 5, 7, 6,
/*0x30*/ 2, 7, 7, 2, 4, 4, 6, 7, 2, 5, 2, 2, 5, 5, 7, 6,
/*0x40*/ 7, 7, 3, 4, 8, 4, 6, 7, 3, 2, 2, 2, 4, 5, 7, 6,
/*0x50*/ 2, 7, 7, 5, 3, 4, 6, 7, 2, 5, 3, 2, 2, 5, 7, 6,
/*0x60*/ 7, 7, 2, 2, 4, 4, 6, 7, 4, 2, 2, 2, 7, 5, 7, 6,
/*0x70*/ 2, 7, 7, 17, 4, 4, 6, 7, 2, 5, 4, 2, 7, 5, 7, 6,
/*0x80*/ 4, 7, 2, 7, 4, 4, 4, 7, 2, 2, 2, 2, 5, 5, 5, 6,
/*0x90*/ 2, 7, 7, 8, 4, 4, 4, 7, 2, 5, 2, 2, 5, 5, 5, 6,
/*0xA0*/ 2, 7, 2, 7, 4, 4, 4, 7, 2, 2, 2, 2, 5, 5, 5, 6,
/*0xB0*/ 2, 7, 7, 8, 4, 4, 4, 7, 2, 5, 2, 2, 5, 5, 5, 6,
/*0xC0*/ 2, 7, 2, 17, 4, 4, 6, 7, 2, 2, 2, 2, 5, 5, 7, 6,
/*0xD0*/ 2, 7, 7, 17, 3, 4, 6, 7, 2, 5, 3, 2, 2, 5, 7, 6,
/*0xE0*/ 2, 7, 2, 17, 4, 4, 6, 7, 2, 2, 2, 2, 5, 5, 7, 6,
/*0xF0*/ 2, 7, 7, 17, 2, 4, 6, 7, 2, 5, 4, 2, 2, 5, 7, 6,
};
#if 0
static bool WillIRQOccur(void) NO_INLINE;
static bool WillIRQOccur(void)
{
bool ret = false;
if(HU_IRQlow)
{
if(!(HU_PI&I_FLAG))
{
if(HU_IRQlow & MDFN_IQTIMER & HuCPU.IRQMaskDelay)
ret = true;
else if((HU_IRQlow & MDFN_IQIRQ1 & HuCPU.IRQMaskDelay) || ((HU_IRQlow >> 8) & MDFN_IQIRQ1 & HuCPU.IRQMaskDelay))
ret = true;
else if(HU_IRQlow & MDFN_IQIRQ2 & HuCPU.IRQMaskDelay)
ret = true;
}
}
return(true);
}
#endif
void HuC6280_IRQBegin(int w)
{
HU_IRQlow|=w;
}
void HuC6280_IRQEnd(int w)
{
HU_IRQlow&=~w;
}
void HuC6280_Reset(void)
{
HuCPU.timer_next_timestamp = HuCPU.timestamp + 1024;
HuCPU.timer_load = 0;
HuCPU.timer_value = 0;
HuCPU.timer_status = 0;
HuCPU.in_block_move = 0;
unsigned int npc;
HuCPU.IRQMask = HuCPU.IRQMaskDelay = 7;
HuC6280_SetMPR(0, 0xFF);
HuC6280_SetMPR(8, 0xFF);
HuC6280_SetMPR(1, 0xF8);
for(int i = 2; i < 8; i++)
HuC6280_SetMPR(i, 0);
npc = RdMem16(0xFFFE);
#define PC_local HuCPU.PC
SetPC(npc);
#undef PC_local
HuCPU.mooPI = I_FLAG;
HuCPU.P = I_FLAG;
HU_IRQlow = 0;
}
void HuC6280_Init(void)
{
memset((void *)&HuCPU,0,sizeof(HuCPU));
memset(dummy_bank, 0, sizeof(dummy_bank));
#ifdef HUC6280_LAZY_FLAGS
#else
for(int x=0; x < 256; x++)
if(!x) ZNTable[x]=Z_FLAG;
else if (x&0x80) ZNTable[x]=N_FLAG;
else ZNTable[x]=0;
#endif
}
void HuC6280_Power(void)
{
HuCPU.IRQlow = 0;
HuCPU.A = 0;
HuCPU.X = 0;
HuCPU.Y = 0;
HuCPU.S = 0;
HuCPU.P = 0;
HuCPU.mooPI = 0;
#if 0
HU_PC = HU_PC_base = NULL;
#else
HuCPU.PC = 0;
#endif
HuCPU.timestamp = 0;
for(int i = 0; i < 9; i++)
{
HuCPU.MPR[i] = 0;
HuCPU.FastPageR[i] = NULL;
}
HuC6280_Reset();
}
void HuC6280_Run(int32 cycles)
{
const int32 next_user_event = HuCPU.previous_next_user_event + cycles * pce_overclocked;
HuCPU.previous_next_user_event = next_user_event;
LOAD_LOCALS();
if(HuCPU.timestamp >= next_user_event)
return;
int32 next_event;
if(HuCPU.in_block_move)
{
next_event = (next_user_event < HuCPU.timer_next_timestamp) ? next_user_event : HuCPU.timer_next_timestamp;
switch(HuCPU.in_block_move)
{
case IBM_TIA: goto continue_the_TIA;
case IBM_TAI: goto continue_the_TAI;
case IBM_TDD: goto continue_the_TDD;
case IBM_TII: goto continue_the_TII;
case IBM_TIN: goto continue_the_TIN;
}
}
while(MDFN_LIKELY(HuCPU.timestamp < next_user_event))
{
next_event = (next_user_event < HuCPU.timer_next_timestamp) ? next_user_event : HuCPU.timer_next_timestamp;
while(MDFN_LIKELY(HuCPU.timestamp < next_event))
{
uint8 b1;
if(HU_IRQlow)
{
if(!(HU_PI&I_FLAG))
{
uint32 tmpa = 0;
if(HU_IRQlow & MDFN_IQTIMER & HuCPU.IRQMaskDelay)
tmpa = 0xFFFA;
else if((HU_IRQlow & MDFN_IQIRQ1 & HuCPU.IRQMaskDelay) || ((HU_IRQlow >> 8) & MDFN_IQIRQ1 & HuCPU.IRQMaskDelay))
tmpa = 0xFFF8;
else if(HU_IRQlow & MDFN_IQIRQ2 & HuCPU.IRQMaskDelay)
tmpa = 0xFFF6;
if(tmpa)
{
unsigned int npc;
ADDCYC(8);
PUSH_PC();
COMPRESS_FLAGS();
PUSH((HU_P&~B_FLAG));
HU_P |= I_FLAG;
HU_P &= ~(T_FLAG | D_FLAG);
HU_PI = HU_P;
npc = RdMem16(tmpa);
SetPC(npc);
if(tmpa == 0xFFF8)
HU_IRQlow &= ~0x200;
continue;
}
}
} // end if(HU_IRQlow)
//printf("%04x\n", GetRealPC());
HU_PI = HU_P;
HuCPU.IRQMaskDelay = HuCPU.IRQMask;
b1 = RdAtPC();
ADDCYC(CycTable[b1]);
IncPC();
switch(b1)
{
#include "huc6280_ops.inc"
}
#ifndef HUC6280_EXTRA_CRAZY
FixPC_PC();
#endif
} // end while(HuCPU.timestamp < next_event)
while(HuCPU.timestamp >= HuCPU.timer_next_timestamp)
{
HuCPU.timer_next_timestamp += 1024 * pce_overclocked;
if(HuCPU.timer_status)
{
HuCPU.timer_value --;
if(HuCPU.timer_value < 0)
{
HuCPU.timer_value = HuCPU.timer_load;
HuC6280_IRQBegin(MDFN_IQTIMER);
}
}
}
} // end while(HuCPU.timestamp < next_user_event)
GetOutBMT:
SAVE_LOCALS();
}
void HuC6280_ResetTS(void)
{
HuCPU.timer_next_timestamp -= HuCPU.timestamp;
HuCPU.previous_next_user_event -= HuCPU.timestamp;
HuCPU.timestamp = 0;
}
int HuC6280_StateAction(StateMem *sm, int load, int data_only)
{
uint16 tmp_PC = GetRealPC_EXTERNAL();
#define P_local HuCPU.P
COMPRESS_FLAGS();
SFORMAT SFCPU[]=
{
SFVARN(tmp_PC, "PC"),
SFVARN(HuCPU.A, "A"),
SFVARN(HuCPU.P, "P"),
SFVARN(HuCPU.X, "X"),
SFVARN(HuCPU.Y, "Y"),
SFVARN(HuCPU.S, "S"),
SFVARN(HuCPU.mooPI, "PI"),
SFVARN(HuCPU.IRQMask, "IRQMask"),
SFVARN(HuCPU.IRQMaskDelay, "IRQMaskDelay"),
SFARRAYN(HuCPU.MPR, 8, "MPR"),
SFVARN(HuCPU.timer_status, "timer_status"),
SFVARN(HuCPU.timer_value, "timer_value"),
SFVARN(HuCPU.timer_load, "timer_load"),
SFVARN(HuCPU.IRQlow, "IRQlow"),
SFVARN(HuCPU.in_block_move, "IBM"),
SFVARN(HuCPU.bmt_src, "IBM_SRC"),
SFVARN(HuCPU.bmt_dest, "IBM_DEST"),
SFVARN(HuCPU.bmt_length, "IBM_LENGTH"),
SFVARN(HuCPU.bmt_alternate, "IBM_ALTERNATE"),
SFVARN(HuCPU.timestamp, "timestamp"),
SFVARN(HuCPU.timer_next_timestamp, "timer_next_timestamp"),
SFVARN(HuCPU.previous_next_user_event, "previous_next_user_event"),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, SFCPU, "CPU");
if(load)
{
// Update MPR cache
HuC6280_FlushMPRCache();
// This must be after the MPR cache is updated:
SetPC_EXTERNAL(tmp_PC);
}
EXPAND_FLAGS();
#undef P_local
return(ret);
}
};

View File

@ -0,0 +1,156 @@
#ifndef _HuC6280H
#define HUC6280_CRAZY_VERSION
//#define HUC6280_EXTRA_CRAZY
#define HUC6280_LAZY_FLAGS
namespace PCE_Fast
{
typedef struct __HuC6280
{
#ifdef HUC6280_CRAZY_VERSION
uint8 *PC, *PC_base;
#else
uint16 PC;
#endif
uint8 A,X,Y,S,P,mooPI;
#ifdef HUC6280_LAZY_FLAGS
uint32 ZNFlags;
#endif
uint8 MPR[9]; // 8, + 1 for PC overflow from $ffff to $10000
uint8 *FastPageR[9];
uint8 *Page1;
//uint8 *PAGE1_W;
//const uint8 *PAGE1_R;
uint32 IRQlow; /* Simulated IRQ pin held low(or is it high?).
And other junk hooked on for speed reasons.*/
int32 timestamp;
uint8 IRQMask, IRQMaskDelay;
uint8 timer_status;
int32 timer_value, timer_load;
int32 timer_next_timestamp;
uint32 in_block_move;
uint16 bmt_src, bmt_dest, bmt_length;
uint32 bmt_alternate;
#define IBM_TIA 1
#define IBM_TAI 2
#define IBM_TDD 3
#define IBM_TII 4
#define IBM_TIN 5
int32 previous_next_user_event;
} HuC6280;
void HuC6280_Run(int32 cycles);
void HuC6280_ResetTS(void);
extern HuC6280 HuCPU;
extern uint8 *HuCPUFastMap[0x100];
#define N_FLAG 0x80
#define V_FLAG 0x40
#define T_FLAG 0x20
#define B_FLAG 0x10
#define D_FLAG 0x08
#define I_FLAG 0x04
#define Z_FLAG 0x02
#define C_FLAG 0x01
#define NTSC_CPU 1789772.7272727272727272
#define PAL_CPU 1662607.125
#define MDFN_IQIRQ1 0x002
#define MDFN_IQIRQ2 0x001
#define MDFN_IQTIMER 0x004
#define MDFN_IQRESET 0x020
void HuC6280_Init(void) MDFN_COLD;
void HuC6280_Reset(void) MDFN_COLD;
void HuC6280_Power(void) MDFN_COLD;
void HuC6280_IRQBegin(int w);
void HuC6280_IRQEnd(int w);
int HuC6280_StateAction(StateMem *sm, int load, int data_only);
static INLINE void HuC6280_StealCycle(void)
{
HuCPU.timestamp++;
}
static INLINE uint8 HuC6280_TimerRead(unsigned int A)
{
#if 0
return(HuCPU.timer_value | (PCEIODataBuffer & 0x80));
#endif
uint8 tvr = HuCPU.timer_value;
if(HuCPU.timer_next_timestamp == HuCPU.timestamp)
tvr = (tvr - 1) & 0x7F;
return(tvr | (PCEIODataBuffer & 0x80));
}
static INLINE void HuC6280_TimerWrite(unsigned int A, uint8 V)
{
switch(A & 1)
{
case 0: HuCPU.timer_load = (V & 0x7F); break;
case 1: if(V & 1) // Enable counter
{
if(HuCPU.timer_status == 0)
{
HuCPU.timer_next_timestamp = HuCPU.timestamp + 1024;
HuCPU.timer_value = HuCPU.timer_load;
}
}
HuCPU.timer_status = V & 1;
break;
}
}
static INLINE uint8 HuC6280_IRQStatusRead(unsigned int A)
{
if(!(A & 2))
return(PCEIODataBuffer);
switch(A & 1)
{
case 0:
HuC6280_IRQEnd(MDFN_IQTIMER);
return(HuCPU.IRQMask ^ 0x7);
case 1:
{
int status = 0;
if(HuCPU.IRQlow & MDFN_IQIRQ1) status |= 2;
if(HuCPU.IRQlow & MDFN_IQIRQ2) status |= 1;
if(HuCPU.IRQlow & MDFN_IQTIMER) status |= 4;
return(status | (PCEIODataBuffer & ~(1 | 2 | 4)));
}
}
return(PCEIODataBuffer);
}
static INLINE void HuC6280_IRQStatusWrite(unsigned int A, uint8 V)
{
if(!(A & 2)) return;
switch(A & 1)
{
case 0: HuCPU.IRQMask = (V & 0x7) ^ 0x7; break;
case 1: HuC6280_IRQEnd(MDFN_IQTIMER); break;
}
}
};
#define _HuC6280H
#endif

View File

@ -0,0 +1,635 @@
/* Mednafen - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define TEST_WEIRD_TFLAG(n) { if(HU_P & T_FLAG) puts("RAWR" n); }
case 0x00: /* BRK */
IncPC();
HU_P &= ~T_FLAG;
PUSH_PC();
COMPRESS_FLAGS();
PUSH(HU_P|B_FLAG);
HU_P|=I_FLAG;
HU_P &= ~D_FLAG;
HU_PI|=I_FLAG;
{
unsigned int npc;
npc=RdOp(0xFFF6);
npc|=RdOp(0xFFF7)<<8;
SetPC(npc);
}
break;
case 0x40: /* RTI */
HU_P = POP();
EXPAND_FLAGS();
/* HU_PI=HU_P; This is probably incorrect, so it's commented out. */
HU_PI = HU_P;
POP_PC();
// T-flag handling here:
TEST_WEIRD_TFLAG("RTI");
break;
case 0x60: /* RTS */
POP_PC_AP();
break;
case 0x48: /* PHA */
PUSH(HU_A);
break;
case 0x08: /* PHP */
HU_P &= ~T_FLAG;
COMPRESS_FLAGS();
PUSH(HU_P|B_FLAG);
break;
case 0xDA: // PHX 65C02
PUSH(HU_X);
break;
case 0x5A: // PHY 65C02
PUSH(HU_Y);
break;
case 0x68: /* PLA */
HU_A = POP();
X_ZN(HU_A);
break;
case 0xFA: // PLX 65C02
HU_X = POP();
X_ZN(HU_X);
break;
case 0x7A: // PLY 65C02
HU_Y = POP();
X_ZN(HU_Y);
break;
case 0x28: /* PLP */
HU_P = POP();
EXPAND_FLAGS();
// T-flag handling here:
TEST_WEIRD_TFLAG("PLP");
break;
case 0x4C:
{
unsigned int npc;
npc = RdAtPC();
IncPC();
npc|=RdAtPC() << 8;
SetPC(npc);
}
break; /* JMP ABSOLUTE */
case 0x6C: /* JMP Indirect */
{
uint32 tmp;
unsigned int npc;
GetAB(tmp);
npc=RdMem(tmp);
npc|=RdMem(tmp + 1)<<8;
SetPC(npc);
}
break;
case 0x7C: // JMP Indirect X - 65C02
{
uint32 tmp;
unsigned int npc;
GetAB(tmp);
tmp += HU_X;
npc=RdMem(tmp);
npc|=RdMem(tmp + 1)<<8;
SetPC(npc);
}
break;
case 0x20: /* JSR */
{
unsigned int npc;
npc = RdAtPC();
IncPC();
PUSH_PC();
npc |= RdAtPC() <<8;
SetPC(npc);
}
break;
case 0xAA: /* TAX */
HU_X=HU_A;
X_ZN(HU_A);
break;
case 0x8A: /* TXA */
HU_A=HU_X;
X_ZN(HU_A);
break;
case 0xA8: /* TAY */
HU_Y=HU_A;
X_ZN(HU_A);
break;
case 0x98: /* TYA */
HU_A=HU_Y;
X_ZN(HU_A);
break;
case 0xBA: /* TSX */
HU_X=HU_S;
X_ZN(HU_X);
break;
case 0x9A: /* TXS */
HU_S=HU_X;
break;
case 0xCA: /* DEX */
HU_X--;
X_ZN(HU_X);
break;
case 0x88: /* DEY */
HU_Y--;
X_ZN(HU_Y);
break;
case 0xE8: /* INX */
HU_X++;
X_ZN(HU_X);
break;
case 0xC8: /* INY */
HU_Y++;
X_ZN(HU_Y);
break;
case 0x54: CSL; break;
case 0xD4: CSH; break;
case 0x62: HU_A = 0; break; // CLA
case 0x82: HU_X = 0; break; // CLX
case 0xC2: HU_Y = 0; break; // CLY
case 0x18: /* CLC */
HU_P&=~C_FLAG;
break;
case 0xD8: /* CLD */
HU_P&=~D_FLAG;
break;
case 0x58: /* CLI */
if((HU_P & I_FLAG) && (HU_IRQlow & MDFN_IQIRQ1))
{
uint8 moo_op = RdAtPC();
if((moo_op == 0xAC || moo_op == 0xAD || moo_op == 0xAE) &&
((RdOp(GetRealPC() + 1) & 0x3) == 0) && ((RdOp(GetRealPC() + 2) & 0xFC) == 0))
{
HU_IRQlow |= 0x200;
//puts("CLI/LDA madness!");
}
}
HU_P&=~I_FLAG;
break;
case 0xB8: /* CLV */
HU_P&=~V_FLAG;
break;
case 0x38: /* SEC */
HU_P|=C_FLAG;
break;
case 0xF8: /* SED */
HU_P|=D_FLAG;
break;
case 0x78: /* SEI */
HU_P|=I_FLAG;
break;
case 0xEA: /* NOP */
break;
case 0x0A: RMW_A(ASL);
case 0x06: RMW_ZP(ASL);
case 0x16: RMW_ZPX(ASL);
case 0x0E: RMW_AB(ASL);
case 0x1E: RMW_ABX(ASL);
case 0x3A: RMW_A(DEC);
case 0xC6: RMW_ZP(DEC);
case 0xD6: RMW_ZPX(DEC);
case 0xCE: RMW_AB(DEC);
case 0xDE: RMW_ABX(DEC);
case 0x1A: RMW_A(INC); // 65C02
case 0xE6: RMW_ZP(INC);
case 0xF6: RMW_ZPX(INC);
case 0xEE: RMW_AB(INC);
case 0xFE: RMW_ABX(INC);
case 0x4A: RMW_A(LSR);
case 0x46: RMW_ZP(LSR);
case 0x56: RMW_ZPX(LSR);
case 0x4E: RMW_AB(LSR);
case 0x5E: RMW_ABX(LSR);
case 0x2A: RMW_A(ROL);
case 0x26: RMW_ZP(ROL);
case 0x36: RMW_ZPX(ROL);
case 0x2E: RMW_AB(ROL);
case 0x3E: RMW_ABX(ROL);
case 0x6A: RMW_A(ROR);
case 0x66: RMW_ZP(ROR);
case 0x76: RMW_ZPX(ROR);
case 0x6E: RMW_AB(ROR);
case 0x7E: RMW_ABX(ROR);
case 0x69: LD_IM(ADC);
case 0x65: LD_ZP(ADC);
case 0x75: LD_ZPX(ADC);
case 0x6D: LD_AB(ADC);
case 0x7D: LD_ABX(ADC);
case 0x79: LD_ABY(ADC);
case 0x72: LD_IND(ADC);
case 0x61: LD_IX(ADC);
case 0x71: LD_IY(ADC);
case 0x29: LD_IM(AND);
case 0x25: LD_ZP(AND);
case 0x35: LD_ZPX(AND);
case 0x2D: LD_AB(AND);
case 0x3D: LD_ABX(AND);
case 0x39: LD_ABY(AND);
case 0x32: LD_IND(AND);
case 0x21: LD_IX(AND);
case 0x31: LD_IY(AND);
case 0x89: LD_IM(BIT);
case 0x24: LD_ZP(BIT);
case 0x34: LD_ZPX(BIT);
case 0x2C: LD_AB(BIT);
case 0x3C: LD_ABX(BIT);
case 0xC9: LD_IM(CMP);
case 0xC5: LD_ZP(CMP);
case 0xD5: LD_ZPX(CMP);
case 0xCD: LD_AB(CMP);
case 0xDD: LD_ABX(CMP);
case 0xD9: LD_ABY(CMP);
case 0xD2: LD_IND(CMP);
case 0xC1: LD_IX(CMP);
case 0xD1: LD_IY(CMP);
case 0xE0: LD_IM(CPX);
case 0xE4: LD_ZP(CPX);
case 0xEC: LD_AB(CPX);
case 0xC0: LD_IM(CPY);
case 0xC4: LD_ZP(CPY);
case 0xCC: LD_AB(CPY);
case 0x49: LD_IM(EOR);
case 0x45: LD_ZP(EOR);
case 0x55: LD_ZPX(EOR);
case 0x4D: LD_AB(EOR);
case 0x5D: LD_ABX(EOR);
case 0x59: LD_ABY(EOR);
case 0x52: LD_IND(EOR);
case 0x41: LD_IX(EOR);
case 0x51: LD_IY(EOR);
case 0xA9: LD_IM(LDA);
case 0xA5: LD_ZP(LDA);
case 0xB5: LD_ZPX(LDA);
case 0xAD: LD_AB(LDA);
case 0xBD: LD_ABX(LDA);
case 0xB9: LD_ABY(LDA);
case 0xB2: LD_IND(LDA);
case 0xA1: LD_IX(LDA);
case 0xB1: LD_IY(LDA);
case 0xA2: LD_IM(LDX);
case 0xA6: LD_ZP(LDX);
case 0xB6: LD_ZPY(LDX);
case 0xAE: LD_AB(LDX);
case 0xBE: LD_ABY(LDX);
case 0xA0: LD_IM(LDY);
case 0xA4: LD_ZP(LDY);
case 0xB4: LD_ZPX(LDY);
case 0xAC: LD_AB(LDY);
case 0xBC: LD_ABX(LDY);
case 0x09: LD_IM(ORA);
case 0x05: LD_ZP(ORA);
case 0x15: LD_ZPX(ORA);
case 0x0D: LD_AB(ORA);
case 0x1D: LD_ABX(ORA);
case 0x19: LD_ABY(ORA);
case 0x12: LD_IND(ORA);
case 0x01: LD_IX(ORA);
case 0x11: LD_IY(ORA);
case 0xE9: LD_IM(SBC);
case 0xE5: LD_ZP(SBC);
case 0xF5: LD_ZPX(SBC);
case 0xED: LD_AB(SBC);
case 0xFD: LD_ABX(SBC);
case 0xF9: LD_ABY(SBC);
case 0xF2: LD_IND(SBC);
case 0xE1: LD_IX(SBC);
case 0xF1: LD_IY(SBC);
case 0x85: ST_ZP(HU_A);
case 0x95: ST_ZPX(HU_A);
case 0x8D: ST_AB(HU_A);
case 0x9D: ST_ABX(HU_A);
case 0x99: ST_ABY(HU_A);
case 0x92: ST_IND(HU_A);
case 0x81: ST_IX(HU_A);
case 0x91: ST_IY(HU_A);
case 0x86: ST_ZP(HU_X);
case 0x96: ST_ZPY(HU_X);
case 0x8E: ST_AB(HU_X);
case 0x84: ST_ZP(HU_Y);
case 0x94: ST_ZPX(HU_Y);
case 0x8C: ST_AB(HU_Y);
/* BBRi */
case 0x0F: LD_ZP(BBRi(0));
case 0x1F: LD_ZP(BBRi(1));
case 0x2F: LD_ZP(BBRi(2));
case 0x3F: LD_ZP(BBRi(3));
case 0x4F: LD_ZP(BBRi(4));
case 0x5F: LD_ZP(BBRi(5));
case 0x6F: LD_ZP(BBRi(6));
case 0x7F: LD_ZP(BBRi(7));
/* BBSi */
case 0x8F: LD_ZP(BBSi(0));
case 0x9F: LD_ZP(BBSi(1));
case 0xAF: LD_ZP(BBSi(2));
case 0xBF: LD_ZP(BBSi(3));
case 0xCF: LD_ZP(BBSi(4));
case 0xDF: LD_ZP(BBSi(5));
case 0xEF: LD_ZP(BBSi(6));
case 0xFF: LD_ZP(BBSi(7));
/* BRA */
case 0x80: BRA; break;
/* BSR */
case 0x44:
{
PUSH_PC();
BRA;
}
break;
/* BCC */
case 0x90: JR(!(HU_P&C_FLAG)); break;
/* BCS */
case 0xB0: JR(HU_P&C_FLAG); break;
/* BVC */
case 0x50: JR(!(HU_P&V_FLAG)); break;
/* BVS */
case 0x70: JR(HU_P&V_FLAG); break;
#ifdef HUC6280_LAZY_FLAGS
/* BEQ */
case 0xF0: JR(!(HU_ZNFlags & 0xFF)); break;
/* BNE */
case 0xD0: JR((HU_ZNFlags & 0xFF)); break;
/* BMI */
case 0x30: JR((HU_ZNFlags & 0x80000000)); break;
/* BPL */
case 0x10: JR(!(HU_ZNFlags & 0x80000000)); break;
#else
/* BEQ */
case 0xF0: JR(HU_P&Z_FLAG); break;
/* BNE */
case 0xD0: JR(!(HU_P&Z_FLAG)); break;
/* BMI */
case 0x30: JR(HU_P&N_FLAG); break;
/* BPL */
case 0x10: JR(!(HU_P&N_FLAG)); break;
#endif
// RMB 65SC02
case 0x07: RMW_ZP(RMB(0));
case 0x17: RMW_ZP(RMB(1));
case 0x27: RMW_ZP(RMB(2));
case 0x37: RMW_ZP(RMB(3));
case 0x47: RMW_ZP(RMB(4));
case 0x57: RMW_ZP(RMB(5));
case 0x67: RMW_ZP(RMB(6));
case 0x77: RMW_ZP(RMB(7));
// SMB 65SC02
case 0x87: RMW_ZP(SMB(0));
case 0x97: RMW_ZP(SMB(1));
case 0xa7: RMW_ZP(SMB(2));
case 0xb7: RMW_ZP(SMB(3));
case 0xc7: RMW_ZP(SMB(4));
case 0xd7: RMW_ZP(SMB(5));
case 0xe7: RMW_ZP(SMB(6));
case 0xf7: RMW_ZP(SMB(7));
// STZ 65C02
case 0x64: ST_ZP(0);
case 0x74: ST_ZPX(0);
case 0x9C: ST_AB(0);
case 0x9E: ST_ABX(0);
// TRB 65SC02
case 0x14: RMW_ZP(TRB);
case 0x1C: RMW_AB(TRB);
// TSB 65SC02
case 0x04: RMW_ZP(TSB);
case 0x0C: RMW_AB(TSB);
// TST
case 0x83: { uint8 zoomhack=RdAtPC(); IncPC(); LD_ZP(TST); }
case 0xA3: { uint8 zoomhack=RdAtPC(); IncPC(); LD_ZPX(TST); }
case 0x93: { uint8 zoomhack=RdAtPC(); IncPC(); LD_AB(TST); }
case 0xB3: { uint8 zoomhack=RdAtPC(); IncPC(); LD_ABX(TST); }
case 0x22: // SAX(amaphone!)
{
uint8 tmp = HU_X;
HU_X = HU_A;
HU_A = tmp;
}
break;
case 0x42: // SAY(what?)
{
uint8 tmp = HU_Y;
HU_Y = HU_A;
HU_A = tmp;
}
break;
case 0x02: // SXY
{
uint8 tmp = HU_X;
HU_X = HU_Y;
HU_Y = tmp;
}
break;
case 0x73: // TII
LD_BMT(BMT_TII);
case 0xC3: // TDD
LD_BMT(BMT_TDD);
case 0xD3: // TIN
LD_BMT(BMT_TIN);
case 0xE3: // TIA
LD_BMT(BMT_TIA);
case 0xF3: // TAI
LD_BMT(BMT_TAI);
case 0x43: // TMAi
LD_IM(TMA);
case 0x53: // TAMi
LD_IM(TAM);
case 0x03: // ST0
LD_IM(ST0);
case 0x13: // ST1
LD_IM(ST1);
case 0x23: // ST2
LD_IM(ST2);
case 0xF4: /* SET */
{
// AND, EOR, ORA, ADC
uint8 Abackup = HU_A;
ADDCYC(3);
HU_A = HU_Page1[HU_X]; //PAGE1_R[HU_X];
switch(RdAtPC())
{
default: //puts("Bad SET");
break;
case 0x69: IncPC(); LD_IM(ADC);
case 0x65: IncPC(); LD_ZP(ADC);
case 0x75: IncPC(); LD_ZPX(ADC);
case 0x6D: IncPC(); LD_AB(ADC);
case 0x7D: IncPC(); LD_ABX(ADC);
case 0x79: IncPC(); LD_ABY(ADC);
case 0x72: IncPC(); LD_IND(ADC);
case 0x61: IncPC(); LD_IX(ADC);
case 0x71: IncPC(); LD_IY(ADC);
case 0x29: IncPC(); LD_IM(AND);
case 0x25: IncPC(); LD_ZP(AND);
case 0x35: IncPC(); LD_ZPX(AND);
case 0x2D: IncPC(); LD_AB(AND);
case 0x3D: IncPC(); LD_ABX(AND);
case 0x39: IncPC(); LD_ABY(AND);
case 0x32: IncPC(); LD_IND(AND);
case 0x21: IncPC(); LD_IX(AND);
case 0x31: IncPC(); LD_IY(AND);
case 0x49: IncPC(); LD_IM(EOR);
case 0x45: IncPC(); LD_ZP(EOR);
case 0x55: IncPC(); LD_ZPX(EOR);
case 0x4D: IncPC(); LD_AB(EOR);
case 0x5D: IncPC(); LD_ABX(EOR);
case 0x59: IncPC(); LD_ABY(EOR);
case 0x52: IncPC(); LD_IND(EOR);
case 0x41: IncPC(); LD_IX(EOR);
case 0x51: IncPC(); LD_IY(EOR);
case 0x09: IncPC(); LD_IM(ORA);
case 0x05: IncPC(); LD_ZP(ORA);
case 0x15: IncPC(); LD_ZPX(ORA);
case 0x0D: IncPC(); LD_AB(ORA);
case 0x1D: IncPC(); LD_ABX(ORA);
case 0x19: IncPC(); LD_ABY(ORA);
case 0x12: IncPC(); LD_IND(ORA);
case 0x01: IncPC(); LD_IX(ORA);
case 0x11: IncPC(); LD_IY(ORA);
}
HU_Page1[HU_X] /*PAGE1_W[HU_X]*/ = HU_A;
HU_A = Abackup;
}
break;
case 0xFC:
{
int32 ec_tmp;
ec_tmp = next_event - HuCPU.timestamp;
if(ec_tmp > 0)
{
ADDCYC(ec_tmp);
}
}
break;
default: //MDFN_printf("Bad %02x at $%04x\n", b1, GetRealPC());
break;

View File

@ -0,0 +1,338 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pce.h"
#include "input.h"
#include "huc.h"
#include "../movie.h"
#include "../mednafen-endian.h"
namespace PCE_Fast
{
static int InputTypes[5];
static uint8 *data_ptr[5];
static bool AVPad6Which[5]; // Lower(8 buttons) or higher(4 buttons).
static bool AVPad6Enabled[5];
uint16 pce_jp_data[5];
static int64 mouse_last_meow[5];
static int32 mouse_x[5], mouse_y[5];
static uint16 mouse_rel[5];
uint8 pce_mouse_button[5];
uint8 mouse_index[5];
static uint8 sel;
static uint8 read_index = 0;
static void SyncSettings(void);
void PCEINPUT_SettingChanged(const char *name)
{
SyncSettings();
}
void PCEINPUT_Init(void)
{
SyncSettings();
}
void PCEINPUT_SetInput(int port, const char *type, void *ptr)
{
assert(port < 5);
if(!strcasecmp(type, "gamepad"))
InputTypes[port] = 1;
else if(!strcasecmp(type, "mouse"))
InputTypes[port] = 2;
else
InputTypes[port] = 0;
data_ptr[port] = (uint8 *)ptr;
}
void INPUT_Frame(void)
{
for(int x = 0; x < 5; x++)
{
if(InputTypes[x] == 1)
{
uint16 new_data = data_ptr[x][0] | (data_ptr[x][1] << 8);
if((new_data & 0x1000) && !(pce_jp_data[x] & 0x1000))
{
AVPad6Enabled[x] = !AVPad6Enabled[x];
MDFN_DispMessage("%d-button mode selected for pad %d", AVPad6Enabled[x] ? 6 : 2, x + 1);
}
pce_jp_data[x] = new_data;
}
else if(InputTypes[x] == 2)
{
mouse_x[x] += (int32)MDFN_de32lsb(data_ptr[x] + 0);
mouse_y[x] += (int32)MDFN_de32lsb(data_ptr[x] + 4);
pce_mouse_button[x] = *(uint8 *)(data_ptr[x] + 8);
}
}
}
void INPUT_FixTS(void)
{
for(int x = 0; x < 5; x++)
{
if(InputTypes[x] == 2)
mouse_last_meow[x] -= HuCPU.timestamp;
}
}
static INLINE bool CheckLM(int n)
{
if((int64)HuCPU.timestamp - mouse_last_meow[n] > 10000)
{
mouse_last_meow[n] = HuCPU.timestamp;
int32 rel_x = (int32)((0-mouse_x[n]));
int32 rel_y = (int32)((0-mouse_y[n]));
if(rel_x < -127) rel_x = -127;
if(rel_x > 127) rel_x = 127;
if(rel_y < -127) rel_y = -127;
if(rel_y > 127) rel_y = 127;
mouse_rel[n] = ((rel_x & 0xF0) >> 4) | ((rel_x & 0x0F) << 4);
mouse_rel[n] |= (((rel_y & 0xF0) >> 4) | ((rel_y & 0x0F) << 4)) << 8;
mouse_x[n] += (int32)(rel_x);
mouse_y[n] += (int32)(rel_y);
return(1);
}
return(0);
}
uint8 INPUT_Read(unsigned int A)
{
uint8 ret = 0xF;
int tmp_ri = read_index;
if(tmp_ri > 4)
ret ^= 0xF;
else
{
if(!InputTypes[tmp_ri])
ret ^= 0xF;
else if(InputTypes[tmp_ri] == 2) // Mouse
{
if(sel & 1)
{
CheckLM(tmp_ri);
ret ^= 0xF;
ret ^= mouse_rel[tmp_ri] & 0xF;
mouse_rel[tmp_ri] >>= 4;
}
else
{
if(pce_mouse_button[tmp_ri] & 1)
ret ^= 0x3; //pce_mouse_button[tmp_ri];
if(pce_mouse_button[tmp_ri] & 0x2)
ret ^= 0x8;
}
}
else
{
if(InputTypes[tmp_ri] == 1) // Gamepad
{
if(AVPad6Which[tmp_ri] && AVPad6Enabled[tmp_ri])
{
if(sel & 1)
ret ^= 0x0F;
else
ret ^= (pce_jp_data[tmp_ri] >> 8) & 0x0F;
}
else
{
if(sel & 1)
ret ^= (pce_jp_data[tmp_ri] >> 4) & 0x0F;
else
ret ^= pce_jp_data[tmp_ri] & 0x0F;
}
if(!(sel & 1))
AVPad6Which[tmp_ri] = !AVPad6Which[tmp_ri];
}
}
}
if(!PCE_IsCD)
ret |= 0x80; // Set when CDROM is not attached
//ret |= 0x40; // PC Engine if set, TG16 if clear. Let's leave it clear, PC Engine games don't seem to mind if it's clear, but TG16 games barf if it's set.
ret |= 0x30; // Always-set?
return(ret);
}
void INPUT_Write(unsigned int A, uint8 V)
{
if((V & 1) && !(sel & 2) && (V & 2))
{
read_index = 0;
}
else if((V & 1) && !(sel & 1))
{
if(read_index < 255)
read_index++;
}
sel = V & 3;
}
int INPUT_StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT StateRegs[] =
{
// 0.8.A fix:
SFARRAYB(AVPad6Enabled, 5),
SFARRAYB(AVPad6Which, 5),
SFVARN(mouse_last_meow[0], "mlm_0"),
SFVARN(mouse_last_meow[1], "mlm_1"),
SFVARN(mouse_last_meow[2], "mlm_2"),
SFVARN(mouse_last_meow[3], "mlm_3"),
SFVARN(mouse_last_meow[4], "mlm_4"),
SFARRAY32(mouse_x, 5),
SFARRAY32(mouse_y, 5),
SFARRAY16(mouse_rel, 5),
SFARRAY(pce_mouse_button, 5),
SFARRAY(mouse_index, 5),
// end 0.8.A fix
SFARRAY16(pce_jp_data, 5),
SFVAR(sel),
SFVAR(read_index),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "JOY");
return(ret);
}
// GamepadIDII and GamepadIDII_DSR must be EXACTLY the same except for the RUN+SELECT exclusion in the latter.
static const InputDeviceInputInfoStruct GamepadIDII[] =
{
{ "i", "I", 12, IDIT_BUTTON_CAN_RAPID, NULL },
{ "ii", "II", 11, IDIT_BUTTON_CAN_RAPID, NULL },
{ "select", "SELECT", 4, IDIT_BUTTON, NULL },
{ "run", "RUN", 5, IDIT_BUTTON, NULL },
{ "up", "UP ↑", 0, IDIT_BUTTON, "down" },
{ "right", "RIGHT →", 3, IDIT_BUTTON, "left" },
{ "down", "DOWN ↓", 1, IDIT_BUTTON, "up" },
{ "left", "LEFT ←", 2, IDIT_BUTTON, "right" },
{ "iii", "III", 10, IDIT_BUTTON, NULL },
{ "iv", "IV", 7, IDIT_BUTTON, NULL },
{ "v", "V", 8, IDIT_BUTTON, NULL },
{ "vi", "VI", 9, IDIT_BUTTON, NULL },
{ "mode_select", "2/6 Mode Select", 6, IDIT_BUTTON, NULL },
};
static const InputDeviceInputInfoStruct GamepadIDII_DSR[] =
{
{ "i", "I", 12, IDIT_BUTTON_CAN_RAPID, NULL },
{ "ii", "II", 11, IDIT_BUTTON_CAN_RAPID, NULL },
{ "select", "SELECT", 4, IDIT_BUTTON, "run" },
{ "run", "RUN", 5, IDIT_BUTTON, "select" },
{ "up", "UP ↑", 0, IDIT_BUTTON, "down" },
{ "right", "RIGHT →", 3, IDIT_BUTTON, "left" },
{ "down", "DOWN ↓", 1, IDIT_BUTTON, "up" },
{ "left", "LEFT ←", 2, IDIT_BUTTON, "right" },
{ "iii", "III", 10, IDIT_BUTTON, NULL },
{ "iv", "IV", 7, IDIT_BUTTON, NULL },
{ "v", "V", 8, IDIT_BUTTON, NULL },
{ "vi", "VI", 9, IDIT_BUTTON, NULL },
{ "mode_select", "2/6 Mode Select", 6, IDIT_BUTTON, NULL },
};
static const InputDeviceInputInfoStruct MouseIDII[] =
{
{ "x_axis", "X Axis", -1, IDIT_X_AXIS_REL },
{ "y_axis", "Y Axis", -1, IDIT_Y_AXIS_REL },
{ "left", "Left Button", 0, IDIT_BUTTON, NULL },
{ "right", "Right Button", 1, IDIT_BUTTON, NULL },
};
// If we add more devices to this array, REMEMBER TO UPDATE the hackish array indexing in the SyncSettings() function
// below.
static InputDeviceInfoStruct InputDeviceInfo[] =
{
// None
{
"none",
"none",
NULL,
NULL,
0,
NULL
},
// Gamepad
{
"gamepad",
"Gamepad",
NULL,
NULL,
sizeof(GamepadIDII) / sizeof(InputDeviceInputInfoStruct),
GamepadIDII,
},
// Mouse
{
"mouse",
"Mouse",
NULL,
NULL,
sizeof(MouseIDII) / sizeof(InputDeviceInputInfoStruct),
MouseIDII,
},
};
static const InputPortInfoStruct PortInfo[] =
{
{ "port1", "Port 1", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo, "gamepad" },
{ "port2", "Port 2", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo, "gamepad" },
{ "port3", "Port 3", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo, "gamepad" },
{ "port4", "Port 4", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo, "gamepad" },
{ "port5", "Port 5", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo, "gamepad" },
};
InputInfoStruct PCEInputInfo =
{
sizeof(PortInfo) / sizeof(InputPortInfoStruct),
PortInfo
};
static void SyncSettings(void)
{
MDFNGameInfo->mouse_sensitivity = MDFN_GetSettingF("pce_fast.mouse_sensitivity");
InputDeviceInfo[1].IDII = MDFN_GetSettingB("pce_fast.disable_softreset") ? GamepadIDII_DSR : GamepadIDII;
}
};

View File

@ -0,0 +1,19 @@
#ifndef __PCE_INPUT_H
#define __PCE_INPUT_H
namespace PCE_Fast
{
void PCEINPUT_Init(void);
void PCEINPUT_SettingChanged(const char *name);
void PCEINPUT_SetInput(int port, const char *type, void *ptr);
uint8 INPUT_Read(unsigned int A);
void INPUT_Write(unsigned int A, uint8 V);
void INPUT_Frame(void);
int INPUT_StateAction(StateMem *sm, int load, int data_only);
extern InputInfoStruct PCEInputInfo;
void INPUT_FixTS(void);
};
#endif

View File

@ -0,0 +1,138 @@
A &= 0x1FFF;
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
const void * const IOReadHandlers[0x20] =
{
&&VDC_00, &&VDC_01, &&VDC_02, &&VDC_03,
&&VCE_00, &&VCE_01, &&VCE_02, &&VCE_03,
&&PSG_00, &&PSG_01, &&PSG_02, &&PSG_03,
&&TIMER_00, &&TIMER_01, &&TIMER_02, &&TIMER_03,
&&INPUT_00, &&INPUT_01, &&INPUT_02, &&INPUT_03,
&&IRQ_00, &&IRQ_01, &&IRQ_02, &&IRQ_03,
&&CDROM_00, &&CDROM_01, &&CDROM_02, &&CDROM_03,
&&EXP_00, &&EXP_01, &&EXP_02, &&EXP_03
};
goto *IOReadHandlers[((A & 0x1C00) >> 8) | (A & 0x3)];
{
#define PCEF_CASEL(label, caseval) label
#else
#define PCEF_CASEL(label, caseval) case (caseval)
switch(((A & 0x1C00) >> 8) | (A & 0x3))
{
#endif
//
//
//
#if IOREAD_SGX==1
PCEF_CASEL(VDC_00, 0x00):
PCEF_CASEL(VDC_01, 0x01):
PCEF_CASEL(VDC_02, 0x02):
PCEF_CASEL(VDC_03, 0x03):
HuC6280_StealCycle();
return(VDC_Read(A & 0x1F, TRUE));
#else
PCEF_CASEL(VDC_00, 0x00):
HuC6280_StealCycle();
return(VDC_Read(0, FALSE));
PCEF_CASEL(VDC_01, 0x01):
HuC6280_StealCycle();
return(VDC_Read(1, FALSE));
PCEF_CASEL(VDC_02, 0x02):
HuC6280_StealCycle();
return(VDC_Read(2, FALSE));
PCEF_CASEL(VDC_03, 0x03):
HuC6280_StealCycle();
return(VDC_Read(3, FALSE));
#endif
PCEF_CASEL(VCE_00, 0x04):
PCEF_CASEL(VCE_01, 0x05):
PCEF_CASEL(VCE_02, 0x06):
PCEF_CASEL(VCE_03, 0x07):
HuC6280_StealCycle();
return(VCE_Read(A));
PCEF_CASEL(PSG_00, 0x08):
PCEF_CASEL(PSG_01, 0x09):
PCEF_CASEL(PSG_02, 0x0A):
PCEF_CASEL(PSG_03, 0x0B):
if(HuCPU.in_block_move)
return(0);
return(PCEIODataBuffer);
PCEF_CASEL(TIMER_00, 0x0C):
PCEF_CASEL(TIMER_01, 0x0D):
PCEF_CASEL(TIMER_02, 0x0E):
PCEF_CASEL(TIMER_03, 0x0F):
if(HuCPU.in_block_move)
return(0);
{
uint8 ret = HuC6280_TimerRead(A);
PCEIODataBuffer = ret;
return(ret);
}
PCEF_CASEL(INPUT_00, 0x10):
PCEF_CASEL(INPUT_01, 0x11):
PCEF_CASEL(INPUT_02, 0x12):
PCEF_CASEL(INPUT_03, 0x13):
if(HuCPU.in_block_move)
return(0);
{
uint8 ret = INPUT_Read(A);
PCEIODataBuffer = ret;
return(ret);
}
PCEF_CASEL(IRQ_00, 0x14):
PCEF_CASEL(IRQ_01, 0x15):
PCEF_CASEL(IRQ_02, 0x16):
PCEF_CASEL(IRQ_03, 0x17):
if(HuCPU.in_block_move)
return(0);
{
uint8 ret = HuC6280_IRQStatusRead(A);
PCEIODataBuffer = ret;
return(ret);
}
PCEF_CASEL(CDROM_00, 0x18):
PCEF_CASEL(CDROM_01, 0x19):
PCEF_CASEL(CDROM_02, 0x1A):
PCEF_CASEL(CDROM_03, 0x1B):
if(!PCE_IsCD)
return(0xFF);
if((A & 0x1E00) == 0x1A00)
{
if(arcade_card)
return(arcade_card->Read(A & 0x1FFF));
else
return(0);
}
else
{
return(PCECD_Read(HuCPU.timestamp * 3, A));
}
PCEF_CASEL(EXP_00, 0x1C):
PCEF_CASEL(EXP_01, 0x1D):
PCEF_CASEL(EXP_02, 0x1E):
PCEF_CASEL(EXP_03, 0x1F):
#ifdef HAVE_HES
if(IsHES)
return(ReadIBP(A));
#endif
return(0xFF);
}
#undef PCEF_CASEL
//printf("Meow: %08x, %02x:%04x\n", A, A >> 13, A & 0x1FFF);

View File

@ -0,0 +1,714 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pce.h"
#include <zlib.h>
#include "vdc.h"
#include "psg.h"
#include "input.h"
#include "huc.h"
#include "pcecd.h"
#include "pcecd_drive.h"
#include "hes.h"
#include "arcade_card/arcade_card.h"
#include "../mempatcher.h"
#include "../cdrom/cdromif.h"
namespace PCE_Fast
{
static PCEFast_PSG *psg = NULL;
extern ArcadeCard *arcade_card; // Bah, lousy globals.
static Blip_Buffer sbuf[2];
bool PCE_ACEnabled;
static bool IsSGX;
static bool IsHES;
int pce_overclocked;
// Statically allocated for speed...or something.
uint8 ROMSpace[0x88 * 8192 + 8192]; // + 8192 for PC-as-pointer safety padding
uint8 BaseRAM[32768 + 8192]; // 8KB for PCE, 32KB for Super Grafx // + 8192 for PC-as-pointer safety padding
uint8 PCEIODataBuffer;
readfunc PCERead[0x100];
writefunc PCEWrite[0x100];
static DECLFR(PCEBusRead)
{
//printf("BUS Read: %02x %04x\n", A >> 13, A);
return(0xFF);
}
static DECLFW(PCENullWrite)
{
//printf("Null Write: %02x, %08x %02x\n", A >> 13, A, V);
}
static DECLFR(BaseRAMReadSGX)
{
return((BaseRAM - (0xF8 * 8192))[A]);
}
static DECLFW(BaseRAMWriteSGX)
{
(BaseRAM - (0xF8 * 8192))[A] = V;
}
static DECLFR(BaseRAMRead)
{
return((BaseRAM - (0xF8 * 8192))[A]);
}
static DECLFR(BaseRAMRead_Mirrored)
{
return(BaseRAM[A & 0x1FFF]);
}
static DECLFW(BaseRAMWrite)
{
(BaseRAM - (0xF8 * 8192))[A] = V;
}
static DECLFW(BaseRAMWrite_Mirrored)
{
BaseRAM[A & 0x1FFF] = V;
}
static DECLFR(IORead)
{
#define IOREAD_SGX 0
#include "ioread.inc"
#undef IOREAD_SGX
}
static DECLFR(IOReadSGX)
{
#define IOREAD_SGX 1
#include "ioread.inc"
#undef IOREAD_SGX
}
static DECLFW(IOWrite)
{
A &= 0x1FFF;
switch(A >> 10)
{
case 0: HuC6280_StealCycle();
VDC_Write(A, V);
break;
case 1: HuC6280_StealCycle();
VCE_Write(A, V);
break;
case 2: PCEIODataBuffer = V;
psg->Write(HuCPU.timestamp / pce_overclocked, A, V);
break;
case 3: PCEIODataBuffer = V;
HuC6280_TimerWrite(A, V);
break;
case 4: PCEIODataBuffer = V; INPUT_Write(A, V); break;
case 5: PCEIODataBuffer = V; HuC6280_IRQStatusWrite(A, V); break;
case 6:
if(!PCE_IsCD)
break;
if((A & 0x1E00) == 0x1A00)
{
if(arcade_card)
arcade_card->Write(A & 0x1FFF, V);
}
else
{
PCECD_Write(HuCPU.timestamp * 3, A, V);
}
break;
case 7: break; // Expansion.
}
}
static void PCECDIRQCB(bool asserted)
{
if(asserted)
HuC6280_IRQBegin(MDFN_IQIRQ2);
else
HuC6280_IRQEnd(MDFN_IQIRQ2);
}
bool PCE_InitCD(void)
{
PCECD_Settings cd_settings;
memset(&cd_settings, 0, sizeof(PCECD_Settings));
cd_settings.CDDA_Volume = (double)MDFN_GetSettingUI("pce_fast.cddavolume") / 100;
cd_settings.CD_Speed = MDFN_GetSettingUI("pce_fast.cdspeed");
cd_settings.ADPCM_Volume = (double)MDFN_GetSettingUI("pce_fast.adpcmvolume") / 100;
cd_settings.ADPCM_LPF = MDFN_GetSettingB("pce_fast.adpcmlp");
if(cd_settings.CDDA_Volume != 1.0)
MDFN_printf(_("CD-DA Volume: %d%%\n"), (int)(100 * cd_settings.CDDA_Volume));
if(cd_settings.ADPCM_Volume != 1.0)
MDFN_printf(_("ADPCM Volume: %d%%\n"), (int)(100 * cd_settings.ADPCM_Volume));
return(PCECD_Init(&cd_settings, PCECDIRQCB, PCE_MASTER_CLOCK, pce_overclocked, &sbuf[0], &sbuf[1]));
}
static int LoadCommon(void);
static void LoadCommonPre(void);
static bool TestMagic(const char *name, MDFNFILE *fp)
{
if(memcmp(GET_FDATA_PTR(fp), "HESM", 4) && strcasecmp(GET_FEXTS_PTR(fp), "pce") && strcasecmp(GET_FEXTS_PTR(fp), "sgx"))
return(FALSE);
return(TRUE);
}
static int Load(const char *name, MDFNFILE *fp)
{
uint32 headerlen = 0;
uint32 r_size;
IsHES = 0;
IsSGX = 0;
if(!memcmp(GET_FDATA_PTR(fp), "HESM", 4))
IsHES = 1;
LoadCommonPre();
if(!IsHES)
{
if(GET_FSIZE_PTR(fp) & 0x200) // 512 byte header!
headerlen = 512;
}
r_size = GET_FSIZE_PTR(fp) - headerlen;
if(r_size > 4096 * 1024) r_size = 4096 * 1024;
for(int x = 0; x < 0x100; x++)
{
PCERead[x] = PCEBusRead;
PCEWrite[x] = PCENullWrite;
}
uint32 crc = crc32(0, GET_FDATA_PTR(fp) + headerlen, GET_FSIZE_PTR(fp) - headerlen);
#ifdef HAVE_HES
if(IsHES)
{
if(!PCE_HESLoad(GET_FDATA_PTR(fp), GET_FSIZE_PTR(fp)))
return(0);
}
else
#endif
HuCLoad(GET_FDATA_PTR(fp) + headerlen, GET_FSIZE_PTR(fp) - headerlen, crc);
if(!strcasecmp(GET_FEXTS_PTR(fp), "sgx"))
IsSGX = TRUE;
if(GET_FSIZE_PTR(fp) >= 8192 && !memcmp(GET_FDATA_PTR(fp) + headerlen, "DARIUS Version 1.11b", strlen("DARIUS VERSION 1.11b")))
{
MDFN_printf("SuperGfx: Darius Plus\n");
IsSGX = 1;
}
if(crc == 0x4c2126b0)
{
MDFN_printf("SuperGfx: Aldynes\n");
IsSGX = 1;
}
if(crc == 0x8c4588e2)
{
MDFN_printf("SuperGfx: 1941 - Counter Attack\n");
IsSGX = 1;
}
if(crc == 0x1f041166)
{
MDFN_printf("SuperGfx: Madouou Granzort\n");
IsSGX = 1;
}
if(crc == 0xb486a8ed)
{
MDFN_printf("SuperGfx: Daimakaimura\n");
IsSGX = 1;
}
if(crc == 0x3b13af61)
{
MDFN_printf("SuperGfx: Battle Ace\n");
IsSGX = 1;
}
return(LoadCommon());
}
static void LoadCommonPre(void)
{
// FIXME: Make these globals less global!
pce_overclocked = MDFN_GetSettingUI("pce_fast.ocmultiplier");
PCE_ACEnabled = MDFN_GetSettingB("pce_fast.arcadecard");
if(pce_overclocked > 1)
MDFN_printf(_("CPU overclock: %dx\n"), pce_overclocked);
if(MDFN_GetSettingUI("pce_fast.cdspeed") > 1)
MDFN_printf(_("CD-ROM speed: %ux\n"), (unsigned int)MDFN_GetSettingUI("pce_fast.cdspeed"));
memset(HuCPUFastMap, 0, sizeof(HuCPUFastMap));
for(int x = 0; x < 0x100; x++)
{
PCERead[x] = PCEBusRead;
PCEWrite[x] = PCENullWrite;
}
MDFNMP_Init(1024, (1 << 21) / 1024);
}
static int LoadCommon(void)
{
IsSGX |= MDFN_GetSettingB("pce_fast.forcesgx") ? 1 : 0;
if(IsHES)
IsSGX = 1;
// Don't modify IsSGX past this point.
VDC_Init(IsSGX);
if(IsSGX)
{
MDFN_printf("SuperGrafx Emulation Enabled.\n");
PCERead[0xF8] = PCERead[0xF9] = PCERead[0xFA] = PCERead[0xFB] = BaseRAMReadSGX;
PCEWrite[0xF8] = PCEWrite[0xF9] = PCEWrite[0xFA] = PCEWrite[0xFB] = BaseRAMWriteSGX;
for(int x = 0xf8; x < 0xfb; x++)
HuCPUFastMap[x] = BaseRAM - 0xf8 * 8192;
PCERead[0xFF] = IOReadSGX;
}
else
{
PCERead[0xF8] = BaseRAMRead;
PCERead[0xF9] = PCERead[0xFA] = PCERead[0xFB] = BaseRAMRead_Mirrored;
PCEWrite[0xF8] = BaseRAMWrite;
PCEWrite[0xF9] = PCEWrite[0xFA] = PCEWrite[0xFB] = BaseRAMWrite_Mirrored;
for(int x = 0xf8; x < 0xfb; x++)
HuCPUFastMap[x] = BaseRAM - x * 8192;
PCERead[0xFF] = IORead;
}
MDFNMP_AddRAM(IsSGX ? 32768 : 8192, 0xf8 * 8192, BaseRAM);
PCEWrite[0xFF] = IOWrite;
HuC6280_Init();
psg = new PCEFast_PSG(&sbuf[0], &sbuf[1]);
psg->SetVolume(1.0);
if(PCE_IsCD)
{
unsigned int cdpsgvolume = MDFN_GetSettingUI("pce_fast.cdpsgvolume");
if(cdpsgvolume != 100)
{
MDFN_printf(_("CD PSG Volume: %d%%\n"), cdpsgvolume);
}
psg->SetVolume(0.678 * cdpsgvolume / 100);
}
PCEINPUT_Init();
PCE_Power();
MDFNGameInfo->LayerNames = IsSGX ? "BG0\0SPR0\0BG1\0SPR1\0" : "Background\0Sprites\0";
MDFNGameInfo->fps = (uint32)((double)7159090.90909090 / 455 / 263 * 65536 * 256);
// Clean this up:
if(!MDFN_GetSettingB("pce_fast.correct_aspect"))
MDFNGameInfo->fb_width = 682;
if(!IsHES)
{
MDFNGameInfo->nominal_width = MDFN_GetSettingB("pce_fast.correct_aspect") ? 288 : 341;
MDFNGameInfo->nominal_height = MDFN_GetSettingUI("pce_fast.slend") - MDFN_GetSettingUI("pce_fast.slstart") + 1;
MDFNGameInfo->lcm_width = MDFN_GetSettingB("pce_fast.correct_aspect") ? 1024 : 341;
MDFNGameInfo->lcm_height = MDFNGameInfo->nominal_height;
}
return(1);
}
static bool TestMagicCD(std::vector<CDIF *> *CDInterfaces)
{
static const uint8 magic_test[0x20] = { 0x82, 0xB1, 0x82, 0xCC, 0x83, 0x76, 0x83, 0x8D, 0x83, 0x4F, 0x83, 0x89, 0x83, 0x80, 0x82, 0xCC,
0x92, 0x98, 0x8D, 0xEC, 0x8C, 0xA0, 0x82, 0xCD, 0x8A, 0x94, 0x8E, 0xAE, 0x89, 0xEF, 0x8E, 0xD0
};
uint8 sector_buffer[2048];
CDIF *cdiface = (*CDInterfaces)[0];
CDUtility::TOC toc;
bool ret = FALSE;
memset(sector_buffer, 0, sizeof(sector_buffer));
cdiface->ReadTOC(&toc);
for(int32 track = toc.first_track; track <= toc.last_track; track++)
{
if(toc.tracks[track].control & 0x4)
{
cdiface->ReadSector(sector_buffer, toc.tracks[track].lba, 1);
if(!memcmp((char*)sector_buffer, (char *)magic_test, 0x20))
ret = TRUE;
// PCE CD BIOS apparently only looks at the first data track.
break;
}
}
// If it's a PC-FX CD(Battle Heat), return false.
// This is very kludgy.
for(int32 track = toc.first_track; track <= toc.last_track; track++)
{
if(toc.tracks[track].control & 0x4)
{
cdiface->ReadSector(sector_buffer, toc.tracks[track].lba, 1);
if(!strncmp("PC-FX:Hu_CD-ROM", (char*)sector_buffer, strlen("PC-FX:Hu_CD-ROM")))
{
return(false);
}
}
}
// Now, test for the Games Express CD games. The GE BIOS seems to always look at sector 0x10, but only if the first track is a
// data track.
if(toc.first_track == 1 && (toc.tracks[1].control & 0x4))
{
if(cdiface->ReadSector(sector_buffer, 0x10, 1))
{
if(!memcmp((char *)sector_buffer + 0x8, "HACKER CD ROM SYSTEM", 0x14))
{
ret = TRUE;
}
}
}
return(ret);
}
static int LoadCD(std::vector<CDIF *> *CDInterfaces)
{
std::string bios_path = MDFN_MakeFName(MDFNMKF_FIRMWARE, 0, MDFN_GetSettingS("pce_fast.cdbios").c_str() );
IsHES = 0;
IsSGX = 0;
LoadCommonPre();
if(!HuCLoadCD(bios_path.c_str()))
return(0);
PCECD_Drive_SetDisc(true, NULL, true);
PCECD_Drive_SetDisc(false, (*CDInterfaces)[0], true);
return(LoadCommon());
}
static void CloseGame(void)
{
#ifdef HAVE_HES
if(IsHES)
HES_Close();
else
#endif
{
HuCClose();
}
VDC_Close();
if(psg)
{
delete psg;
psg = NULL;
}
}
static void Emulate(EmulateSpecStruct *espec)
{
INPUT_Frame();
MDFNMP_ApplyPeriodicCheats();
#if 0
{
static bool firstcat = true;
MDFN_PixelFormat nf;
nf.bpp = 16;
nf.colorspace = MDFN_COLORSPACE_RGB;
nf.Rshift = 11;
nf.Gshift = 5;
nf.Bshift = 0;
nf.Ashift = 16;
nf.Rprec = 5;
nf.Gprec = 6;
nf.Bprec = 5;
nf.Aprec = 8;
espec->surface->SetFormat(nf, false);
espec->VideoFormatChanged = firstcat;
firstcat = false;
}
#endif
#if 0
static bool firstcat = true;
MDFN_PixelFormat tmp_pf;
tmp_pf.Rshift = 0;
tmp_pf.Gshift = 0;
tmp_pf.Bshift = 0;
tmp_pf.Ashift = 8;
tmp_pf.Rprec = 0;
tmp_pf.Gprec = 0;
tmp_pf.Bprec = 0;
tmp_pf.Aprec = 0;
tmp_pf.bpp = 8;
tmp_pf.colorspace = MDFN_COLORSPACE_RGB;
espec->surface->SetFormat(tmp_pf, false);
espec->VideoFormatChanged = firstcat;
firstcat = false;
#endif
if(espec->VideoFormatChanged)
VDC_SetPixelFormat(espec->surface->format); //.Rshift, espec->surface->format.Gshift, espec->surface->format.Bshift);
if(espec->SoundFormatChanged)
{
for(int y = 0; y < 2; y++)
{
sbuf[y].set_sample_rate(espec->SoundRate ? espec->SoundRate : 44100, 50);
sbuf[y].clock_rate((long)(PCE_MASTER_CLOCK / 3));
sbuf[y].bass_freq(10);
}
}
VDC_RunFrame(espec, IsHES);
if(PCE_IsCD)
{
PCECD_Run(HuCPU.timestamp * 3);
}
psg->EndFrame(HuCPU.timestamp / pce_overclocked);
if(espec->SoundBuf)
{
for(int y = 0; y < 2; y++)
{
sbuf[y].end_frame(HuCPU.timestamp / pce_overclocked);
espec->SoundBufSize = sbuf[y].read_samples(espec->SoundBuf + y, espec->SoundBufMaxSize, 1);
}
}
espec->MasterCycles = HuCPU.timestamp * 3;
INPUT_FixTS();
HuC6280_ResetTS();
if(PCE_IsCD)
PCECD_ResetTS();
#ifdef HAVE_HES
if(IsHES && !espec->skip)
HES_Draw(espec->surface, &espec->DisplayRect, espec->SoundBuf, espec->SoundBufSize);
#endif
}
static int StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT StateRegs[] =
{
SFARRAY(BaseRAM, IsSGX? 32768 : 8192),
SFVAR(PCEIODataBuffer),
SFEND
};
//for(int i = 8192; i < 32768; i++)
// if(BaseRAM[i] != 0xFF)
// printf("%d %02x\n", i, BaseRAM[i]);
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "MAIN");
ret &= HuC6280_StateAction(sm, load, data_only);
ret &= VDC_StateAction(sm, load, data_only);
ret &= psg->StateAction(sm, load, data_only);
ret &= INPUT_StateAction(sm, load, data_only);
ret &= HuC_StateAction(sm, load, data_only);
if(load)
{
}
return(ret);
}
void PCE_Power(void)
{
memset(BaseRAM, 0x00, sizeof(BaseRAM));
if(!IsSGX)
for(int i = 8192; i < 32768; i++)
BaseRAM[i] = 0xFF;
PCEIODataBuffer = 0xFF;
#ifdef HAVE_HES
if(IsHES)
HES_Reset();
#endif
HuC6280_Power();
VDC_Power();
psg->Power(HuCPU.timestamp / pce_overclocked);
HuC_Power();
if(PCE_IsCD)
{
PCECD_Power(HuCPU.timestamp * 3);
}
}
static void DoSimpleCommand(int cmd)
{
switch(cmd)
{
case MDFN_MSC_RESET: PCE_Power(); break;
case MDFN_MSC_POWER: PCE_Power(); break;
}
}
static MDFNSetting PCESettings[] =
{
{ "pce_fast.correct_aspect", MDFNSF_CAT_VIDEO, gettext_noop("Correct the aspect ratio."), NULL, MDFNST_BOOL, "1" },
{ "pce_fast.slstart", MDFNSF_NOFLAGS, gettext_noop("First rendered scanline."), NULL, MDFNST_UINT, "4", "0", "239" },
{ "pce_fast.slend", MDFNSF_NOFLAGS, gettext_noop("Last rendered scanline."), NULL, MDFNST_UINT, "235", "0", "239" },
{ "pce_fast.mouse_sensitivity", MDFNSF_NOFLAGS, gettext_noop("Mouse sensitivity."), NULL, MDFNST_FLOAT, "0.50", NULL, NULL, NULL, PCEINPUT_SettingChanged },
{ "pce_fast.disable_softreset", MDFNSF_NOFLAGS, gettext_noop("If set, when RUN+SEL are pressed simultaneously, disable both buttons temporarily."), NULL, MDFNST_BOOL, "0", NULL, NULL, NULL, PCEINPUT_SettingChanged },
{ "pce_fast.forcesgx", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Force SuperGrafx emulation."), NULL, MDFNST_BOOL, "0" },
{ "pce_fast.arcadecard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Enable Arcade Card emulation."), NULL, MDFNST_BOOL, "1" },
{ "pce_fast.ocmultiplier", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("CPU overclock multiplier."), NULL, MDFNST_UINT, "1", "1", "100"},
{ "pce_fast.cdspeed", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("CD-ROM data transfer speed multiplier."), NULL, MDFNST_UINT, "1", "1", "100" },
{ "pce_fast.nospritelimit", MDFNSF_NOFLAGS, gettext_noop("Remove 16-sprites-per-scanline hardware limit."), NULL, MDFNST_BOOL, "0" },
{ "pce_fast.cdbios", MDFNSF_EMU_STATE, gettext_noop("Path to the CD BIOS"), NULL, MDFNST_STRING, "syscard3.pce" },
{ "pce_fast.adpcmlp", MDFNSF_NOFLAGS, gettext_noop("Enable dynamic ADPCM lowpass filter."), NULL, MDFNST_BOOL, "0" },
{ "pce_fast.cdpsgvolume", MDFNSF_NOFLAGS, gettext_noop("PSG volume when playing a CD game."), NULL, MDFNST_UINT, "100", "0", "200" },
{ "pce_fast.cddavolume", MDFNSF_NOFLAGS, gettext_noop("CD-DA volume."), NULL, MDFNST_UINT, "100", "0", "200" },
{ "pce_fast.adpcmvolume", MDFNSF_NOFLAGS, gettext_noop("ADPCM volume."), NULL, MDFNST_UINT, "100", "0", "200" },
{ NULL }
};
static uint8 MemRead(uint32 addr)
{
return(PCERead[(addr / 8192) & 0xFF](addr));
}
static const FileExtensionSpecStruct KnownExtensions[] =
{
{ ".pce", gettext_noop("PC Engine ROM Image") },
{ ".hes", gettext_noop("PC Engine Music Rip") },
{ ".sgx", gettext_noop("SuperGrafx ROM Image") },
{ NULL, NULL }
};
};
MDFNGI EmulatedPCE_Fast =
{
"pce_fast",
"PC Engine (CD)/TurboGrafx 16 (CD)/SuperGrafx",
KnownExtensions,
MODPRIO_INTERNAL_LOW,
NULL,
&PCEInputInfo,
Load,
TestMagic,
LoadCD,
TestMagicCD,
CloseGame,
VDC_SetLayerEnableMask,
NULL,
NULL,
NULL,
NULL,
NULL,
MemRead,
NULL,
false,
StateAction,
Emulate,
PCEINPUT_SetInput,
DoSimpleCommand,
PCESettings,
MDFN_MASTERCLOCK_FIXED(PCE_MASTER_CLOCK),
0,
true, // Multires possible?
0, // lcm_width
0, // lcm_height
NULL, // Dummy
288, // Nominal width
232, // Nominal height
512, // Framebuffer width
242, // Framebuffer height
2, // Number of output sound channels
};

View File

@ -0,0 +1,62 @@
#ifndef _PCE_H
#define _PCE_H
#include "../mednafen-types.h"
#include "../mednafen.h"
#include "../state.h"
#include "../general.h"
#include "../mednafen-memory.h"
#ifdef __LIBRETRO__
#define GET_FDATA(fp) (fp.f_data)
#define GET_FSIZE(fp) (fp.f_size)
#define GET_FEXTS(fp) (fp.f_ext)
#define GET_FDATA_PTR(fp) (fp->f_data)
#define GET_FSIZE_PTR(fp) (fp->f_size)
#define GET_FEXTS_PTR(fp) (fp->f_ext)
#define gzread(a, b, c) fread(b, c, 1, a)
#else
#define GET_FDATA(fp) (fp.Data())
#define GET_FSIZE(fp) (fp.Size())
#define GET_FDATA_PTR(fp) (fp->data)
#define GET_FSIZE_PTR(fp) (fp->size)
#define GET_FEXTS_PTR(fp) (fp->ext)
#define gzread(a, b, c) gzread(a, b, c)
#endif
#define PCE_MASTER_CLOCK 21477272.727273
#define DECLFR(x) uint8 MDFN_FASTCALL x (uint32 A)
#define DECLFW(x) void MDFN_FASTCALL x (uint32 A, uint8 V)
namespace PCE_Fast
{
extern uint8 ROMSpace[0x88 * 8192 + 8192];
typedef void (MDFN_FASTCALL *writefunc)(uint32 A, uint8 V);
typedef uint8 (MDFN_FASTCALL *readfunc)(uint32 A);
extern uint8 PCEIODataBuffer;
bool PCE_InitCD(void) MDFN_COLD;
};
#include "huc6280.h"
namespace PCE_Fast
{
extern bool PCE_ACEnabled; // Arcade Card emulation enabled?
void PCE_Power(void) MDFN_COLD;
extern readfunc PCERead[0x100];
extern writefunc PCEWrite[0x100];
extern int pce_overclocked;
extern uint8 BaseRAM[32768 + 8192];
};
using namespace PCE_Fast;
#endif

View File

@ -0,0 +1,984 @@
/* Mednafen - Multi-system Emulator
*
* Copyright notice for this file:
* Copyright (C) 2004 Ki
* Copyright (C) 2007-2011 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
PCE_FAST(less accurate, faster, etc.) fork from PCE module "pcecd.cpp".
*/
#include "../mednafen.h"
#include "../cdrom/cdromif.h"
#include "pcecd_drive.h"
#include "../okiadpcm.h"
#include "pcecd.h"
#include "../cdrom/SimpleFIFO.h"
namespace PCE_Fast
{
//#define PCECD_DEBUG
static unsigned int OC_Multiplier;
static void (*IRQCB)(bool asserted);
static float CDDAVolumeSetting; // User setting!
static bool bBRAMEnabled;
static uint8 _Port[15];
static uint8 ACKStatus;
static SimpleFIFO<uint8> SubChannelFIFO(16);
static Blip_Buffer *sbuf[2];
static int16 RawPCMVolumeCache[2];
static int32 ClearACKDelay;
static int32 lastts;
static int32 pcecd_drive_ne = 0;
// ADPCM variables and whatnot
#define ADPCM_DEBUG(x, ...) { /*printf("[Half=%d, End=%d, Playing=%d] "x, ADPCM.HalfReached, ADPCM.EndReached, ADPCM.Playing, ## __VA_ARGS__);*/ }
typedef Blip_Synth<blip_good_quality, 16384> ADSynth;
static ADSynth ADPCMSynth;
static OKIADPCM_Decoder<OKIADPCM_MSM5205> MSM5205;
static bool ADPCMLP;
typedef struct
{
uint8 *RAM; // = NULL; //0x10000;
uint16 Addr;
uint16 ReadAddr;
uint16 WriteAddr;
uint16 LengthCount;
bool HalfReached;
bool EndReached;
bool Playing;
uint8 LastCmd;
uint32 SampleFreq;
uint32 LPF_SampleFreq;
uint8 PlayBuffer;
uint8 ReadBuffer;
int32 ReadPending;
int32 WritePending;
uint8 WritePendingValue;
uint32 PlayNibble;
int64 bigdivacc;
int64 bigdiv;
int32 last_pcm;
} ADPCM_t;
static ADPCM_t ADPCM;
typedef struct
{
uint8 Command;
int32 Volume;
int32 CycleCounter;
uint32 CountValue; // What to reload CycleCounter with when it expires.
bool Clocked;
} FADE_t;
static FADE_t Fader;
static int32 ADPCMFadeVolume, CDDAFadeVolume;
static INLINE void Fader_SyncWhich(void)
{
if(Fader.Command & 0x2) // ADPCM fade
{
ADPCMFadeVolume = Fader.Volume;
CDDAFadeVolume = 65536;
}
else // CD-DA Fade
{
CDDAFadeVolume = Fader.Volume;
ADPCMFadeVolume = 65536;
}
ADPCMFadeVolume >>= 6;
PCECD_Drive_SetCDDAVolume(0.50f * CDDAFadeVolume * CDDAVolumeSetting);
}
static void RedoLPF(int f)
{
if(sbuf[0] && sbuf[1])
{
if(ADPCMLP)
{
if(f >= 14)
{
int rolloff = (int)((((double)32087.5 / (16 - f)) / 2) * 0.70);
ADPCMSynth.treble_eq( blip_eq_t(-1000, rolloff, sbuf[0]->sample_rate()));
}
else
{
int rolloff = (int)((((double)32087.5 / (16 - f)) / 2) * 0.80);
ADPCMSynth.treble_eq( blip_eq_t(-1000, rolloff, sbuf[0]->sample_rate()));
}
}
else
ADPCMSynth.treble_eq(-8.0);
}
}
static INLINE int32 ADPCM_ClocksToNextEvent(void)
{
int32 ret = (ADPCM.bigdiv + 65535) >> 16;
if(ADPCM.WritePending && ret > ADPCM.WritePending)
ret = ADPCM.WritePending;
if(ADPCM.ReadPending && ret > ADPCM.ReadPending)
ret = ADPCM.ReadPending;
return(ret);
}
static int32 CalcNextEvent(int32 base)
{
int32 next_event = base;
int32 ADPCM_ctne = ADPCM_ClocksToNextEvent();
if(next_event > ADPCM_ctne)
next_event = ADPCM_ctne;
if(ClearACKDelay > 0 && next_event > ClearACKDelay)
next_event = ClearACKDelay;
if(next_event > pcecd_drive_ne)
next_event = pcecd_drive_ne;
if(Fader.Clocked && next_event > Fader.CycleCounter)
next_event = Fader.CycleCounter;
return(next_event);
}
static void update_irq_state()
{
uint8 irq = _Port[2] & _Port[0x3] & (0x4|0x8|0x10|0x20|0x40);
IRQCB((bool)irq);
}
static void StuffSubchannel(uint8 meow, int subindex)
{
uint8 tmp_data = meow & 0x7F;
if(subindex == -2)
tmp_data = 0x00;
else if(subindex == -1)
tmp_data = 0x80;
if(SubChannelFIFO.CanWrite())
SubChannelFIFO.Write(&tmp_data, 1);
_Port[0x3] |= 0x10;
update_irq_state();
}
static void CDIRQ(int type)
{
#ifdef PCECD_DEBUG
if(type != 0x8000 || _Port[0x3] & 0x60)
printf("CDIRQ: %d\n", type);
#endif
if(type & 0x8000)
{
type &= 0x7FFF;
if(type == PCECD_Drive_IRQ_DATA_TRANSFER_DONE)
_Port[0x3] &= ~0x20;
else if(type == PCECD_Drive_IRQ_DATA_TRANSFER_READY)
_Port[0x3] &= ~0x40;
}
else if(type == PCECD_Drive_IRQ_DATA_TRANSFER_DONE)
{
_Port[0x3] |= 0x20;
}
else if(type == PCECD_Drive_IRQ_DATA_TRANSFER_READY)
{
_Port[0x3] |= 0x40;
}
update_irq_state();
}
static void UpdateADPCMIRQState(void)
{
_Port[0x3] &= ~0xC;
_Port[0x3] |= ADPCM.HalfReached ? 0x4 : 0x0;
_Port[0x3] |= ADPCM.EndReached ? 0x8 : 0x0;
update_irq_state();
}
static INLINE uint8 read_1808(int32 timestamp)
{
uint8 ret = PCECD_Drive_GetDB();
if(PCECD_Drive_GetREQ() && !PCECD_Drive_GetACK() && !PCECD_Drive_GetCD())
{
if(PCECD_Drive_GetIO())
{
PCECD_Drive_SetACK(TRUE);
ACKStatus = TRUE;
pcecd_drive_ne = PCECD_Drive_Run(timestamp);
ClearACKDelay = 15 * 3;
}
}
return(ret);
}
bool PCECD_SetSettings(const PCECD_Settings *settings)
{
if(settings)
{
assert(settings->CDDA_Volume <= 2.0);
assert(settings->ADPCM_Volume <= 2.0);
}
CDDAVolumeSetting = settings ? settings->CDDA_Volume : 1.0;
Fader_SyncWhich();
ADPCMSynth.volume(0.42735f * (settings ? settings->ADPCM_Volume : 1.0));
ADPCMLP = settings ? settings->ADPCM_LPF : 0;
PCECD_Drive_SetTransferRate(126000 * (settings ? settings->CD_Speed : 1));
return true;
}
bool PCECD_Init(const PCECD_Settings *settings, void (*irqcb)(bool), double master_clock, unsigned int ocm, Blip_Buffer *soundbuf_l, Blip_Buffer *soundbuf_r)
{
lastts = 0;
OC_Multiplier = ocm;
IRQCB = irqcb;
sbuf[0] = soundbuf_l;
sbuf[1] = soundbuf_r;
// Warning: magic number 126000 in PCECD_SetSettings() too
PCECD_Drive_Init(3 * OC_Multiplier, sbuf[0], sbuf[1], 126000 * (settings ? settings->CD_Speed : 1), master_clock * OC_Multiplier, CDIRQ, StuffSubchannel);
if(!(ADPCM.RAM = (uint8 *)MDFN_malloc(0x10000, _("PCE ADPCM RAM"))))
{
return(0);
}
PCECD_SetSettings(settings);
ADPCM.bigdivacc = (int64)((double)master_clock * OC_Multiplier * 65536 / 32087.5);
return(TRUE);
}
void PCECD_Close(void)
{
if(ADPCM.RAM)
{
MDFN_free(ADPCM.RAM);
ADPCM.RAM = NULL;
}
PCECD_Drive_Close();
}
void PCECD_Power(uint32 timestamp)
{
if((int32)timestamp != lastts)
(void)PCECD_Run(timestamp);
IRQCB(0);
PCECD_Drive_Power(timestamp);
pcecd_drive_ne = 0x7fffffff;
bBRAMEnabled = FALSE;
memset(_Port, 0, sizeof(_Port));
ACKStatus = 0;
ClearACKDelay = 0;
memset(ADPCM.RAM, 0x00, 65536);
ADPCM.ReadPending = ADPCM.WritePending = 0;
ADPCM.ReadBuffer = 0;
ADPCM.PlayBuffer = 0;
ADPCM.LastCmd = 0;
MSM5205.SetSample(0x800);
MSM5205.SetSSI(0);
ADPCM.SampleFreq = 0;
ADPCM.LPF_SampleFreq = 0;
ADPCM.bigdiv = ADPCM.bigdivacc * (16 - ADPCM.SampleFreq);
RedoLPF(ADPCM.LPF_SampleFreq);
ADPCM.Addr = 0;
ADPCM.ReadAddr = 0;
ADPCM.WriteAddr = 0;
ADPCM.LengthCount = 0;
ADPCM.LastCmd = 0;
ADPCM.HalfReached = false;
ADPCM.EndReached = false;
ADPCM.Playing = false;
ADPCM.PlayNibble = 0;
UpdateADPCMIRQState();
Fader.Command = 0x00;
Fader.Volume = 0;
Fader.CycleCounter = 0;
Fader.CountValue = 0;
Fader.Clocked = FALSE;
}
bool PCECD_IsBRAMEnabled(void)
{
return bBRAMEnabled;
}
uint8 PCECD_Read(uint32 timestamp, uint32 A)
{
uint8 ret = 0;
if((A & 0x18c0) == 0x18c0)
{
switch (A & 0x18cf)
{
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;
}
}
else
{
PCECD_Run(timestamp);
switch(A & 0xf)
{
case 0x0:
ret = 0;
ret |= PCECD_Drive_GetBSY() ? 0x80 : 0x00;
ret |= PCECD_Drive_GetREQ() ? 0x40 : 0x00;
ret |= PCECD_Drive_GetMSG() ? 0x20 : 0x00;
ret |= PCECD_Drive_GetCD() ? 0x10 : 0x00;
ret |= PCECD_Drive_GetIO() ? 0x08 : 0x00;
break;
case 0x1: ret = PCECD_Drive_GetDB();
break;
case 0x2: ret = _Port[2];
break;
case 0x3: bBRAMEnabled = FALSE;
/* switch left/right of digitized cd playback */
ret = _Port[0x3];
_Port[0x3] ^= 2;
break;
case 0x4: ret = _Port[4];
break;
case 0x5: if(_Port[0x3] & 0x2)
ret = RawPCMVolumeCache[1] & 0xff; // Right
else
ret = RawPCMVolumeCache[0] & 0xff; // Left
break;
case 0x6: if(_Port[0x3] & 0x2)
ret = ((uint16)RawPCMVolumeCache[1]) >> 8; // Right
else
ret = ((uint16)RawPCMVolumeCache[0]) >> 8; // Left
break;
case 0x7:
if(SubChannelFIFO.CanRead() > 0)
ret = SubChannelFIFO.ReadByte();
else
ret = 0x00; // Not sure if it's 0, 0xFF, the last byte read, or something else.
if(SubChannelFIFO.CanRead() == 0)
{
_Port[0x3] &= ~0x10;
update_irq_state();
}
break;
case 0x8:
ret = read_1808(timestamp);
break;
case 0xa:
ADPCM_DEBUG("ReadBuffer\n");
ADPCM.ReadPending = 19 * 3; //24 * 3;
ret = ADPCM.ReadBuffer;
break;
case 0xb:
ret = _Port[0xb];
break;
case 0xc:
//printf("ADPCM Status Read: %d\n", timestamp);
ret = 0x00;
ret |= (ADPCM.EndReached) ? 0x01 : 0x00;
ret |= (ADPCM.Playing) ? 0x08 : 0x00;
ret |= (ADPCM.WritePending > 0) ? 0x04 : 0x00;
ret |= (ADPCM.ReadPending > 0) ? 0x80 : 0x00;
break;
case 0xd:
ret = ADPCM.LastCmd;
break;
}
}
#ifdef PCECD_DEBUG
printf("Read: %04x %02x, %d\n", A, ret, timestamp);
#endif
return(ret);
}
static INLINE void Fader_Run(const int32 clocks)
{
if(Fader.Clocked)
{
Fader.CycleCounter -= clocks;
while(Fader.CycleCounter <= 0)
{
if(Fader.Volume)
Fader.Volume--;
Fader_SyncWhich();
Fader.CycleCounter += Fader.CountValue;
}
}
}
void PCECD_Write(uint32 timestamp, uint32 physAddr, uint8 data)
{
const uint8 V = data;
#ifdef PCECD_DEBUG
printf("Write: (PC=%04x, t=%6d) %04x %02x; MSG: %d, REQ: %d, ACK: %d, CD: %d, IO: %d, BSY: %d, SEL: %d\n", HuCPU.PC, timestamp, physAddr, data, PCECD_Drive_GetMSG(), PCECD_Drive_GetREQ(), PCECD_Drive_GetACK(), PCECD_Drive_GetCD(), PCECD_Drive_GetIO(), PCECD_Drive_GetBSY(), PCECD_Drive_GetSEL());
#endif
PCECD_Run(timestamp);
switch (physAddr & 0xf)
{
case 0x0:
PCECD_Drive_SetSEL(1);
PCECD_Drive_Run(timestamp);
PCECD_Drive_SetSEL(0);
pcecd_drive_ne = PCECD_Drive_Run(timestamp);
/* reset irq status */
_Port[0x3] &= ~(0x20 | 0x40); // TODO: Confirm writing this register really reset these bits.
update_irq_state();
break;
case 0x1: // $1801
_Port[1] = data;
PCECD_Drive_SetDB(data);
pcecd_drive_ne = PCECD_Drive_Run(timestamp);
break;
case 0x2: // $1802
#ifdef PCECD_DEBUG
if(!(_Port[0x3] & _Port[2] & 0x40) && (_Port[0x3] & data & 0x40))
puts("IRQ on waah 0x40");
if(!(_Port[0x3] & _Port[2] & 0x20) && (_Port[0x3] & data & 0x20))
puts("IRQ on waah 0x20");
#endif
PCECD_Drive_SetACK(data & 0x80);
pcecd_drive_ne = PCECD_Drive_Run(timestamp);
_Port[2] = data;
ACKStatus = (bool)(data & 0x80);
update_irq_state();
break;
case 0x3: // read only
break;
case 0x4:
PCECD_Drive_SetRST(data & 0x2);
pcecd_drive_ne = PCECD_Drive_Run(timestamp);
if(data & 0x2)
{
_Port[0x3] &= ~0x70;
update_irq_state();
}
_Port[4] = data;
break;
case 0x5:
case 0x6:
{
int16 left, right;
PCECD_Drive_GetCDDAValues(left, right);
RawPCMVolumeCache[0] = ((int64)abs(left) * CDDAFadeVolume) >> 16;
RawPCMVolumeCache[1] = ((int64)abs(right) * CDDAFadeVolume) >> 16;
}
break;
case 0x7: // $1807: D7=1 enables backup ram
if (data & 0x80)
{
bBRAMEnabled = TRUE;
}
break;
case 0x8: // Set ADPCM address low
if(ADPCM.LastCmd & 0x80)
break;
ADPCM.Addr &= 0xFF00;
ADPCM.Addr |= V;
ADPCM_DEBUG("SAL: %02x, %d\n", V, timestamp);
// Length appears to be constantly latched when D4 is set(tested on a real system)
if(ADPCM.LastCmd & 0x10)
{
ADPCM_DEBUG("Set length(crazy way L): %04x\n", ADPCM.Addr);
ADPCM.LengthCount = ADPCM.Addr;
}
break;
case 0x9: // Set ADPCM address high
if(ADPCM.LastCmd & 0x80)
break;
ADPCM.Addr &= 0x00FF;
ADPCM.Addr |= V << 8;
ADPCM_DEBUG("SAH: %02x, %d\n", V, timestamp);
// Length appears to be constantly latched when D4 is set(tested on a real system)
if(ADPCM.LastCmd & 0x10)
{
ADPCM_DEBUG("Set length(crazy way H): %04x\n", ADPCM.Addr);
ADPCM.LengthCount = ADPCM.Addr;
}
break;
case 0xa:
//ADPCM_DEBUG("Write: %02x, %d\n", V, timestamp);
ADPCM.WritePending = 3 * 11;
ADPCM.WritePendingValue = data;
break;
case 0xb: // adpcm dma
ADPCM_DEBUG("DMA: %02x\n", V);
_Port[0xb] = data;
break;
case 0xc: // read-only
break;
case 0xd:
ADPCM_DEBUG("Write180D: %02x\n", V);
if(data & 0x80)
{
ADPCM.Addr = 0;
ADPCM.ReadAddr = 0;
ADPCM.WriteAddr = 0;
ADPCM.LengthCount = 0;
ADPCM.LastCmd = 0;
ADPCM.Playing = false;
ADPCM.HalfReached = false;
ADPCM.EndReached = false;
ADPCM.PlayNibble = 0;
UpdateADPCMIRQState();
MSM5205.SetSample(0x800);
MSM5205.SetSSI(0);
break;
}
if(ADPCM.Playing && !(data & 0x20))
ADPCM.Playing = false;
if(!ADPCM.Playing && (data & 0x20))
{
ADPCM.bigdiv = ADPCM.bigdivacc * (16 - ADPCM.SampleFreq);
ADPCM.Playing = true;
ADPCM.HalfReached = false; // Not sure about this.
ADPCM.PlayNibble = 0;
MSM5205.SetSample(0x800);
MSM5205.SetSSI(0);
}
// Length appears to be constantly latched when D4 is set(tested on a real system)
if(data & 0x10)
{
ADPCM_DEBUG("Set length: %04x\n", ADPCM.Addr);
ADPCM.LengthCount = ADPCM.Addr;
ADPCM.EndReached = false;
}
// D2 and D3 control read address
if(!(ADPCM.LastCmd & 0x8) && (data & 0x08))
{
if(data & 0x4)
ADPCM.ReadAddr = ADPCM.Addr;
else
ADPCM.ReadAddr = (ADPCM.Addr - 1) & 0xFFFF;
ADPCM_DEBUG("Set ReadAddr: %04x, %06x\n", ADPCM.Addr, ADPCM.ReadAddr);
}
// D0 and D1 control write address
if(!(ADPCM.LastCmd & 0x2) && (data & 0x2))
{
ADPCM.WriteAddr = ADPCM.Addr;
if(!(data & 0x1))
ADPCM.WriteAddr = (ADPCM.WriteAddr - 1) & 0xFFFF;
ADPCM_DEBUG("Set WriteAddr: %04x, %06x\n", ADPCM.Addr, ADPCM.WriteAddr);
}
ADPCM.LastCmd = data;
UpdateADPCMIRQState();
break;
case 0xe: // Set ADPCM playback rate
{
uint8 freq = V & 0x0F;
ADPCM.SampleFreq = freq;
ADPCM_DEBUG("Freq: %02x\n", freq);
}
break;
case 0xf:
Fader.Command = V;
#ifdef PCECD_DEBUG
printf("Fade: %02x\n", data);
#endif
// Cancel fade
if(!(V & 0x8))
{
Fader.Volume = 65536;
Fader.CycleCounter = 0;
Fader.CountValue = 0;
Fader.Clocked = FALSE;
}
else
{
Fader.CountValue = OC_Multiplier * 3 * ((V & 0x4) ? 273 : 655); // 2.500s : 6.000s;
if(!Fader.Clocked)
Fader.CycleCounter = Fader.CountValue;
Fader.Clocked = TRUE;
}
Fader_SyncWhich();
break;
}
}
static INLINE void ADPCM_PB_Run(int32 basetime, int32 run_time)
{
ADPCM.bigdiv -= run_time * 65536;
while(ADPCM.bigdiv <= 0)
{
ADPCM.bigdiv += ADPCM.bigdivacc * (16 - ADPCM.SampleFreq);
if(ADPCM.Playing && !ADPCM.PlayNibble) // Do playback sample buffer fetch.
{
ADPCM.HalfReached = (ADPCM.LengthCount < 32768);
if(!ADPCM.LengthCount && !(ADPCM.LastCmd & 0x10))
{
if(ADPCM.EndReached)
ADPCM.HalfReached = false;
ADPCM.EndReached = true;
if(ADPCM.LastCmd & 0x40)
ADPCM.Playing = false;
}
ADPCM.PlayBuffer = ADPCM.RAM[ADPCM.ReadAddr];
ADPCM.ReadAddr = (ADPCM.ReadAddr + 1) & 0xFFFF;
if(ADPCM.LengthCount && !(ADPCM.LastCmd & 0x10))
ADPCM.LengthCount--;
}
if(ADPCM.Playing)
{
int32 pcm;
uint8 nibble;
nibble = (ADPCM.PlayBuffer >> (ADPCM.PlayNibble ^ 4)) & 0x0F;
pcm = MSM5205.Decode(nibble) - 2048;
ADPCM.PlayNibble ^= 4;
pcm = (pcm * ADPCMFadeVolume) >> 8;
uint32 synthtime = ((basetime + (ADPCM.bigdiv >> 16))) / (3 * OC_Multiplier);
if(sbuf[0] && sbuf[1])
{
ADPCMSynth.offset(synthtime, pcm - ADPCM.last_pcm, sbuf[0]);
ADPCMSynth.offset(synthtime, pcm - ADPCM.last_pcm, sbuf[1]);
}
ADPCM.last_pcm = pcm;
}
}
}
static INLINE void ADPCM_Run(const int32 clocks, const int32 timestamp)
{
//printf("ADPCM Run: %d\n", clocks);
ADPCM_PB_Run(timestamp, clocks);
if(ADPCM.WritePending)
{
ADPCM.WritePending -= clocks;
if(ADPCM.WritePending <= 0)
{
ADPCM.HalfReached = (ADPCM.LengthCount < 32768);
if(!(ADPCM.LastCmd & 0x10) && ADPCM.LengthCount < 0xFFFF)
ADPCM.LengthCount++;
ADPCM.RAM[ADPCM.WriteAddr++] = ADPCM.WritePendingValue;
ADPCM.WritePending = 0;
}
}
if(!ADPCM.WritePending)
{
if(_Port[0xb] & 0x3)
{
// Run PCECD_Drive before we examine the signals.
pcecd_drive_ne = PCECD_Drive_Run(timestamp);
if(!PCECD_Drive_GetCD() && PCECD_Drive_GetIO() && PCECD_Drive_GetREQ() && !PCECD_Drive_GetACK())
{
ADPCM.WritePendingValue = read_1808(timestamp);
ADPCM.WritePending = 10 * 3;
}
}
}
if(ADPCM.ReadPending)
{
ADPCM.ReadPending -= clocks;
if(ADPCM.ReadPending <= 0)
{
ADPCM.ReadBuffer = ADPCM.RAM[ADPCM.ReadAddr];
ADPCM.ReadAddr = (ADPCM.ReadAddr + 1) & 0xFFFF;
ADPCM.ReadPending = 0;
ADPCM.HalfReached = (ADPCM.LengthCount < 32768);
if(!(ADPCM.LastCmd & 0x10))
{
if(ADPCM.LengthCount)
ADPCM.LengthCount--;
else
{
ADPCM.EndReached = true;
ADPCM.HalfReached = false;
if(ADPCM.LastCmd & 0x40)
ADPCM.Playing = false;
}
}
}
}
UpdateADPCMIRQState();
}
void PCECD_Run(uint32 in_timestamp)
{
int32 clocks = in_timestamp - lastts;
int32 running_ts = lastts;
//printf("Run Begin: Clocks=%d(%d - %d), cl=%d\n", clocks, in_timestamp, lastts, CalcNextEvent);
//fflush(stdout);
while(clocks > 0)
{
int32 chunk_clocks = CalcNextEvent(clocks);
running_ts += chunk_clocks;
if(ClearACKDelay > 0)
{
ClearACKDelay -= chunk_clocks;
if(ClearACKDelay <= 0)
{
ACKStatus = FALSE;
PCECD_Drive_SetACK(FALSE);
PCECD_Drive_Run(running_ts);
if(PCECD_Drive_GetCD())
{
_Port[0xb] &= ~1;
#ifdef PCECD_DEBUG
puts("DMA End");
#endif
}
}
}
Fader_Run(chunk_clocks);
ADPCM_Run(chunk_clocks, running_ts);
pcecd_drive_ne = PCECD_Drive_Run(running_ts);
clocks -= chunk_clocks;
}
lastts = in_timestamp;
}
void PCECD_ResetTS(void)
{
if(ADPCM.SampleFreq != ADPCM.LPF_SampleFreq)
{
ADPCM.LPF_SampleFreq = ADPCM.SampleFreq;
RedoLPF(ADPCM.LPF_SampleFreq);
}
PCECD_Drive_ResetTS();
lastts = 0;
}
static int ADPCM_StateAction(StateMem *sm, int load, int data_only)
{
uint32 ad_sample = MSM5205.GetSample();
int32 ad_ref_index = MSM5205.GetSSI();
SFORMAT StateRegs[] =
{
SFARRAY(ADPCM.RAM, 0x10000),
SFVAR(ADPCM.bigdiv),
SFVAR(ADPCM.Addr),
SFVAR(ADPCM.ReadAddr),
SFVAR(ADPCM.WriteAddr),
SFVAR(ADPCM.LengthCount),
SFVAR(ADPCM.LastCmd),
SFVAR(ADPCM.SampleFreq),
SFVAR(ADPCM.ReadPending),
SFVAR(ADPCM.ReadBuffer),
SFVAR(ADPCM.PlayBuffer),
SFVAR(ADPCM.WritePending),
SFVAR(ADPCM.WritePendingValue),
SFVAR(ADPCM.HalfReached),
SFVAR(ADPCM.EndReached),
SFVAR(ADPCM.Playing),
SFVAR(ADPCM.PlayNibble),
SFVAR(ad_sample),
SFVAR(ad_ref_index),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "APCM");
if(load)
{
MSM5205.SetSample(ad_sample);
MSM5205.SetSSI(ad_ref_index);
RedoLPF(ADPCM.SampleFreq);
}
return(ret);
}
int PCECD_StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT StateRegs[] =
{
SFVAR(bBRAMEnabled),
SFVAR(ACKStatus),
SFVAR(ClearACKDelay),
SFARRAY16(RawPCMVolumeCache, 2),
SFARRAY(_Port, sizeof(_Port)),
SFVAR(Fader.Command),
SFVAR(Fader.Volume),
SFVAR(Fader.CycleCounter),
SFVAR(Fader.CountValue),
SFVAR(Fader.Clocked),
SFARRAY(&SubChannelFIFO.data[0], SubChannelFIFO.data.size()),
SFVAR(SubChannelFIFO.read_pos),
SFVAR(SubChannelFIFO.write_pos),
SFVAR(SubChannelFIFO.in_count),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "PECD");
ret &= PCECD_Drive_StateAction(sm, load, data_only, "CDRM");
ret &= ADPCM_StateAction(sm, load, data_only);
if(load)
{
Fader_SyncWhich();
//PCECD_Drive_SetDB(_Port[1]);
PCECD_Drive_SetACK(ACKStatus);
PCECD_Drive_SetRST(_Port[4] & 0x2);
SubChannelFIFO.read_pos %= SubChannelFIFO.size;
SubChannelFIFO.write_pos %= SubChannelFIFO.size;
}
return(ret);
}
}

View File

@ -0,0 +1,37 @@
#ifndef __PCE_CDROM_H
#define __PCE_CDROM_H
#include <blip/Blip_Buffer.h>
namespace PCE_Fast
{
typedef struct
{
float CDDA_Volume; // Max 2.000...
float ADPCM_Volume; // Max 2.000...
unsigned int CD_Speed;
bool ADPCM_LPF;
} PCECD_Settings;
void PCECD_Run(uint32 in_timestamp);
void PCECD_ResetTS(void);
bool PCECD_Init(const PCECD_Settings *settings, void (*irqcb)(bool), double master_clock, unsigned int ocm, Blip_Buffer *soundbuf_l, Blip_Buffer *soundbuf_r) MDFN_COLD;
bool PCECD_SetSettings(const PCECD_Settings *settings) MDFN_COLD;
void PCECD_Close(void) MDFN_COLD;
void PCECD_Power(uint32 timestamp) MDFN_COLD;
uint8 PCECD_Read(uint32 timestamp, uint32);
void PCECD_Write(uint32 timestamp, uint32, uint8 data);
bool PCECD_IsBRAMEnabled(void);
int PCECD_StateAction(StateMem *sm, int load, int data_only);
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
#ifndef __PCEFAST_PCECD_Drive_H
#define __PCEFAST_PCECD_Drive_H
#include <blip/Blip_Buffer.h>
namespace PCE_Fast
{
typedef int32 pcecd_drive_timestamp_t;
struct pcecd_drive_bus_t
{
// Data bus(FIXME: we should have a variable for the target and the initiator, and OR them together to be truly accurate).
uint8 DB;
uint32 signals;
};
extern pcecd_drive_bus_t cd_bus; // Don't access this structure directly by name outside of pcecd_drive.c, but use the macros below.
// Signals under our(the "target") control.
#define PCECD_Drive_IO_mask 0x001
#define PCECD_Drive_CD_mask 0x002
#define PCECD_Drive_MSG_mask 0x004
#define PCECD_Drive_REQ_mask 0x008
#define PCECD_Drive_BSY_mask 0x010
// Signals under the control of the initiator(not us!)
#define PCECD_Drive_kingRST_mask 0x020
#define PCECD_Drive_kingACK_mask 0x040
#define PCECD_Drive_kingSEL_mask 0x100
#define BSY_signal ((const bool)(cd_bus.signals & PCECD_Drive_BSY_mask))
#define ACK_signal ((const bool)(cd_bus.signals & PCECD_Drive_kingACK_mask))
#define RST_signal ((const bool)(cd_bus.signals & PCECD_Drive_kingRST_mask))
#define MSG_signal ((const bool)(cd_bus.signals & PCECD_Drive_MSG_mask))
#define SEL_signal ((const bool)(cd_bus.signals & PCECD_Drive_kingSEL_mask))
#define REQ_signal ((const bool)(cd_bus.signals & PCECD_Drive_REQ_mask))
#define IO_signal ((const bool)(cd_bus.signals & PCECD_Drive_IO_mask))
#define CD_signal ((const bool)(cd_bus.signals & PCECD_Drive_CD_mask))
#define DB_signal ((const uint8)cd_bus.DB)
#define PCECD_Drive_GetDB() DB_signal
#define PCECD_Drive_GetBSY() BSY_signal
#define PCECD_Drive_GetIO() IO_signal
#define PCECD_Drive_GetCD() CD_signal
#define PCECD_Drive_GetMSG() MSG_signal
#define PCECD_Drive_GetREQ() REQ_signal
// Should we phase out getting these initiator-driven signals like this(the initiator really should keep track of them itself)?
#define PCECD_Drive_GetACK() ACK_signal
#define PCECD_Drive_GetRST() RST_signal
#define PCECD_Drive_GetSEL() SEL_signal
void PCECD_Drive_Power(pcecd_drive_timestamp_t system_timestamp);
void PCECD_Drive_SetDB(uint8 data);
// These PCECD_Drive_Set* functions are kind of misnomers, at least in comparison to the PCECD_Drive_Get* functions...
// They will set/clear the bits corresponding to the KING's side of the bus.
void PCECD_Drive_SetACK(bool set);
void PCECD_Drive_SetSEL(bool set);
void PCECD_Drive_SetRST(bool set);
uint32 PCECD_Drive_Run(pcecd_drive_timestamp_t);
void PCECD_Drive_ResetTS(void);
enum
{
PCECD_Drive_IRQ_DATA_TRANSFER_DONE = 1,
PCECD_Drive_IRQ_DATA_TRANSFER_READY,
PCECD_Drive_IRQ_MAGICAL_REQ,
};
void PCECD_Drive_GetCDDAValues(int16 &left, int16 &right);
void PCECD_Drive_SetLog(void (*logfunc)(const char *, const char *, ...)) MDFN_COLD;
void PCECD_Drive_Init(int CDDATimeDiv, Blip_Buffer *leftbuf, Blip_Buffer *rightbuf, uint32 TransferRate, uint32 SystemClock, void (*IRQFunc)(int), void (*SSCFunc)(uint8, int)) MDFN_COLD;
void PCECD_Drive_Close(void) MDFN_COLD;
void PCECD_Drive_SetTransferRate(uint32 TransferRate);
void PCECD_Drive_SetCDDAVolume(unsigned vol); // vol of 65536 = 1.0 = maximum.
int PCECD_Drive_StateAction(StateMem *sm, int load, int data_only, const char *sname);
void PCECD_Drive_SetDisc(bool tray_open, CDIF *cdif, bool no_emu_side_effects = false) MDFN_COLD;
}
#endif

View File

@ -0,0 +1,677 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../mednafen.h"
#include "psg.h"
#include <math.h>
#include <string.h>
#include <trio/trio.h>
namespace PCE_Fast
{
void PCEFast_PSG::SetVolume(double new_volume)
{
OutputVolume = new_volume;
Synth.volume(OutputVolume / 6);
}
void PCEFast_PSG::UpdateOutput_Norm(const int32 timestamp, psg_channel *ch)
{
int32 samp[2];
int sv = ch->dda;
samp[0] = dbtable[ch->vl[0]][sv];
samp[1] = dbtable[ch->vl[1]][sv];
Synth.offset_inline(timestamp, samp[0] - ch->blip_prev_samp[0], sbuf[0]);
Synth.offset_inline(timestamp, samp[1] - ch->blip_prev_samp[1], sbuf[1]);
ch->blip_prev_samp[0] = samp[0];
ch->blip_prev_samp[1] = samp[1];
}
void PCEFast_PSG::UpdateOutput_Noise(const int32 timestamp, psg_channel *ch)
{
int32 samp[2];
int sv = ((ch->lfsr & 1) << 5) - (ch->lfsr & 1); //(ch->lfsr & 0x1) ? 0x1F : 0;
samp[0] = dbtable[ch->vl[0]][sv];
samp[1] = dbtable[ch->vl[1]][sv];
Synth.offset_inline(timestamp, samp[0] - ch->blip_prev_samp[0], sbuf[0]);
Synth.offset_inline(timestamp, samp[1] - ch->blip_prev_samp[1], sbuf[1]);
ch->blip_prev_samp[0] = samp[0];
ch->blip_prev_samp[1] = samp[1];
}
void PCEFast_PSG::UpdateOutput_Off(const int32 timestamp, psg_channel *ch)
{
int32 samp[2];
samp[0] = samp[1] = 0;
Synth.offset_inline(timestamp, samp[0] - ch->blip_prev_samp[0], sbuf[0]);
Synth.offset_inline(timestamp, samp[1] - ch->blip_prev_samp[1], sbuf[1]);
ch->blip_prev_samp[0] = samp[0];
ch->blip_prev_samp[1] = samp[1];
}
void PCEFast_PSG::UpdateOutput_Accum(const int32 timestamp, psg_channel *ch)
{
int32 samp[2];
samp[0] = ((int32)dbtable_volonly[ch->vl[0]] * ((int32)ch->samp_accum - 496)) >> (8 + 5);
samp[1] = ((int32)dbtable_volonly[ch->vl[1]] * ((int32)ch->samp_accum - 496)) >> (8 + 5);
Synth.offset_inline(timestamp, samp[0] - ch->blip_prev_samp[0], sbuf[0]);
Synth.offset_inline(timestamp, samp[1] - ch->blip_prev_samp[1], sbuf[1]);
ch->blip_prev_samp[0] = samp[0];
ch->blip_prev_samp[1] = samp[1];
}
// This function should always be called after RecalcFreqCache() (it's not called from RecalcFreqCache to avoid redundant code)
void PCEFast_PSG::RecalcUOFunc(int chnum)
{
psg_channel *ch = &channel[chnum];
//printf("UO Update: %d, %02x\n", chnum, ch->control);
if(!(ch->control & 0xC0))
ch->UpdateOutput = &PCEFast_PSG::UpdateOutput_Off;
else if(ch->noisectrl & ch->control & 0x80)
ch->UpdateOutput = &PCEFast_PSG::UpdateOutput_Noise;
// If the control for the channel is in waveform play mode, and the (real) playback frequency is too high, and the channel is either not the LFO modulator channel or
// if the LFO trigger bit(which halts the LFO modulator channel's waveform incrementing when set) is clear
else if((ch->control & 0xC0) == 0x80 && ch->freq_cache <= 0xA && (chnum != 1 || !(lfoctrl & 0x80)) )
ch->UpdateOutput = &PCEFast_PSG::UpdateOutput_Accum;
else
ch->UpdateOutput = &PCEFast_PSG::UpdateOutput_Norm;
}
void PCEFast_PSG::RecalcFreqCache(int chnum)
{
psg_channel *ch = &channel[chnum];
if(chnum == 0 && (lfoctrl & 0x03))
{
const uint32 shift = (((lfoctrl & 0x3) - 1) << 1);
uint8 la = channel[1].dda;
int32 tmp_freq = ((int32)ch->frequency + ((la - 0x10) << shift)) & 0xFFF;
ch->freq_cache = (tmp_freq ? tmp_freq : 4096) << 1;
}
else
{
ch->freq_cache = (ch->frequency ? ch->frequency : 4096) << 1;
if(chnum == 1 && (lfoctrl & 0x03))
ch->freq_cache *= lfofreq ? lfofreq : 256;
}
}
void PCEFast_PSG::RecalcNoiseFreqCache(int chnum)
{
psg_channel *ch = &channel[chnum];
int32 freq = 0x1F - (ch->noisectrl & 0x1F);
if(!freq)
freq = 0x20;
else
freq <<= 6;
freq <<= 1;
ch->noise_freq_cache = freq;
}
PCEFast_PSG::PCEFast_PSG(Blip_Buffer *bb_l, Blip_Buffer *bb_r)
{
//printf("Test: %u, %u\n", sizeof(psg_channel), (uint8*)&channel[0].balance - (uint8*)&channel[0].waveform[0]);
Synth.treble_eq(-2.0);
sbuf[0] = bb_l;
sbuf[1] = bb_r;
lastts = 0;
for(int ch = 0; ch < 6; ch++)
{
channel[ch].blip_prev_samp[0] = 0;
channel[ch].blip_prev_samp[1] = 0;
channel[ch].lastts = 0;
}
SetVolume(1.0);
for(int vl = 0; vl < 32; vl++)
{
double flub = 1;
if(vl)
flub /= pow(2, (double)1 / 4 * vl); // ~1.5dB reduction per increment of vl
if(vl == 0x1F)
flub = 0;
for(int samp = 0; samp < 32; samp++)
{
int eff_samp = samp * 2 - 0x1F;
dbtable[vl][samp] = (int32)(flub * eff_samp * 128);
dbtable_volonly[vl] = (int32)(flub * 65536);
}
}
Power(0);
}
PCEFast_PSG::~PCEFast_PSG()
{
}
int32 PCEFast_PSG::GetVL(const int chnum, const int lr)
{
// Note: Changing the 0x1F(not that there should be) would require changing the channel pseudo-off volume check logic later on.
static const uint8 scale_tab[] =
{
0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x10, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F
};
psg_channel *ch = &channel[chnum];
const int gbal = 0x1F - scale_tab[(globalbalance >> (lr ? 0 : 4)) & 0xF];
const int bal = 0x1F - scale_tab[(ch->balance >> (lr ? 0 : 4)) & 0xF];
const int al = 0x1F - (ch->control & 0x1F);
int vol_reduction;
vol_reduction = gbal + bal + al;
if(vol_reduction > 0x1F)
vol_reduction = 0x1F;
return(vol_reduction);
}
void PCEFast_PSG::Write(int32 timestamp, uint8 A, uint8 V)
{
A &= 0x0F;
if(A == 0x00)
{
select = (V & 0x07);
return;
}
Update(timestamp);
psg_channel *ch = &channel[select];
//if(A == 0x01 || select == 5)
// printf("Write Ch: %d %04x %02x, %d\n", select, A, V, timestamp);
switch(A)
{
default: break;
case 0x01: /* Global sound balance */
globalbalance = V;
vol_pending = true;
break;
case 0x02: /* Channel frequency (LSB) */
if(select > 5) return; // no more than 6 channels, silly game.
ch->frequency = (ch->frequency & 0x0F00) | V;
RecalcFreqCache(select);
RecalcUOFunc(select);
break;
case 0x03: /* Channel frequency (MSB) */
if(select > 5) return; // no more than 6 channels, silly game.
ch->frequency = (ch->frequency & 0x00FF) | ((V & 0x0F) << 8);
RecalcFreqCache(select);
RecalcUOFunc(select);
break;
case 0x04: /* Channel enable, DDA, volume */
if(select > 5) return; // no more than 6 channels, silly game.
if((ch->control & 0x40) && !(V & 0x40))
{
ch->waveform_index = 0;
ch->dda = ch->waveform[ch->waveform_index];
ch->counter = ch->freq_cache;
}
if(!(ch->control & 0x80) && (V & 0x80))
{
if(!(V & 0x40))
{
ch->waveform_index = (ch->waveform_index + 1) & 0x1F;
ch->dda = ch->waveform[ch->waveform_index];
}
}
ch->control = V;
RecalcFreqCache(select);
RecalcUOFunc(select);
vol_pending = true;
break;
case 0x05: /* Channel balance */
if(select > 5) return; // no more than 6 channels, silly game.
ch->balance = V;
vol_pending = true;
break;
case 0x06: /* Channel waveform data */
if(select > 5) return; // no more than 6 channels, silly game.
V &= 0x1F;
if(!(ch->control & 0x40))
{
ch->samp_accum -= ch->waveform[ch->waveform_index];
ch->waveform[ch->waveform_index] = V;
ch->samp_accum += ch->waveform[ch->waveform_index];
}
if((ch->control & 0xC0) == 0x00)
ch->waveform_index = ((ch->waveform_index + 1) & 0x1F);
if(ch->control & 0x80)
{
// According to my tests(on SuperGrafx), writing to this channel
// will update the waveform value cache/latch regardless of DDA mode being enabled.
ch->dda = V;
}
break;
case 0x07: /* Noise enable and frequency */
if(select > 5) return; // no more than 6 channels, silly game.
if(select >= 4)
{
ch->noisectrl = V;
RecalcNoiseFreqCache(select);
RecalcUOFunc(select);
}
break;
case 0x08: /* LFO frequency */
lfofreq = V & 0xFF;
//printf("LFO Freq: %02x\n", V);
break;
case 0x09: /* LFO trigger and control */
//printf("LFO Ctrl: %02x\n", V);
if(V & 0x80)
{
channel[1].waveform_index = 0;
channel[1].dda = channel[1].waveform[channel[1].waveform_index];
channel[1].counter = channel[1].freq_cache;
}
lfoctrl = V;
RecalcFreqCache(0);
RecalcUOFunc(0);
RecalcFreqCache(1);
RecalcUOFunc(1);
break;
}
}
// Don't use INLINE, which has always_inline in it, due to gcc's inability to cope with the type of recursion
// used in this function.
template<bool LFO_On>
void PCEFast_PSG::RunChannel(int chc, int32 timestamp)
{
psg_channel *ch = &channel[chc];
int32 running_timestamp = ch->lastts;
int32 run_time = timestamp - ch->lastts;
ch->lastts = timestamp;
if(!run_time)
return;
(this->*ch->UpdateOutput)(running_timestamp, ch);
if(chc >= 4)
{
int32 freq = ch->noise_freq_cache;
ch->noisecount -= run_time;
#define CLOCK_LFSR(lfsr) { unsigned int newbit = ((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 11) ^ (lfsr >> 12) ^ (lfsr >> 17)) & 1; lfsr = (lfsr >> 1) | (newbit << 17); }
if(&PCEFast_PSG::UpdateOutput_Noise == ch->UpdateOutput)
{
while(ch->noisecount <= 0)
{
CLOCK_LFSR(ch->lfsr);
UpdateOutput_Noise(timestamp + ch->noisecount, ch);
ch->noisecount += freq;
}
}
else
{
while(ch->noisecount <= 0)
{
CLOCK_LFSR(ch->lfsr);
ch->noisecount += freq;
}
}
#undef CLOCK_LFSR
}
// D7 of control is 0, don't clock the counter at all.
// D7 of lfocontrol is 1(and chc == 1), don't clock the counter at all(not sure about this)
// In DDA mode, don't clock the counter.
// (Noise being enabled isn't handled here since AFAIK it doesn't disable clocking of the waveform portion, its sound just overrides the sound from
// the waveform portion when the noise enable bit is set, which is handled in our RecalcUOFunc).
if(!(ch->control & 0x80) || (chc == 1 && (lfoctrl & 0x80)) || (ch->control & 0x40))
return;
ch->counter -= run_time;
if(!LFO_On && ch->freq_cache <= 0xA)
{
if(ch->counter <= 0)
{
const int32 inc_count = ((0 - ch->counter) / ch->freq_cache) + 1;
ch->counter += inc_count * ch->freq_cache;
ch->waveform_index = (ch->waveform_index + inc_count) & 0x1F;
ch->dda = ch->waveform[ch->waveform_index];
}
}
while(ch->counter <= 0)
{
ch->waveform_index = (ch->waveform_index + 1) & 0x1F;
ch->dda = ch->waveform[ch->waveform_index];
(this->*ch->UpdateOutput)(timestamp + ch->counter, ch);
if(LFO_On)
{
RunChannel<false>(1, timestamp + ch->counter);
RecalcFreqCache(0);
RecalcUOFunc(0);
ch->counter += (ch->freq_cache <= 0xA) ? 0xA : ch->freq_cache; // Not particularly accurate, but faster.
}
else
ch->counter += ch->freq_cache;
}
}
INLINE void PCEFast_PSG::UpdateSubLFO(int32 timestamp)
{
RunChannel<true>(0, timestamp);
for(int chc = 1; chc < 6; chc++)
RunChannel<false>(chc, timestamp);
}
INLINE void PCEFast_PSG::UpdateSubNonLFO(int32 timestamp)
{
for(int chc = 0; chc < 6; chc++)
RunChannel<false>(chc, timestamp);
}
//static int32 last_read;
//static int32 last_apply;
void PCEFast_PSG::Update(int32 timestamp)
{
int32 run_time = timestamp - lastts;
if(vol_pending && !vol_update_counter && !vol_update_which)
{
vol_update_counter = 1;
vol_pending = false;
}
bool lfo_on = (bool)(lfoctrl & 0x03);
if(lfo_on)
{
if(!(channel[1].control & 0x80) || (lfoctrl & 0x80))
{
lfo_on = 0;
RecalcFreqCache(0);
RecalcUOFunc(0);
}
}
int32 clocks = run_time;
int32 running_timestamp = lastts;
while(clocks > 0)
{
int32 chunk_clocks = clocks;
if(vol_update_counter > 0 && chunk_clocks > vol_update_counter)
chunk_clocks = vol_update_counter;
running_timestamp += chunk_clocks;
clocks -= chunk_clocks;
if(lfo_on)
UpdateSubLFO(running_timestamp);
else
UpdateSubNonLFO(running_timestamp);
if(vol_update_counter > 0)
{
vol_update_counter -= chunk_clocks;
if(!vol_update_counter)
{
const int phase = vol_update_which & 1;
const int lr = ((vol_update_which >> 1) & 1) ^ 1;
const int chnum = vol_update_which >> 2;
if(!phase)
{
//printf("Volume update(Read, %d since last): ch=%d, lr=%d, ts=%d\n", running_timestamp - last_read, chnum, lr, running_timestamp);
if(chnum < 6)
{
vol_update_vllatch = GetVL(chnum, lr);
}
//last_read = running_timestamp;
}
else
{
// printf("Volume update(Apply): ch=%d, lr=%d, ts=%d\n", chnum, lr, running_timestamp);
if(chnum < 6)
{
channel[chnum].vl[lr] = vol_update_vllatch;
}
//last_apply = running_timestamp;
}
vol_update_which = (vol_update_which + 1) & 0x1F;
if(vol_update_which)
vol_update_counter = phase ? 1 : 255;
else if(vol_pending)
{
vol_update_counter = phase ? 1 : 255;
vol_pending = false;
}
}
}
lastts = running_timestamp;
}
}
void PCEFast_PSG::EndFrame(int32 timestamp)
{
Update(timestamp);
lastts = 0;
for(int chc = 0; chc < 6; chc++)
channel[chc].lastts = 0;
}
void PCEFast_PSG::Power(const int32 timestamp)
{
// Not sure about power-on values, these are mostly just intuitive guesses(with some laziness thrown in).
if(timestamp != lastts)
Update(timestamp);
memset(&channel, 0, sizeof(channel));
select = 0;
globalbalance = 0;
lfofreq = 0;
lfoctrl = 0;
for(int ch = 0; ch < 6; ch++)
{
channel[ch].frequency = 0;
channel[ch].control = 0x00;
channel[ch].balance = 0;
memset(channel[ch].waveform, 0, 32);
channel[ch].samp_accum = 0;
channel[ch].waveform_index = 0;
channel[ch].dda = 0x00;
channel[ch].noisectrl = 0x00;
channel[ch].vl[0] = 0x1F;
channel[ch].vl[1] = 0x1F;
channel[ch].samp_accum = 0;
RecalcFreqCache(ch);
RecalcUOFunc(ch);
channel[ch].counter = channel[ch].freq_cache;
if(ch >= 4)
{
RecalcNoiseFreqCache(ch);
channel[ch].noisecount = 1;
channel[ch].lfsr = 1;
}
}
vol_pending = false;
vol_update_counter = 0;
vol_update_which = 0;
}
int PCEFast_PSG::StateAction(StateMem *sm, int load, int data_only)
{
int ret = 1;
for(int ch = 0; ch < 6; ch++)
{
char tmpstr[5] = "SCHx";
psg_channel *pt = &channel[ch];
SFORMAT CH_StateRegs[] =
{
SFVARN(pt->counter, "counter"),
SFVARN(pt->frequency, "frequency"),
SFVARN(pt->control, "control"),
SFVARN(pt->balance, "balance"),
SFARRAYN(pt->waveform, 32, "waveform"),
SFVARN(pt->waveform_index, "waveform_index"),
SFVARN(pt->dda, "dda"),
SFVARN(pt->noisectrl, "noisectrl"),
SFVARN(pt->noisecount, "noisecount"),
SFVARN(pt->lfsr, "lfsr"),
SFARRAY32N(pt->vl, 2, "vl"), // TODO
SFEND
};
tmpstr[3] = '0' + ch;
ret &= MDFNSS_StateAction(sm, load, data_only, CH_StateRegs, tmpstr);
}
SFORMAT PSG_StateRegs[] =
{
SFVAR(select),
SFVAR(globalbalance),
SFVAR(lfofreq),
SFVAR(lfoctrl),
SFVAR(vol_update_counter),
SFVAR(vol_update_which),
SFVAR(vol_pending),
SFEND
};
ret &= MDFNSS_StateAction(sm, load, data_only, PSG_StateRegs, "PSG");
if(load)
{
vol_update_which &= 0x1F;
if(!channel[4].lfsr)
channel[4].lfsr = 1;
if(!channel[5].lfsr)
channel[5].lfsr = 1;
for(int ch = 0; ch < 6; ch++)
{
channel[ch].samp_accum = 0;
for(int wi = 0; wi < 32; wi++)
{
channel[ch].waveform[wi] &= 0x1F;
channel[ch].samp_accum += channel[ch].waveform[wi];
}
for(int lr = 0; lr < 2; lr++)
channel[ch].vl[lr] &= 0x1F;
if(!channel[ch].noisecount && ch >= 4)
{
printf("ch=%d, noisecount == 0\n", ch);
channel[ch].noisecount = 1;
}
if(channel[ch].counter <= 0)
{
printf("ch=%d, counter <= 0\n", ch);
channel[ch].counter = 1;
}
if(ch >= 4)
RecalcNoiseFreqCache(ch);
RecalcFreqCache(ch);
RecalcUOFunc(ch);
}
}
return(ret);
}
}

View File

@ -0,0 +1,99 @@
#ifndef _PCEFast_PSG_H
#define _PCEFast_PSG_H
#include <blip/Blip_Buffer.h>
namespace PCE_Fast
{
class PCEFast_PSG;
struct psg_channel
{
uint8 waveform[32]; /* Waveform data */
uint8 waveform_index; /* Waveform data index */
uint8 dda;
uint8 control; /* Channel enable, DDA, volume */
uint8 noisectrl; /* Noise enable/ctrl (channels 4,5 only) */
int32 vl[2]; //vll, vlr;
int32 counter;
void (PCEFast_PSG::*UpdateOutput)(const int32 timestamp, psg_channel *ch);
uint32 freq_cache;
uint32 noise_freq_cache; // Channel 4,5 only
int32 noisecount;
uint32 lfsr;
int32 samp_accum; // The result of adding up all the samples in the waveform buffer(part of an optimization for high-frequency playback).
int32 blip_prev_samp[2];
int32 lastts;
uint16 frequency; /* Channel frequency */
uint8 balance; /* Channel balance */
};
class PCEFast_PSG
{
public:
PCEFast_PSG(Blip_Buffer *bb_l, Blip_Buffer *bb_r) MDFN_COLD;
~PCEFast_PSG() MDFN_COLD;
int StateAction(StateMem *sm, int load, int data_only) MDFN_COLD;
void Power(const int32 timestamp) MDFN_COLD;
void Write(int32 timestamp, uint8 A, uint8 V);
void SetVolume(double new_volume) MDFN_COLD;
void EndFrame(int32 timestamp);
private:
void Update(int32 timestamp);
void UpdateSubLFO(int32 timestamp);
void UpdateSubNonLFO(int32 timestamp);
void RecalcUOFunc(int chnum);
void UpdateOutput_Off(const int32 timestamp, psg_channel *ch);
void UpdateOutput_Accum(const int32 timestamp, psg_channel *ch);
void UpdateOutput_Norm(const int32 timestamp, psg_channel *ch);
void UpdateOutput_Noise(const int32 timestamp, psg_channel *ch);
int32 GetVL(const int chnum, const int lr);
void RecalcFreqCache(int chnum);
void RecalcNoiseFreqCache(int chnum);
template<bool LFO_On>
void RunChannel(int chc, int32 timestamp);
double OutputVolume;
uint8 select; /* Selected channel (0-5) */
uint8 globalbalance; /* Global sound balance */
uint8 lfofreq; /* LFO frequency */
uint8 lfoctrl; /* LFO control */
int32 vol_update_counter;
int32 vol_update_which;
int32 vol_update_vllatch;
bool vol_pending;
psg_channel channel[6];
int32 lastts;
Blip_Buffer *sbuf[2];
Blip_Synth<blip_good_quality, 8192> Synth;
int32 dbtable_volonly[32];
int32 dbtable[32][32];
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,211 @@
#ifndef _PCE_VDC_H
#define _PCE_VDC_H
namespace PCE_Fast
{
#define REGSETP(_reg, _data, _msb) { _reg &= 0xFF << ((_msb) ? 0 : 8); _reg |= (_data) << ((_msb) ? 8 : 0); }
#define REGGETP(_reg, _msb) ((_reg >> ((_msb) ? 8 : 0)) & 0xFF)
#define VDC_DEBUG(x)
//printf("%s: %d\n", x, vdc->display_counter);
#define VDC_UNDEFINED(x) { }
//{ printf("%s: %d\n", x, vdc->display_counter); }
static const uint8 vram_inc_tab[4] = { 1, 32, 64, 128 };
typedef struct
{
uint8 priority[2];
uint16 winwidths[2];
uint8 st_mode;
} vpc_t;
extern vpc_t vpc;
static const int VRAM_Size = 0x8000;
static const int VRAM_SizeMask = VRAM_Size - 1; //0x7FFF;
static const int VRAM_BGTileNoMask = VRAM_SizeMask / 16; //0x7FF;
typedef struct
{
uint8 CR;
bool lc263; // 263 line count if set, 262 if not
bool bw; // Black and White
uint8 dot_clock; // Dot Clock(5, 7, or 10 MHz = 0, 1, 2)
uint16 color_table[0x200];
uint32 color_table_cache[0x200];
uint16 ctaddress;
} vce_t;
extern vce_t vce;
typedef struct
{
int16 y;
uint16 height;
uint16 x;
uint16 no;
uint16 flags;
bool cgmode;
} SAT_Cache_t;
typedef struct
{
uint32 display_counter;
int32 sat_dma_slcounter;
uint8 select;
uint16 MAWR; // Memory Address Write Register
uint16 MARR; // Memory Address Read Register
uint16 CR; // Control Register
uint16 RCR; // Raster Compare Register
uint16 BXR; // Background X-Scroll Register
uint16 BYR; // Background Y-Scroll Register
uint16 MWR; // Memory Width Register
uint16 HSR; // Horizontal Sync Register
uint16 HDR; // Horizontal Display Register
uint16 VSR;
uint16 VDR;
uint16 VCR;
uint16 DCR;
uint16 SOUR;
uint16 DESR;
uint16 LENR;
uint16 SATB;
uint32 RCRCount;
uint16 read_buffer;
uint8 write_latch;
uint8 status;
uint16 DMAReadBuffer;
bool DMAReadWrite;
bool DMARunning;
bool SATBPending;
bool burst_mode;
uint32 BG_YOffset;
uint32 BG_XOffset;
int SAT_Cache_Valid; // 64 through 128, depending on the number of 32-pixel-wide sprites.
SAT_Cache_t SAT_Cache[128]; //64];
uint16 SAT[0x100];
uint16 VRAM[65536]; //VRAM_Size];
uint64 bg_tile_cache[65536][8]; // Tile, y, x
uint8 spr_tile_cache[1024][16][16]; // Tile, y, x
uint8 spr_tile_clean[1024]; //VRAM_Size / 64];
} vdc_t;
extern vdc_t *vdc_chips[2];
extern int VDC_TotalChips;
void VDC_SetPixelFormat(const MDFN_PixelFormat &format) MDFN_COLD;
void VDC_RunFrame(EmulateSpecStruct *espec, bool IsHES);
void VDC_SetLayerEnableMask(uint64 mask);
DECLFW(VDC_Write);
DECLFW(VDC_Write_ST);
DECLFR(VCE_Read);
static INLINE uint8 VDC_Read(unsigned int A, bool SGX)
{
uint8 ret = 0;
int msb = A & 1;
int chip = 0;
vdc_t *vdc;
if(SGX)
{
A &= 0x1F;
switch(A)
{
case 0x8: return(vpc.priority[0]);
case 0x9: return(vpc.priority[1]);
case 0xA: return(vpc.winwidths[0]);
case 0xB: return(vpc.winwidths[0] >> 8);
case 0xC: return(vpc.winwidths[1]);
case 0xD: return(vpc.winwidths[1] >> 8);
case 0xE: return(0);
}
if(A & 0x8) return(0);
chip = (A & 0x10) >> 4;
vdc = vdc_chips[chip];
A &= 0x3;
}
else
{
vdc = vdc_chips[0];
A &= 0x3;
}
switch(A)
{
case 0x0: ret = vdc->status;
vdc->status &= ~0x3F;
if(SGX)
{
if(!(vdc_chips[0]->status & 0x3F) && !(vdc_chips[1]->status & 0x3F))
HuC6280_IRQEnd(MDFN_IQIRQ1);
}
else
HuC6280_IRQEnd(MDFN_IQIRQ1); // Clear VDC IRQ line
break;
case 0x2:
case 0x3:
ret = REGGETP(vdc->read_buffer, msb);
if(vdc->select == 0x2) // VRR - VRAM Read Register
{
if(msb)
{
vdc->MARR += vram_inc_tab[(vdc->CR >> 11) & 0x3];
if(vdc->MARR >= VRAM_Size)
VDC_UNDEFINED("Unmapped VRAM VRR read");
vdc->read_buffer = vdc->VRAM[vdc->MARR & VRAM_SizeMask];
}
}
break;
}
//if(HuCPU.isopread && (A == 1 || A == 3)) //(A == 2 || A == 3)) // && A == 1)
if(A == 1)
{
//if(vdc->display_counter >= (VDS + VSW) && vdc->display_counter < (VDS + VSW + VDW + 1) && vce.dot_clock > 0)
if(vce.dot_clock > 0)
ret = 0x40;
//printf("%d %d %02x\n", vdc->display_counter, vce.dot_clock, ret);
//ret = 0x40;
}
return(ret);
}
DECLFW(VCE_Write);
void VDC_Init(int sgx) MDFN_COLD;
void VDC_Close(void) MDFN_COLD;
void VDC_Reset(void) MDFN_COLD;
void VDC_Power(void) MDFN_COLD;
int VDC_StateAction(StateMem *sm, int load, int data_only);
};
#endif

View File

@ -0,0 +1,35 @@
uint32 vdc2_pixel, vdc1_pixel;
vdc2_pixel = vdc1_pixel = vce.color_table_cache[0];
if(pb & 1)
vdc1_pixel = lb0[x];
if(pb & 2)
vdc2_pixel = lb1[x];
/* Dai MakaiMura uses setting 1, and expects VDC #2 sprites in front of VDC #1 background, but
behind VDC #1's sprites.
*/
switch(pb >> 2)
{
case 1:
//if((vdc2_pixel & (amask << 2)) && !(vdc1_pixel & (amask << 2)))
// vdc1_pixel |= amask;
vdc1_pixel |= (((vdc2_pixel ^ vdc1_pixel) & vdc2_pixel) >> 2) & amask;
break;
case 2:
//if((vdc1_pixel & (amask << 2)) && !(vdc2_pixel & (amask << 2)) && !(vdc2_pixel & amask))
// vdc1_pixel |= amask;
puts("MOO");
// TODO: Verify that this is correct logic.
{
const uint32 intermediate = ((vdc1_pixel ^ vdc2_pixel) & vdc1_pixel) >> 2;
vdc1_pixel |= (intermediate ^ vdc2_pixel) & intermediate & amask;
}
break;
}
target[x] = (vdc1_pixel & amask) ? vdc2_pixel : vdc1_pixel;

View File

@ -69,14 +69,26 @@ void MDFN_Surface::Init(void *const p_pixels, const uint32 p_width, const uint32
pixels16 = NULL;
pixels = NULL;
#if defined(WANT_8BPP)
palette = NULL;
#endif
if(!(rpix = calloc(1, p_pitchinpix * p_height * (nf.bpp / 8))))
throw(1);
if(nf.bpp == 16)
#if defined(WANT_8BPP)
//if(nf.bpp == 8)
{
pixels8 = (uint8 *)rpix;
palette = (MDFN_PaletteEntry*)calloc(sizeof(MDFN_PaletteEntry), 256);
}
#elif defined(WANT_16BPP)
//if(nf.bpp == 16)
pixels16 = (uint16 *)rpix;
else
#elif defined(WANT_32BPP)
//else
pixels = (uint32 *)rpix;
#endif
w = p_width;
h = p_height;
@ -94,9 +106,17 @@ void MDFN_Surface::SetFormat(const MDFN_PixelFormat &nf, bool convert)
MDFN_Surface::~MDFN_Surface()
{
if(pixels)
free(pixels);
#if defined(WANT_16BPP)
if(pixels16)
free(pixels16);
#elif defined(WANT_32BPP)
if(pixels)
free(pixels);
#elif defined(WANT_8BPP)
pixels8 = NULL;
if(palette)
free(palette);
palette = NULL;
#endif
}

View File

@ -33,6 +33,11 @@
#define MAKECOLOR(r, g, b, a) (((r >> RED_EXPAND) << RED_SHIFT) | ((g >> GREEN_EXPAND) << GREEN_SHIFT) | ((b >> BLUE_EXPAND) << BLUE_SHIFT))
#endif
struct MDFN_PaletteEntry
{
uint8 r, g, b;
};
typedef struct
{
int32 x, y, w, h;
@ -126,6 +131,8 @@ class MDFN_Surface //typedef struct
int32 pitchinpix; // New name, new code should use this.
};
MDFN_PaletteEntry *palette;
MDFN_PixelFormat format;
void SetFormat(const MDFN_PixelFormat &new_format, bool convert);

View File

@ -0,0 +1,86 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifdef WANT_CRC32
static const unsigned long crc_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};
#define DO1_CRC32(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
#define DO2_CRC32(buf) DO1_CRC32(buf); DO1_CRC32(buf);
#define DO4_CRC32(buf) DO2_CRC32(buf); DO2_CRC32(buf);
#define DO8_CRC32(buf) DO4_CRC32(buf); DO4_CRC32(buf);
unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned int len)
{
if (buf == 0) return 0L;
crc = crc ^ 0xffffffffL;
while (len >= 8)
{
DO8_CRC32(buf);
len -= 8;
}
if (len) do {
DO1_CRC32(buf);
} while (--len);
return crc ^ 0xffffffffL;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -5,84 +5,7 @@
extern "C" {
#endif
#ifdef WANT_CRC32
static const unsigned long crc_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};
#define DO1_CRC32(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
#define DO2_CRC32(buf) DO1_CRC32(buf); DO1_CRC32(buf);
#define DO4_CRC32(buf) DO2_CRC32(buf); DO2_CRC32(buf);
#define DO8_CRC32(buf) DO4_CRC32(buf); DO4_CRC32(buf);
static unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned int len)
{
if (buf == 0) return 0L;
crc = crc ^ 0xffffffffL;
while (len >= 8)
{
DO8_CRC32(buf);
len -= 8;
}
if (len) do {
DO1_CRC32(buf);
} while (--len);
return crc ^ 0xffffffffL;
}
#endif
unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned int len);
#ifdef __cplusplus
}

View File

@ -92,6 +92,11 @@ void MDFND_Message(const char *str)
void MDFND_MidSync(const EmulateSpecStruct *)
{}
void MDFN_MidLineUpdate(EmulateSpecStruct *espec, int y)
{
//MDFND_MidLineUpdate(espec, y);
}
void MDFND_PrintError(const char* err)
{
if (log_cb)