Update to Mednafen 0.9.26 - psx core

This commit is contained in:
twinaphex 2012-10-20 08:54:50 +02:00
parent fcf2d96753
commit d09d20f300
85 changed files with 54545 additions and 2829 deletions

View File

@ -140,7 +140,7 @@ WARNINGS := -Wall \
-Wno-overflow
FLAGS += $(ENDIANNESS_DEFINES) -DSIZEOF_DOUBLE=8 $(WARNINGS) \
-DMEDNAFEN_VERSION=\"0.9.25\" -DPACKAGE=\"mednafen\" -DMEDNAFEN_VERSION_NUMERIC=925 -DPSS_STYLE=1 -DMPC_FIXED_POINT -DARCH_X86 -DWANT_PSX_EMU -DSTDC_HEADERS -D__STDC_LIMIT_MACROS -D__LIBRETRO__ -DNDEBUG
-DMEDNAFEN_VERSION=\"0.9.26\" -DPACKAGE=\"mednafen\" -DMEDNAFEN_VERSION_NUMERIC=926 -DPSS_STYLE=1 -DMPC_FIXED_POINT -DARCH_X86 -DWANT_PSX_EMU -DSTDC_HEADERS -D__STDC_LIMIT_MACROS -D__LIBRETRO__ -DNDEBUG
CXXFLAGS += $(FLAGS)
CFLAGS += $(FLAGS) -std=gnu99

View File

@ -332,7 +332,7 @@ void retro_get_system_info(struct retro_system_info *info)
{
memset(info, 0, sizeof(*info));
info->library_name = "Mednafen PSX";
info->library_version = "0.9.25";
info->library_version = "0.9.26";
info->need_fullpath = true;
info->valid_extensions = "cue|CUE";
}

View File

@ -1,9 +0,0 @@
DEFS = @DEFS@ @CFLAG_VISIBILITY@
noinst_LIBRARIES = libmpcdec.a
libmpcdec_a_SOURCES = huffman.c mpc_decoder.c mpc_reader.c \
requant.c streaminfo.c synth_filter.c mpc_bits_reader.c mpc_demux.c \
mpc_bits_reader.h huffman.h decoder.h internal.h requant.h mpcdec_math.h \
crc32.c huffman-bcl.c

View File

@ -1,609 +0,0 @@
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@
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/mpcdec
DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
AUTHORS COPYING ChangeLog
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_$(V))
am__v_AR_ = $(am__v_AR_$(AM_DEFAULT_VERBOSITY))
am__v_AR_0 = @echo " AR " $@;
AM_V_at = $(am__v_at_$(V))
am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
am__v_at_0 = @
libmpcdec_a_AR = $(AR) $(ARFLAGS)
libmpcdec_a_LIBADD =
am_libmpcdec_a_OBJECTS = huffman.$(OBJEXT) mpc_decoder.$(OBJEXT) \
mpc_reader.$(OBJEXT) requant.$(OBJEXT) streaminfo.$(OBJEXT) \
synth_filter.$(OBJEXT) mpc_bits_reader.$(OBJEXT) \
mpc_demux.$(OBJEXT) crc32.$(OBJEXT) huffman-bcl.$(OBJEXT)
libmpcdec_a_OBJECTS = $(am_libmpcdec_a_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
AM_V_lt = $(am__v_lt_$(V))
am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
am__v_lt_0 = --silent
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_$(V))
am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
am__v_CC_0 = @echo " CC " $@;
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_$(V))
am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
am__v_CCLD_0 = @echo " CCLD " $@;
AM_V_GEN = $(am__v_GEN_$(V))
am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
am__v_GEN_0 = @echo " GEN " $@;
SOURCES = $(libmpcdec_a_SOURCES)
DIST_SOURCES = $(libmpcdec_a_SOURCES)
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 = @DEFS@ @CFLAG_VISIBILITY@
DEPDIR = @DEPDIR@
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@
MATH_OPTIMIZER_FLAGS = @MATH_OPTIMIZER_FLAGS@
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@
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@
XMKMF = @XMKMF@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
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@
lt_ECHO = @lt_ECHO@
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@
noinst_LIBRARIES = libmpcdec.a
libmpcdec_a_SOURCES = huffman.c mpc_decoder.c mpc_reader.c \
requant.c streaminfo.c synth_filter.c mpc_bits_reader.c mpc_demux.c \
mpc_bits_reader.h huffman.h decoder.h internal.h requant.h mpcdec_math.h \
crc32.c huffman-bcl.c
all: all-am
.SUFFIXES:
.SUFFIXES: .c .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/mpcdec/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/mpcdec/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)
libmpcdec.a: $(libmpcdec_a_OBJECTS) $(libmpcdec_a_DEPENDENCIES)
$(AM_V_at)-rm -f libmpcdec.a
$(AM_V_AR)$(libmpcdec_a_AR) libmpcdec.a $(libmpcdec_a_OBJECTS) $(libmpcdec_a_LIBADD)
$(AM_V_at)$(RANLIB) libmpcdec.a
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc32.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/huffman-bcl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/huffman.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpc_bits_reader.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpc_decoder.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpc_demux.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpc_reader.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/requant.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/streaminfo.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/synth_filter.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LTCOMPILE) -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:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
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:

3
mednafen/psx-0925/NOTES Normal file
View File

@ -0,0 +1,3 @@
Capcom games(MMX4, MMX5, etc) - Sensitive about CD access and XA timing(XA playback problems).
Viewpoint - Extra-sensitive about GPU LL DMA timing? (It was generating exceptions for some timings...)

View File

@ -0,0 +1,51 @@
Soul Reaver - Legacy of Kain has CD load time pauses where it probably shouldn't.
Battle Arena Toshinden, Final Fantasy 7 have some kind of GPU timing issues.
Zero Divide runs too fast(related to CPU emulation speed?).
Chrono Cross has several-second freezes during some large special attack/magic sequences.
Tiny Toon Adventures - Plucky's Big Adventure is failing and BREAK'ing for some reason, maybe memcard related.
Shadow Master has broken startup images.
Crusaders of Might and Magic - The CD-XA buffering increase for ToD II is apparently exacerbating the early voice cutoff problem in this game.
Crash Team Racing - Noticed a game lockup once in the arcade mode stage select screen, having trouble reproducing it.
Misadventures of Trone Bonne - Voice problems, lockup, possibly due to excessively long seek delays?
Dance Dance Revolution - The music is...totally wonky.
Medal of Honor - Sound issues.
Fuuraiki - Hangs at black screen when trying to start a new game.
Test time delta between GPU LL DMA end and GPU non-busy status for various primitive types in sequence on a PS1.
Test IRQ and COP0 latencies; PSX IRQ controller latency, software IRQ bit latency, latency of both relevant COP0 IRQ enable bits.
Test IRQ with LWC2.
Test IRQ with COP0 instructions(interrupted execution or not?).
Determine maximum quad height and width. See if drawing is an all-or-nothing thing, or if one triangle of the pair will still be drawn
if it's not too large.
Test 0x0 and 1x1 polygon throughput for all triangle and quad drawing commands.
Fix line drawing algorithm to match test results on the real thing.
Instruction cache emulation(MAYBE).
Test time between voice on and envelope reset; test time between voice on and first ADPCM block memory fetch.
The SPU in the PS1 might sometimes drop voice on events when playing an ADPCM block that loops to itself(and was also the first and only
ADPCM block, at least in the test program I noticed the issue in); investigate further.
Make sure debugger COPn disassembly is correct(no typos or whatnot).

View File

@ -0,0 +1,2 @@
This PSX emulation code is horribly unfinished! Please don't take and use any pieces of it in any other project unless you have
a very good reason to!

38
mednafen/psx-0925/SOURCES Normal file
View File

@ -0,0 +1,38 @@
Sources of helpful information used in PS1 emulation(though some of it, especially older compiled information,
is wrong to some degree or incomplete, but it's still useful):
PCSX(and derivatives/forks)
MAME/MESS
P.E.Op.S
Blade Lib
psxsdk
doomed's PSX documents
bITmASTER's document
Neill Corlett's SPU documents
T.Fujita's SIO documents
ChrlyMac
Exophase
mizvekov
notaz
pSXAuthor
smf(blog)
shalma(forum posts, changelogs)
drhell's site
jac's CD-XA document
"The PlayStation 1 Video (STR) Format" - M. Sabin
Various PS1 emulator compatibility lists(for identifying problematic games)
MIPS RISC Architecture - Gerry Kane (1st and 2nd editions)
MIPS Programmer's Handbook, The
-----------
General(non-PS1-specific) CD/CDROM information and code:
SCSI-3 Multimedia Commands Revision 10A
ECMA-130
cdrdao
dvdisaster

2107
mednafen/psx-0925/cdc.cpp Normal file

File diff suppressed because it is too large Load Diff

311
mednafen/psx-0925/cdc.h Normal file
View File

@ -0,0 +1,311 @@
#ifndef __MDFN_PSX_CDC_H
#define __MDFN_PSX_CDC_H
#include "../cdrom/cdromif.h"
#include "../cdrom/SimpleFIFO.h"
#include "../clamp.h"
namespace MDFN_IEN_PSX
{
struct CD_Audio_Buffer
{
int16 Samples[2][0x1000]; // [0][...] = l, [1][...] = r
int32 Size;
uint32 Freq;
};
class PS_CDC
{
public:
PS_CDC();
~PS_CDC();
void SetDisc(bool tray_open, CDIF *cdif, const char disc_id[4]);
void Power(void);
int StateAction(StateMem *sm, int load, int data_only);
void ResetTS(void);
int32 CalcNextEvent(void); // Returns in master cycles to next event.
pscpu_timestamp_t Update(const pscpu_timestamp_t timestamp);
void Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V);
uint8 Read(const pscpu_timestamp_t timestamp, uint32 A);
bool DMACanRead(void);
uint32 DMARead(void);
INLINE uint32 GetCDAudioFreq(void)
{
if(AudioBuffer_UsedCount && !AudioBuffer_InPrebuffer)
{
const unsigned wb = AudioBuffer_ReadPos >> 12;
return AudioBuffer[wb].Freq;
}
return 0;
}
private:
inline void ApplyVolume(int32 samples[2])
{
int32 left_source = samples[0]; //(int16)MDFN_de16lsb(&buf[i * sizeof(int16) * 2 + 0]);
int32 right_source = samples[1]; //(int16)MDFN_de16lsb(&buf[i * sizeof(int16) * 2 + 2]);
int32 left_out = ((left_source * DecodeVolume[0][0]) >> 7) + ((right_source * DecodeVolume[1][0]) >> 7);
int32 right_out = ((left_source * DecodeVolume[0][1]) >> 7) + ((right_source * DecodeVolume[1][1]) >> 7);
clamp(&left_out, -32768, 32767);
clamp(&right_out, -32768, 32767);
if(Muted)
{
left_out = right_out = 0;
}
samples[0] = left_out;
samples[1] = right_out;
}
public:
INLINE void GetCDAudio(int32 &l, int32 &r)
{
if(AudioBuffer_UsedCount && !AudioBuffer_InPrebuffer)
{
const unsigned wb = AudioBuffer_ReadPos >> 12;
int32 samples[2] = { AudioBuffer[wb].Samples[0][AudioBuffer_ReadPos & 0xFFF], AudioBuffer[wb].Samples[1][AudioBuffer_ReadPos & 0xFFF] };
ApplyVolume(samples);
l = samples[0];
r = samples[1];
AudioBuffer_ReadPos = ((AudioBuffer_ReadPos + 1) & 0xFFF) | (AudioBuffer_ReadPos & ~0xFFF);
if((AudioBuffer_ReadPos & 0xFFF) == (AudioBuffer[wb].Size & 0xFFF))
{
//printf("RP == size; usedcount(predec)= %d, PSRCounter=%d\n", AudioBuffer_UsedCount, PSRCounter);
AudioBuffer_ReadPos = ((((AudioBuffer_ReadPos >> 12) + 1) % AudioBuffer_Count) << 12);
AudioBuffer_UsedCount--;
}
}
}
private:
void SoftReset(void);
CDIF *Cur_CDIF;
bool DiscChanged;
int32 DiscStartupDelay;
enum { AudioBuffer_PreBufferCount = 2 };
enum { AudioBuffer_Count = 4 };
CD_Audio_Buffer AudioBuffer[AudioBuffer_Count];
uint32 AudioBuffer_ReadPos;
uint32 AudioBuffer_WritePos;
uint32 AudioBuffer_UsedCount;
bool AudioBuffer_InPrebuffer;
uint8 Pending_DecodeVolume[2][2], DecodeVolume[2][2]; // [data_source][output_port]
void ClearAudioBuffers(void);
uint8 RegSelector;
uint8 ArgsBuf[16];
uint32 ArgsIn; // 5-bit(0 ... 31)
uint8 ResultsBuffer[16];
uint8 ResultsIn; // 5-bit(0 ... 31)
uint8 ResultsWP; // Write position, 4 bit(0 ... 15).
uint8 ResultsRP; // Read position, 4 bit(0 ... 15).
SimpleFIFO<uint8> DMABuffer;
uint8 SB[2340];
uint32 SB_In;
uint8 SubQBuf[0xC];
uint8 SubQBuf_Safe[0xC];
bool SubQChecksumOK;
bool HeaderBufValid;
uint8 HeaderBuf[12];
void RecalcIRQ(void);
enum
{
CDCIRQ_NONE = 0,
CDCIRQ_DATA_READY = 1,
CDCIRQ_COMPLETE = 2,
CDCIRQ_ACKNOWLEDGE = 3,
CDCIRQ_DATA_END = 4,
CDCIRQ_DISC_ERROR = 5
};
// Names are just guessed for these based on what conditions cause them:
enum
{
ERRCODE_BAD_ARGVAL = 0x10,
ERRCODE_BAD_NUMARGS = 0x20,
ERRCODE_BAD_COMMAND = 0x40,
ERRCODE_NOT_READY = 0x80, // 0x80 (happens with getlocl when drive isn't reading, pause when tray is open, and MAYBE when trying to run an async
// command while another async command is currently in its asynch phase being executed[pause when in readtoc, todo test more])
};
uint8 IRQBuffer;
uint8 IRQOutTestMask;
int32 CDCReadyReceiveCounter; // IRQBuffer being non-zero prevents new results and new IRQ from coming in and erasing the current results,
// but apparently at least one CONFOUNDED game is clearing the IRQ state BEFORE reading the results, so we need to have a delay
// between IRQBuffer being cleared to when we allow new results to come in. (The real thing should be like this too,
// but the mechanism is probably more nuanced and complex and ugly and I like anchovy pizza)
void BeginResults(void);
void WriteIRQ(uint8);
void WriteResult(uint8);
uint8 ReadResult(void);
uint8 FilterFile;
uint8 FilterChan;
uint8 PendingCommand;
bool PendingCommandPhase;
int32 PendingCommandCounter;
int32 SPUCounter;
enum { MODE_SPEED = 0x80 };
enum { MODE_STRSND = 0x40 };
enum { MODE_SIZE = 0x20 };
enum { MODE_SIZE2 = 0x10 };
enum { MODE_SF = 0x08 };
enum { MODE_REPORT = 0x04 };
enum { MODE_AUTOPAUSE = 0x02 };
enum { MODE_CDDA = 0x01 };
uint8 Mode;
enum
{
DS_STANDBY = -2,
DS_PAUSED = -1,
DS_STOPPED = 0,
DS_SEEKING,
DS_SEEKING_LOGICAL,
DS_PLAY_SEEKING,
DS_PLAYING,
DS_READING,
DS_RESETTING
};
int DriveStatus;
int StatusAfterSeek;
bool Forward;
bool Backward;
bool Muted;
int32 PlayTrackMatch;
int32 PSRCounter;
int32 CurSector;
unsigned AsyncIRQPending;
uint8 AsyncResultsPending[16];
uint8 AsyncResultsPendingCount;
int32 CalcSeekTime(int32 initial, int32 target, bool motor_on, bool paused);
void ClearAIP(void);
void CheckAIP(void);
void SetAIP(unsigned irq, unsigned result_count, uint8 *r);
void SetAIP(unsigned irq, uint8 result0);
void SetAIP(unsigned irq, uint8 result0, uint8 result1);
int32 SeekTarget;
pscpu_timestamp_t lastts;
CDUtility::TOC toc;
bool IsPSXDisc;
uint8 DiscID[4];
int32 CommandLoc;
bool CommandLoc_Dirty;
uint8 MakeStatus(bool cmd_error = false);
bool DecodeSubQ(uint8 *subpw);
bool CommandCheckDiscPresent(void);
bool XA_Test(const uint8 *sdata);
void XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab);
int16 xa_previous[2][2];
bool xa_cur_set;
uint8 xa_cur_file;
uint8 xa_cur_chan;
struct CDC_CTEntry
{
uint8 args_min;
uint8 args_max;
const char *name;
int32 (PS_CDC::*func)(const int arg_count, const uint8 *args);
int32 (PS_CDC::*func2)(void);
};
void BeginSeek(uint32 target);
void PreSeekHack(uint32 target);
void ReadBase(void);
static CDC_CTEntry Commands[0x20];
int32 Command_Sync(const int arg_count, const uint8 *args);
int32 Command_Nop(const int arg_count, const uint8 *args);
int32 Command_Setloc(const int arg_count, const uint8 *args);
int32 Command_Play(const int arg_count, const uint8 *args);
int32 Command_Forward(const int arg_count, const uint8 *args);
int32 Command_Backward(const int arg_count, const uint8 *args);
int32 Command_ReadN(const int arg_count, const uint8 *args);
int32 Command_Standby(const int arg_count, const uint8 *args);
int32 Command_Standby_Part2(void);
int32 Command_Stop(const int arg_count, const uint8 *args);
int32 Command_Stop_Part2(void);
int32 Command_Pause(const int arg_count, const uint8 *args);
int32 Command_Pause_Part2(void);
int32 Command_Reset(const int arg_count, const uint8 *args);
int32 Command_Mute(const int arg_count, const uint8 *args);
int32 Command_Demute(const int arg_count, const uint8 *args);
int32 Command_Setfilter(const int arg_count, const uint8 *args);
int32 Command_Setmode(const int arg_count, const uint8 *args);
int32 Command_Getparam(const int arg_count, const uint8 *args);
int32 Command_GetlocL(const int arg_count, const uint8 *args);
int32 Command_GetlocP(const int arg_count, const uint8 *args);
int32 Command_ReadT(const int arg_count, const uint8 *args);
int32 Command_ReadT_Part2(void);
int32 Command_GetTN(const int arg_count, const uint8 *args);
int32 Command_GetTD(const int arg_count, const uint8 *args);
int32 Command_SeekL(const int arg_count, const uint8 *args);
int32 Command_SeekP(const int arg_count, const uint8 *args);
int32 Command_Seek_PartN(void);
int32 Command_Test(const int arg_count, const uint8 *args);
int32 Command_ID(const int arg_count, const uint8 *args);
int32 Command_ID_Part2(void);
int32 Command_ReadS(const int arg_count, const uint8 *args);
int32 Command_Init(const int arg_count, const uint8 *args);
int32 Command_ReadTOC(const int arg_count, const uint8 *args);
int32 Command_ReadTOC_Part2(void);
int32 Command_0x1d(const int arg_count, const uint8 *args);
};
}
#endif

1942
mednafen/psx-0925/cpu.cpp Normal file

File diff suppressed because it is too large Load Diff

167
mednafen/psx-0925/cpu.h Normal file
View File

@ -0,0 +1,167 @@
#ifndef __MDFN_PSX_CPU_H
#define __MDFN_PSX_CPU_H
#include "gte.h"
namespace MDFN_IEN_PSX
{
class PS_CPU
{
public:
PS_CPU();
~PS_CPU();
// FAST_MAP_* enums are in BYTES(8-bit), not in 32-bit units("words" in MIPS context), but the sizes
// will always be multiples of 4.
enum { FAST_MAP_SHIFT = 16 };
enum { FAST_MAP_PSIZE = 1 << FAST_MAP_SHIFT };
void SetFastMap(void *region_mem, uint32 region_address, uint32 region_size);
INLINE void SetEventNT(const pscpu_timestamp_t next_event_ts_arg)
{
next_event_ts = next_event_ts_arg;
}
pscpu_timestamp_t Run(pscpu_timestamp_t timestamp_in, bool ILHMode);
void Power(void);
// which ranges 0-5, inclusive
void AssertIRQ(int which, bool asserted);
void SetHalt(bool status);
int StateAction(StateMem *sm, int load, int data_only);
private:
struct
{
uint32 GPR[32];
uint32 GPR_dummy; // Used in load delay simulation(indexing past the end of GPR)
};
uint32 LO;
uint32 HI;
uint32 BACKED_PC;
uint32 BACKED_new_PC;
uint32 BACKED_new_PC_mask;
uint32 IPCache;
void RecalcIPCache(void);
bool Halted;
uint32 BACKED_LDWhich;
uint32 BACKED_LDValue;
pscpu_timestamp_t next_event_ts;
pscpu_timestamp_t gte_ts_done;
uint8 *FastMap[1 << (32 - FAST_MAP_SHIFT)];
uint8 DummyPage[FAST_MAP_PSIZE];
enum
{
CP0REG_BPC = 3, // PC breakpoint address.
CP0REG_BDA = 5, // Data load/store breakpoint address.
CP0REG_TAR = 6, // Target address(???)
CP0REG_DCIC = 7, // Cache control
CP0REG_BDAM = 9, // Data load/store address mask.
CP0REG_BPCM = 11, // PC breakpoint address mask.
CP0REG_SR = 12,
CP0REG_CAUSE = 13,
CP0REG_EPC = 14,
CP0REG_PRID = 15, // Product ID
CP0REG_ERREG = 16
};
struct
{
union
{
uint32 Regs[32];
struct
{
uint32 Unused00;
uint32 Unused01;
uint32 Unused02;
uint32 BPC; // RW
uint32 Unused04;
uint32 BDA; // RW
uint32 TAR;
uint32 DCIC; // RW
uint32 Unused08;
uint32 BDAM; // R/W
uint32 Unused0A;
uint32 BPCM; // R/W
uint32 SR; // R/W
uint32 CAUSE; // R/W(partial)
uint32 EPC; // R
uint32 PRID; // R
uint32 ERREG; // ?(may not exist, test)
};
};
} CP0;
//PS_GTE GTE;
enum
{
EXCEPTION_INT = 0,
EXCEPTION_MOD = 1,
EXCEPTION_TLBL = 2,
EXCEPTION_TLBS = 3,
EXCEPTION_ADEL = 4, // Address error on load
EXCEPTION_ADES = 5, // Address error on store
EXCEPTION_IBE = 6, // Instruction bus error
EXCEPTION_DBE = 7, // Data bus error
EXCEPTION_SYSCALL = 8, // System call
EXCEPTION_BP = 9, // Breakpoint
EXCEPTION_RI = 10, // Reserved instruction
EXCEPTION_COPU = 11, // Coprocessor unusable
EXCEPTION_OV = 12 // Arithmetic overflow
};
uint32 Exception(uint32 code, uint32 PC, const uint32 NPM) MDFN_WARN_UNUSED_RESULT;
template<bool DebugMode, bool ILHMode> pscpu_timestamp_t RunReal(pscpu_timestamp_t timestamp_in);
template<typename T> T ReadMemory(pscpu_timestamp_t &timestamp, uint32 address, bool DS24 = false);
template<typename T> void WriteMemory(pscpu_timestamp_t &timestamp, uint32 address, uint32 value, bool DS24 = false);
//
// Mednafen debugger stuff follows:
//
public:
void SetCPUHook(void (*cpuh)(uint32 pc), void (*addbt)(uint32 from, uint32 to, bool exception));
void CheckBreakpoints(void (*callback)(bool write, uint32 address, unsigned int len), uint32 instr);
enum
{
GSREG_GPR = 0,
GSREG_PC = 32,
GSREG_PC_NEXT,
GSREG_IN_BD_SLOT,
GSREG_LO,
GSREG_HI,
GSREG_SR,
GSREG_CAUSE,
GSREG_EPC,
};
uint32 GetRegister(unsigned int which, char *special, const uint32 special_len);
void SetRegister(unsigned int which, uint32 value);
private:
void (*CPUHook)(uint32 pc);
void (*ADDBT)(uint32 from, uint32 to, bool exception);
};
}
#endif

669
mednafen/psx-0925/debug.cpp Normal file
View File

@ -0,0 +1,669 @@
/* 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 "psx.h"
#include "timer.h"
#include "cdc.h"
#include "spu.h"
namespace MDFN_IEN_PSX
{
extern PS_GPU *GPU;
extern PS_SPU *SPU;
static void (*CPUHook)(uint32) = NULL;
static void (*BPCallB)(uint32 PC) = NULL;
struct PSX_BPOINT
{
uint32 A[2];
int type;
};
static std::vector<PSX_BPOINT> BreakPointsPC, BreakPointsRead, BreakPointsWrite;
static bool FoundBPoint;
static int BTIndex = 0;
struct BTEntry
{
uint32 from;
uint32 to;
uint32 branch_count;
bool exception;
};
#define NUMBT 24
static BTEntry BTEntries[NUMBT];
void DBG_Break(void)
{
FoundBPoint = true;
}
static void AddBranchTrace(uint32 from, uint32 to, bool exception)
{
BTEntry *prevbt = &BTEntries[(BTIndex + NUMBT - 1) % NUMBT];
//if(BTEntries[(BTIndex - 1) & 0xF] == PC) return;
if(prevbt->from == from && prevbt->to == to && prevbt->exception == exception && prevbt->branch_count < 0xFFFFFFFF)
prevbt->branch_count++;
else
{
BTEntries[BTIndex].from = from;
BTEntries[BTIndex].to = to;
BTEntries[BTIndex].exception = exception;
BTEntries[BTIndex].branch_count = 1;
BTIndex = (BTIndex + 1) % NUMBT;
}
}
static std::vector<BranchTraceResult> GetBranchTrace(void)
{
BranchTraceResult tmp;
std::vector<BranchTraceResult> ret;
for(int x = 0; x < NUMBT; x++)
{
const BTEntry *bt = &BTEntries[(x + BTIndex) % NUMBT];
tmp.count = bt->branch_count;
trio_snprintf(tmp.from, sizeof(tmp.from), "%08x", bt->from);
trio_snprintf(tmp.to, sizeof(tmp.to), "%08x", bt->to);
trio_snprintf(tmp.code, sizeof(tmp.code), "%s", bt->exception ? "e" : "");
ret.push_back(tmp);
}
return(ret);
}
void CheckCPUBPCallB(bool write, uint32 address, unsigned int len)
{
std::vector<PSX_BPOINT>::iterator bpit;
std::vector<PSX_BPOINT>::iterator bpit_end;
if(write)
{
bpit = BreakPointsWrite.begin();
bpit_end = BreakPointsWrite.end();
}
else
{
bpit = BreakPointsRead.begin();
bpit_end = BreakPointsRead.end();
}
while(bpit != bpit_end)
{
if(address >= bpit->A[0] && address <= bpit->A[1])
{
FoundBPoint = true;
break;
}
bpit++;
}
}
static void CPUHandler(uint32 PC)
{
std::vector<PSX_BPOINT>::iterator bpit;
if(PC == 0xB0 && CPU->GetRegister(PS_CPU::GSREG_GPR + 9, NULL, 0) == 0x3D)
{
putchar(CPU->GetRegister(PS_CPU::GSREG_GPR + 4, NULL, 0));
//exit(1);
//puts((const char *)&MainRAM[CPU->GetRegister(PS_CPU::GSREG_GPR + 4, NULL, 0) & 0x1FFFFF]);
}
// FIXME/TODO: Call ForceEventUpdates() somewhere
for(bpit = BreakPointsPC.begin(); bpit != BreakPointsPC.end(); bpit++)
{
if(PC >= bpit->A[0] && PC <= bpit->A[1])
{
FoundBPoint = true;
break;
}
}
CPU->CheckBreakpoints(CheckCPUBPCallB, PSX_MemPeek32(PC));
if(FoundBPoint)
{
BPCallB(PC);
FoundBPoint = 0;
}
if(CPUHook)
CPUHook(PC);
}
static void RedoCPUHook(void)
{
const bool HappyTest = BreakPointsPC.size() || BreakPointsRead.size() || BreakPointsWrite.size();
void (*cpuh)(uint32);
cpuh = HappyTest ? CPUHandler : CPUHook;
CPU->SetCPUHook(cpuh, cpuh ? AddBranchTrace : NULL);
}
static void FlushBreakPoints(int type)
{
if(type == BPOINT_READ)
BreakPointsRead.clear();
else if(type == BPOINT_WRITE)
BreakPointsWrite.clear();
else if(type == BPOINT_PC)
BreakPointsPC.clear();
RedoCPUHook();
}
static void AddBreakPoint(int type, unsigned int A1, unsigned int A2, bool logical)
{
PSX_BPOINT tmp;
tmp.A[0] = A1;
tmp.A[1] = A2;
tmp.type = type;
if(type == BPOINT_READ)
BreakPointsRead.push_back(tmp);
else if(type == BPOINT_WRITE)
BreakPointsWrite.push_back(tmp);
else if(type == BPOINT_PC)
BreakPointsPC.push_back(tmp);
RedoCPUHook();
}
static void SetCPUCallback(void (*callb)(uint32 PC))
{
CPUHook = callb;
RedoCPUHook();
}
static void SetBPCallback(void (*callb)(uint32 PC))
{
BPCallB = callb;
}
static void GetAddressSpaceBytes(const char *name, uint32 Address, uint32 Length, uint8 *Buffer)
{
if(!strcmp(name, "cpu"))
{
while(Length--)
{
Address &= 0xFFFFFFFF;
*Buffer = PSX_MemPeek8(Address);
Address++;
Buffer++;
}
}
else if(!strcmp(name, "ram"))
{
while(Length--)
{
Address &= 0x1FFFFF;
*Buffer = PSX_MemPeek8(Address);
Address++;
Buffer++;
}
}
else if(!strcmp(name, "spu"))
{
while(Length--)
{
Address &= 0x7FFFF;
*Buffer = SPU->PeekSPURAM(Address >> 1) >> ((Address & 1) * 8);
Address++;
Buffer++;
}
}
else if(!strcmp(name, "gpu"))
{
while(Length--)
{
Address &= 0xFFFFF;
*Buffer = GPU->PeekRAM(Address >> 1) >> ((Address & 1) * 8);
Address++;
Buffer++;
}
}
}
static void PutAddressSpaceBytes(const char *name, uint32 Address, uint32 Length, uint32 Granularity, bool hl, const uint8 *Buffer)
{
if(!strcmp(name, "cpu"))
{
while(Length--)
{
Address &= 0xFFFFFFFF;
// TODO
PSX_MemWrite8(0, Address, *Buffer);
Address++;
Buffer++;
}
}
else if(!strcmp(name, "gpu"))
{
while(Length--)
{
Address &= 0xFFFFF;
uint16 peeko = GPU->PeekRAM(Address >> 1);
GPU->PokeRAM(Address >> 1, (*Buffer << ((Address & 1) * 8)) | (peeko & (0xFF00 >> ((Address & 1) * 8))) );
Address++;
Buffer++;
}
}
else if(!strcmp(name, "spu"))
{
while(Length--)
{
Address &= 0x7FFFF;
uint16 peeko = SPU->PeekSPURAM(Address >> 1);
SPU->PokeSPURAM(Address >> 1, (*Buffer << ((Address & 1) * 8)) | (peeko & (0xFF00 >> ((Address & 1) * 8))) );
Address++;
Buffer++;
}
}
}
static uint32 MemPeek(uint32 A, unsigned int bsize, bool hl, bool logical)
{
uint32 ret = 0;
for(unsigned int i = 0; i < bsize; i++)
ret |= PSX_MemPeek8(A + i) << (i * 8);
return(ret);
}
static void Disassemble(uint32 &A, uint32 SpecialA, char *TextBuf)
{
assert(!(A & 0x3));
const uint32 instr = PSX_MemPeek32(A);
strncpy(TextBuf, DisassembleMIPS(A, instr).c_str(), 256);
TextBuf[255] = 0;
// trio_snprintf(TextBuf, 256, "0x%08x", instr);
A += 4;
}
static MDFN_Surface *GfxDecode_Buf = NULL;
static int GfxDecode_Line = -1;
static int GfxDecode_Layer = 0;
static int GfxDecode_Scroll = 0;
static int GfxDecode_PBN = 0;
static void DoGfxDecode(void)
{
unsigned tp_w, tp_h;
tp_w = 256;
tp_h = 256;
if(GfxDecode_Buf)
{
for(int sy = 0; sy < GfxDecode_Buf->h; sy++)
{
for(int sx = 0; sx < GfxDecode_Buf->w; sx++)
{
unsigned fb_x = ((sx % GfxDecode_Buf->w) + ((sy + GfxDecode_Scroll) / GfxDecode_Buf->w * GfxDecode_Buf->w)) & 1023;
unsigned fb_y = (((sy + GfxDecode_Scroll) % GfxDecode_Buf->w) + ((((sx % GfxDecode_Buf->w) + ((sy + GfxDecode_Scroll) / GfxDecode_Buf->w * GfxDecode_Buf->w)) / 1024) * 256)) & 511;
uint16 pixel = GPU->PeekRAM(fb_y * 1024 + fb_x);
GfxDecode_Buf->pixels[(sy * GfxDecode_Buf->w * 3) + sx] = GfxDecode_Buf->MakeColor(((pixel >> 0) & 0x1F) * 255 / 31,
((pixel >> 5) & 0x1F) * 255 / 31,
((pixel >> 10) & 0x1F) * 255 / 31, 0xFF);
}
}
}
}
void DBG_GPUScanlineHook(unsigned scanline)
{
if((int)scanline == GfxDecode_Line)
{
DoGfxDecode();
}
}
static void SetGraphicsDecode(MDFN_Surface *surface, int line, int which, int xscroll, int yscroll, int pbn)
{
GfxDecode_Buf = surface;
GfxDecode_Line = line;
GfxDecode_Layer = which;
GfxDecode_Scroll = yscroll;
GfxDecode_PBN = pbn;
if(GfxDecode_Buf && GfxDecode_Line == -1)
DoGfxDecode();
}
DebuggerInfoStruct PSX_DBGInfo =
{
"shift_jis",
4, // Max instruction byte size
4, // Instruction alignment(bytes)
32, // Logical address bits
32, // Physical address bits
0x00000000, // Default watch addr
~0U, // ZP addr
MemPeek,
Disassemble,
NULL,
NULL, //ForceIRQ,
NULL, //NESDBG_GetVector,
FlushBreakPoints,
AddBreakPoint,
SetCPUCallback,
SetBPCallback,
GetBranchTrace,
SetGraphicsDecode,
NULL, //PCFXDBG_SetLogFunc,
};
static RegType Regs_Misc[] =
{
{ TIMER_GSREG_COUNTER0, "COUNTER0", "Counter 0", 2 },
{ TIMER_GSREG_MODE0, "MODE0", "Mode 0", 2 },
{ TIMER_GSREG_TARGET0, "TARGET0", "Target 0", 2 },
{ 0, "------", "", 0xFFFF },
{ TIMER_GSREG_COUNTER1, "COUNTER1", "Counter 1", 2 },
{ TIMER_GSREG_MODE1, "MODE1", "Mode 1", 2 },
{ TIMER_GSREG_TARGET1, "TARGET1", "Target 1", 2 },
{ 0, "------", "", 0xFFFF },
{ TIMER_GSREG_COUNTER2, "COUNTER2", "Counter 2", 2 },
{ TIMER_GSREG_MODE2, "MODE2", "Mode 2", 2 },
{ TIMER_GSREG_TARGET2, "TARGET2", "Target 2", 2 },
{ 0, "------", "", 0xFFFF },
{ 0, "------", "", 0xFFFF },
{ 0x10000 | IRQ_GSREG_ASSERTED, "ASSERTED", "IRQ Asserted", 2 },
{ 0x10000 | IRQ_GSREG_STATUS, "STATUS", "IRQ Status", 2 },
{ 0x10000 | IRQ_GSREG_MASK, "MASK", "IRQ Mask", 2 },
{ 0, "", "", 0 }
};
static uint32 GetRegister_Misc(const unsigned int id, char *special, const uint32 special_len)
{
if(id & 0x10000)
return(IRQ_GetRegister(id & 0xFFFF, special, special_len));
else
return(TIMER_GetRegister(id & 0xFFFF, special, special_len));
}
static void SetRegister_Misc(const unsigned int id, uint32 value)
{
if(id & 0x10000)
IRQ_SetRegister(id & 0xFFFF, value);
else
TIMER_SetRegister(id & 0xFFFF, value);
}
static RegGroupType MiscRegsGroup =
{
NULL,
Regs_Misc,
GetRegister_Misc,
SetRegister_Misc
};
static RegType Regs_SPU[] =
{
{ PS_SPU::GSREG_SPUCONTROL, "SPUCTRL", "SPU Control", 2 },
{ PS_SPU::GSREG_FM_ON, "FMOn", "FM Enable", 3 },
{ PS_SPU::GSREG_NOISE_ON, "NoiseOn", "Noise Enable", 3 },
{ PS_SPU::GSREG_REVERB_ON, "ReverbOn", "Reverb Enable", 3 },
{ PS_SPU::GSREG_CDVOL_L, "CDVolL", "CD Volume Left", 2 },
{ PS_SPU::GSREG_CDVOL_R, "CDVolR", "CD Volume Right", 2 },
{ PS_SPU::GSREG_DRYVOL_CTRL_L, "DryVolCL", "Dry Volume Control Left", 2 },
{ PS_SPU::GSREG_DRYVOL_CTRL_R, "DryVolCR", "Dry Volume Control Right", 2 },
{ PS_SPU::GSREG_DRYVOL_L, "DryVolL", "Dry Volume Left", 2 },
{ PS_SPU::GSREG_DRYVOL_R, "DryVolR", "Dry Volume Right", 2 },
{ PS_SPU::GSREG_WETVOL_L, "WetVolL", "Wet Volume Left", 2 },
{ PS_SPU::GSREG_WETVOL_R, "WetVolR", "Wet Volume Right", 2 },
{ PS_SPU::GSREG_RWADDR, "RWAddr", "SPURAM Read/Write Address", 3 },
{ PS_SPU::GSREG_IRQADDR, "IRQAddr", "IRQ Compare Address", 3 },
{ PS_SPU::GSREG_REVERBWA, "ReverbWA", "Reverb Work Area(Raw)", 2 },
{ PS_SPU::GSREG_VOICEON, "VoiceOn", "Voice On", 3 },
{ PS_SPU::GSREG_VOICEOFF, "VoiceOff", "Voice Off", 3 },
{ PS_SPU::GSREG_BLOCKEND, "BlockEnd", "Block End", 3 },
{ 0, "------", "", 0xFFFF },
{ PS_SPU::GSREG_FB_SRC_A, "FB_SRC_A", "", 2 },
{ PS_SPU::GSREG_FB_SRC_B, "FB_SRC_B", "", 2 },
{ PS_SPU::GSREG_IIR_ALPHA, "IIR_ALPHA", "", 2 },
{ PS_SPU::GSREG_ACC_COEF_A, "ACC_COEF_A", "", 2 },
{ PS_SPU::GSREG_ACC_COEF_B, "ACC_COEF_B", "", 2 },
{ PS_SPU::GSREG_ACC_COEF_C, "ACC_COEF_C", "", 2 },
{ PS_SPU::GSREG_ACC_COEF_D, "ACC_COEF_D", "", 2 },
{ PS_SPU::GSREG_IIR_COEF, "IIR_COEF", "", 2 },
{ PS_SPU::GSREG_FB_ALPHA, "FB_ALPHA", "", 2 },
{ PS_SPU::GSREG_FB_X, "FB_X", "", 2 },
{ PS_SPU::GSREG_IIR_DEST_A0, "IIR_DEST_A0", "", 2 },
{ PS_SPU::GSREG_IIR_DEST_A1, "IIR_DEST_A1", "", 2 },
{ PS_SPU::GSREG_ACC_SRC_A0, "ACC_SRC_A0", "", 2 },
{ PS_SPU::GSREG_ACC_SRC_A1, "ACC_SRC_A1", "", 2 },
{ PS_SPU::GSREG_ACC_SRC_B0, "ACC_SRC_B0", "", 2 },
{ PS_SPU::GSREG_ACC_SRC_B1, "ACC_SRC_B1", "", 2 },
{ PS_SPU::GSREG_IIR_SRC_A0, "IIR_SRC_A0", "", 2 },
{ PS_SPU::GSREG_IIR_SRC_A1, "IIR_SRC_A1", "", 2 },
{ PS_SPU::GSREG_IIR_DEST_B0, "IIR_DEST_B0", "", 2 },
{ PS_SPU::GSREG_IIR_DEST_B1, "IIR_DEST_B1", "", 2 },
{ PS_SPU::GSREG_ACC_SRC_C0, "ACC_SRC_C0", "", 2 },
{ PS_SPU::GSREG_ACC_SRC_C1, "ACC_SRC_C1", "", 2 },
{ PS_SPU::GSREG_ACC_SRC_D0, "ACC_SRC_D0", "", 2 },
{ PS_SPU::GSREG_ACC_SRC_D1, "ACC_SRC_D1", "", 2 },
{ PS_SPU::GSREG_IIR_SRC_B1, "IIR_SRC_B1", "", 2 },
{ PS_SPU::GSREG_IIR_SRC_B0, "IIR_SRC_B0", "", 2 },
{ PS_SPU::GSREG_MIX_DEST_A0, "MIX_DEST_A0", "", 2 },
{ PS_SPU::GSREG_MIX_DEST_A1, "MIX_DEST_A1", "", 2 },
{ PS_SPU::GSREG_MIX_DEST_B0, "MIX_DEST_B0", "", 2 },
{ PS_SPU::GSREG_MIX_DEST_B1, "MIX_DEST_B1", "", 2 },
{ PS_SPU::GSREG_IN_COEF_L, "IN_COEF_L", "", 2 },
{ PS_SPU::GSREG_IN_COEF_R, "IN_COEF_R", "", 2 },
{ 0, "", "", 0 },
};
#define VOICE_HELPER(v) \
{ 0, "--V"#v"--", "", 0xFFFF }, \
{ PS_SPU:: GSREG_V0_VOL_CTRL_L + v * 256, "VolCL", "Volume Control Left", 2 }, \
{ PS_SPU:: GSREG_V0_VOL_CTRL_R + v * 256, "VolCR", "Volume Control Right", 2 }, \
{ PS_SPU:: GSREG_V0_VOL_L + v * 256, "VolL", "Volume Left", 2 }, \
{ PS_SPU:: GSREG_V0_VOL_R + v * 256, "VolR", "Volume Right", 2 }, \
{ PS_SPU:: GSREG_V0_PITCH + v * 256, "Pitch", "Pitch", 2 }, \
{ PS_SPU:: GSREG_V0_STARTADDR + v * 256, "SAddr", "Start Address", 3 }, \
{ PS_SPU:: GSREG_V0_ADSR_CTRL + v * 256, "ADSRCTRL", "ADSR Control", 4 }, \
{ PS_SPU:: GSREG_V0_ADSR_LEVEL + v * 256, "ADSRLev", "ADSR Level", 2 }, \
{ PS_SPU:: GSREG_V0_LOOP_ADDR + v * 256, "LAddr", "Loop Address", 3 }, \
{ PS_SPU:: GSREG_V0_READ_ADDR + v * 256, "RAddr", "Read Address", 3 }
static RegType Regs_SPU_Voices[] =
{
#if 1
VOICE_HELPER(0),
VOICE_HELPER(1),
VOICE_HELPER(2),
VOICE_HELPER(3),
#else
VOICE_HELPER(20),
VOICE_HELPER(21),
VOICE_HELPER(22),
VOICE_HELPER(23),
#endif
{ 0, "", "", 0 },
};
static uint32 GetRegister_SPU(const unsigned int id, char *special, const uint32 special_len)
{
return(SPU->GetRegister(id, special, special_len));
}
static void SetRegister_SPU(const unsigned int id, uint32 value)
{
SPU->SetRegister(id, value);
}
static RegGroupType SPURegsGroup =
{
NULL,
Regs_SPU,
GetRegister_SPU,
SetRegister_SPU
};
static RegGroupType SPUVoicesRegsGroup =
{
NULL,
Regs_SPU_Voices,
GetRegister_SPU,
SetRegister_SPU
};
static RegType Regs_CPU[] =
{
{ PS_CPU::GSREG_PC, "PC", "PC", 4 },
{ PS_CPU::GSREG_PC_NEXT, "NPC", "Next PC", 4 },
{ PS_CPU::GSREG_IN_BD_SLOT, "INBD", "In Branch Delay Slot", 1 },
{ 0, "------", "", 0xFFFF },
{ PS_CPU::GSREG_GPR + 1, "at", "Assembler Temporary", 4 },
{ PS_CPU::GSREG_GPR + 2, "v0", "Return Value 0", 4 },
{ PS_CPU::GSREG_GPR + 3, "v1", "Return Value 1", 4 },
{ PS_CPU::GSREG_GPR + 4, "a0", "Argument 0", 4 },
{ PS_CPU::GSREG_GPR + 5, "a1", "Argument 1", 4 },
{ PS_CPU::GSREG_GPR + 6, "a2", "Argument 2", 4 },
{ PS_CPU::GSREG_GPR + 7, "a3", "Argument 3", 4 },
{ PS_CPU::GSREG_GPR + 8, "t0", "Temporary 0", 4 },
{ PS_CPU::GSREG_GPR + 9, "t1", "Temporary 1", 4 },
{ PS_CPU::GSREG_GPR + 10, "t2", "Temporary 2", 4 },
{ PS_CPU::GSREG_GPR + 11, "t3", "Temporary 3", 4 },
{ PS_CPU::GSREG_GPR + 12, "t4", "Temporary 4", 4 },
{ PS_CPU::GSREG_GPR + 13, "t5", "Temporary 5", 4 },
{ PS_CPU::GSREG_GPR + 14, "t6", "Temporary 6", 4 },
{ PS_CPU::GSREG_GPR + 15, "t7", "Temporary 7", 4 },
{ PS_CPU::GSREG_GPR + 16, "s0", "Subroutine Reg Var 0", 4 },
{ PS_CPU::GSREG_GPR + 17, "s1", "Subroutine Reg Var 1", 4 },
{ PS_CPU::GSREG_GPR + 18, "s2", "Subroutine Reg Var 2", 4 },
{ PS_CPU::GSREG_GPR + 19, "s3", "Subroutine Reg Var 3", 4 },
{ PS_CPU::GSREG_GPR + 20, "s4", "Subroutine Reg Var 4", 4 },
{ PS_CPU::GSREG_GPR + 21, "s5", "Subroutine Reg Var 5", 4 },
{ PS_CPU::GSREG_GPR + 22, "s6", "Subroutine Reg Var 6", 4 },
{ PS_CPU::GSREG_GPR + 23, "s7", "Subroutine Reg Var 7", 4 },
{ PS_CPU::GSREG_GPR + 24, "t8", "Temporary 8", 4 },
{ PS_CPU::GSREG_GPR + 25, "t9", "Temporary 9", 4 },
{ PS_CPU::GSREG_GPR + 26, "k0", "Interrupt/Trap Handler Reg 0", 4 },
{ PS_CPU::GSREG_GPR + 27, "k1", "Interrupt/Trap Handler Reg 1", 4 },
{ PS_CPU::GSREG_GPR + 28, "gp", "Global Pointer", 4 },
{ PS_CPU::GSREG_GPR + 29, "sp", "Stack Pointer", 4 },
{ PS_CPU::GSREG_GPR + 30, "s8", "Subroutine Reg Var 8/Frame Pointer", 4 },
{ PS_CPU::GSREG_GPR + 31, "ra", "Return Address", 4 },
{ 0, "------", "", 0xFFFF },
{ PS_CPU::GSREG_SR, "SR", "Status Register", 4 },
{ PS_CPU::GSREG_CAUSE, "CAU","Cause Register", 4 },
{ PS_CPU::GSREG_EPC, "EPC", "EPC Register", 4 },
{ 0, "", "", 0 }
};
static uint32 GetRegister_CPU(const unsigned int id, char *special, const uint32 special_len)
{
return(CPU->GetRegister(id, special, special_len));
}
static void SetRegister_CPU(const unsigned int id, uint32 value)
{
CPU->SetRegister(id, value);
}
static RegGroupType CPURegsGroup =
{
NULL,
Regs_CPU,
GetRegister_CPU,
SetRegister_CPU
};
bool DBG_Init(void)
{
CPUHook = NULL;
BPCallB = NULL;
FoundBPoint = false;
MDFNDBG_AddRegGroup(&CPURegsGroup);
MDFNDBG_AddRegGroup(&MiscRegsGroup);
MDFNDBG_AddRegGroup(&SPURegsGroup);
MDFNDBG_AddRegGroup(&SPUVoicesRegsGroup);
ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "cpu", "CPU Physical", 32);
ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "ram", "CPU Main Ram", 21);
ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "spu", "SPU RAM", 19);
ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "gpu", "GPU RAM", 20);
return(true);
}
}

21
mednafen/psx-0925/debug.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef __MDFN_PSX_DEBUG_H
#define __MDFN_PSX_DEBUG_H
#ifdef WANT_DEBUGGER
namespace MDFN_IEN_PSX
{
extern DebuggerInfoStruct PSX_DBGInfo;
bool DBG_Init(void);
void DBG_Break(void);
void DBG_GPUScanlineHook(unsigned scanline);
}
#endif
#endif

408
mednafen/psx-0925/dis.cpp Normal file
View File

@ -0,0 +1,408 @@
/* 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 "psx.h"
namespace MDFN_IEN_PSX
{
struct OpEntry
{
uint32 mask;
uint32 value;
const char *mnemonic;
const char *format;
};
#define MASK_OP (0x3F << 26)
#define MASK_FUNC (0x3F)
#define MASK_RS (0x1F << 21)
#define MASK_RT (0x1F << 16)
#define MASK_RD (0x1F << 11)
#define MASK_SA (0x1F << 6)
#define MK_OP(mnemonic, format, op, func, extra_mask) { MASK_OP | (op ? 0 : MASK_FUNC) | extra_mask, (op << 26) | func, mnemonic, format }
#define MK_OP_REGIMM(mnemonic, regop) { MASK_OP | MASK_RT, (0x01 << 26) | (regop << 16), mnemonic, "s, p" }
#define MK_COPZ(z) { MASK_OP | (0x1 << 25), (0x1 << 25) | ((0x10 | z) << 26), "cop" #z, "F" }
#define MK_COP0_FUNC(mnemonic, func) { MASK_OP | (0x1 << 25) | MASK_FUNC, (0x10 << 26) | (0x1 << 25) | func, mnemonic, "" }
#define MK_COPZ_XFER(z, mnemonic, format, xf) { MASK_OP | (0x1F << 21), ((0x10 | z) << 26) | (xf << 21), mnemonic, format }
#define MK_GTE(mnemonic, format, func) { MASK_OP | (0x1 << 25) | MASK_FUNC, (0x1 << 25) | (0x12 << 26) | func, mnemonic, format }
static OpEntry ops[] =
{
MK_OP("nop", "", 0, 0, MASK_RT | MASK_RD | MASK_SA),
//
//
//
MK_OP("sll", "d, t, a", 0, 0, 0),
MK_OP("srl", "d, t, a", 0, 2, 0),
MK_OP("sra", "d, t, a", 0, 3, 0),
MK_OP("sllv", "d, t, s", 0, 4, 0),
MK_OP("srlv", "d, t, s", 0, 6, 0),
MK_OP("srav", "d, t, s", 0, 7, 0),
MK_OP("jr", "s", 0, 8, 0),
MK_OP("jalr", "d, s", 0, 9, 0),
MK_OP("syscall", "", 0, 12, 0), // TODO
MK_OP("break", "", 0, 13, 0), // TODO
MK_OP("mfhi", "d", 0, 16, 0),
MK_OP("mthi", "s", 0, 17, 0),
MK_OP("mflo", "d", 0, 18, 0),
MK_OP("mtlo", "s", 0, 19, 0),
MK_OP("mult", "s, t", 0, 24, 0),
MK_OP("multu", "s, t", 0, 25, 0),
MK_OP("div", "s, t", 0, 26, 0),
MK_OP("divu", "s, t", 0, 27, 0),
MK_OP("add", "d, s, t", 0, 32, 0),
MK_OP("addu", "d, s, t", 0, 33, 0),
MK_OP("sub", "d, s, t", 0, 34, 0),
MK_OP("subu", "d, s, t", 0, 35, 0),
MK_OP("and", "d, s, t", 0, 36, 0),
MK_OP("or", "d, s, t", 0, 37, 0),
MK_OP("xor", "d, s, t", 0, 38, 0),
MK_OP("nor", "d, s, t", 0, 39, 0),
MK_OP("slt", "d, s, t", 0, 42, 0),
MK_OP("sltu", "d, s, t", 0, 43, 0),
MK_OP_REGIMM("bgez", 0x01),
MK_OP_REGIMM("bgezal", 0x11),
MK_OP_REGIMM("bltz", 0x00),
MK_OP_REGIMM("bltzal", 0x10),
MK_OP("j", "P", 2, 0, 0),
MK_OP("jal", "P", 3, 0, 0),
MK_OP("beq", "s, t, p", 4, 0, 0),
MK_OP("bne", "s, t, p", 5, 0, 0),
MK_OP("blez", "s, p", 6, 0, 0),
MK_OP("bgtz", "s, p", 7, 0, 0),
MK_OP("addi", "t, s, i", 8, 0, 0),
MK_OP("addiu", "t, s, i", 9, 0, 0),
MK_OP("slti", "t, s, i", 10, 0, 0),
MK_OP("sltiu", "t, s, i", 11, 0, 0),
MK_OP("andi", "t, s, z", 12, 0, 0),
MK_OP("ori", "t, s, z", 13, 0, 0),
MK_OP("xori", "t, s, z", 14, 0, 0),
MK_OP("lui", "t, z", 15, 0, 0),
MK_COPZ_XFER(0, "mfc0", "t, 0", 0x00),
MK_COPZ_XFER(1, "mfc1", "t, ?", 0x00),
MK_COPZ_XFER(2, "mfc2", "t, g", 0x00),
MK_COPZ_XFER(3, "mfc3", "t, ?", 0x00),
MK_COPZ_XFER(0, "mtc0", "t, 0", 0x04),
MK_COPZ_XFER(1, "mtc1", "t, ?", 0x04),
MK_COPZ_XFER(2, "mtc2", "t, g", 0x04),
MK_COPZ_XFER(3, "mtc3", "t, ?", 0x04),
MK_COPZ_XFER(0, "cfc0", "t, ?", 0x02),
MK_COPZ_XFER(1, "cfc1", "t, ?", 0x02),
MK_COPZ_XFER(2, "cfc2", "t, G", 0x02),
MK_COPZ_XFER(3, "cfc3", "t, ?", 0x02),
MK_COPZ_XFER(0, "ctc0", "t, ?", 0x06),
MK_COPZ_XFER(1, "ctc1", "t, ?", 0x06),
MK_COPZ_XFER(2, "ctc2", "t, G", 0x06),
MK_COPZ_XFER(3, "ctc3", "t, ?", 0x06),
// COP0 stuff here
MK_COP0_FUNC("rfe", 0x10),
MK_OP("lwc0", "?, i(s)", 0x30, 0, 0),
MK_OP("lwc1", "?, i(s)", 0x31, 0, 0),
MK_OP("lwc2", "h, i(s)", 0x32, 0, 0),
MK_OP("lwc3", "?, i(s)", 0x33, 0, 0),
MK_OP("swc0", "?, i(s)", 0x38, 0, 0),
MK_OP("swc1", "?, i(s)", 0x39, 0, 0),
MK_OP("swc2", "h, i(s)", 0x3A, 0, 0),
MK_OP("swc3", "?, i(s)", 0x3B, 0, 0),
MK_OP("lb", "t, i(s)", 0x20, 0, 0),
MK_OP("lh", "t, i(s)", 0x21, 0, 0),
MK_OP("lwl", "t, i(s)", 0x22, 0, 0),
MK_OP("lw", "t, i(s)", 0x23, 0, 0),
MK_OP("lbu", "t, i(s)", 0x24, 0, 0),
MK_OP("lhu", "t, i(s)", 0x25, 0, 0),
MK_OP("lwr", "t, i(s)", 0x26, 0, 0),
MK_OP("sb", "t, i(s)", 0x28, 0, 0),
MK_OP("sh", "t, i(s)", 0x29, 0, 0),
MK_OP("swl", "t, i(s)", 0x2A, 0, 0),
MK_OP("sw", "t, i(s)", 0x2B, 0, 0),
MK_OP("swr", "t, i(s)", 0x2E, 0, 0),
//
// GTE specific instructions
//
// sf mx v cv lm
//
MK_GTE("rtps", "#sf# #lm#", 0x00),
MK_GTE("rtps", "#sf# #lm#", 0x01),
MK_GTE("nclip", "", 0x06),
MK_GTE("op", "#sf# #lm#", 0x0C),
MK_GTE("dpcs", "#sf# #lm#", 0x10),
MK_GTE("intpl", "#sf# #lm#", 0x11),
MK_GTE("mvmva", "#sf# #mx# #v# #cv# #lm#", 0x12),
MK_GTE("ncds", "#sf# #lm#", 0x13),
MK_GTE("cdp", "#sf# #lm#", 0x14),
MK_GTE("ncdt", "#sf# #lm#", 0x16),
MK_GTE("dcpl", "#sf# #lm#", 0x1A),
MK_GTE("nccs", "#sf# #lm#", 0x1B),
MK_GTE("cc", "#sf# #lm#", 0x1C),
MK_GTE("ncs", "#sf# #lm#", 0x1E),
MK_GTE("nct", "#sf# #lm#", 0x20),
MK_GTE("sqr", "#sf# #lm#", 0x28),
MK_GTE("dcpl", "#sf# #lm#", 0x29),
MK_GTE("dpct", "#sf# #lm#", 0x2A),
MK_GTE("avsz3", "", 0x2D),
MK_GTE("avsz4", "", 0x2E),
MK_GTE("rtpt", "#sf# #lm#", 0x30),
MK_GTE("gpf", "#sf# #lm#", 0x3D),
MK_GTE("gpl", "#sf# #lm#", 0x3E),
MK_GTE("ncct", "#sf# #lm#", 0x3F),
//
//
//
MK_COPZ(0),
MK_COPZ(1),
MK_COPZ(2),
MK_COPZ(3),
{ 0, 0, NULL, NULL }
};
std::string DisassembleMIPS(uint32 PC, uint32 instr)
{
std::string ret = "UNKNOWN";
unsigned int rs = (instr >> 21) & 0x1F;
unsigned int rt = (instr >> 16) & 0x1F;
unsigned int rd = (instr >> 11) & 0x1F;
unsigned int shamt = (instr >> 6) & 0x1F;
unsigned int immediate = (int32)(int16)(instr & 0xFFFF);
unsigned int immediate_ze = (instr & 0xFFFF);
unsigned int jt = instr & ((1 << 26) - 1);
static const char *gpr_names[32] =
{
"r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
};
static const char *cop0_names[32] =
{
"CPR0", "CPR1", "CPR2", "BPC", "CPR4", "BDA", "TAR", "DCIC", "CPR8", "BDAM", "CPR10", "BPCM", "SR", "CAUSE", "EPC", "PRID",
"ERREG", "CPR17", "CPR18", "CPR19", "CPR20", "CPR21", "CPR22", "CPR23", "CPR24", "CPR25", "CPR26", "CPR27", "CPR28", "CPR29", "CPR30", "CPR31"
};
static const char *gte_cr_names[32] =
{
"R11R12", "R13R21", "R22R23", "R31R32", "R33", "TRX", "TRY", "TRZ", "L11L12", "L13L21", "L22L23", "L31L32", "L33", "RBK", "GBK", "BBK",
"LR1LR2", "LR3LG1", "LG2LG3", "LB1LB2", "LB3", "RFC", "GFC", "BFC", "OFX", "OFY", "H", "DQA", "DQB", "ZSF3", "ZSF4", "FLAG"
};
static const char *gte_dr_names[32] =
{
"VXY0", "VZ0", "VXY1", "VZ1", "VXY2", "VZ2", "RGB", "OTZ", "IR0", "IR1", "IR2", "IR3", "SXY0", "SXY1", "SXY2", "SXYP",
"SZ0", "SZ1", "SZ2", "SZ3", "RGB0", "RGB1", "RGB2", "RES1", "MAC0", "MAC1", "MAC2", "MAC3", "IRGB", "ORGB", "LZCS", "LZCR"
};
OpEntry *op = ops;
while(op->mnemonic)
{
if((instr & op->mask) == op->value)
{
// a = shift amount
// s = rs
// t = rt
// d = rd
// i = immediate
// z = immediate, zero-extended
// p = PC + 4 + immediate
// P = ((PC + 4) & 0xF0000000) | (26bitval << 2)
//
// 0 = rd(cop0 registers)
// c = rd(copz data registers)
// C = rd(copz control registers)
// g = rd(GTE data registers)
// G = rd(GTE control registers)
// h = rt(GTE data registers)
char s_a[16];
char s_i[16];
char s_z[16];
char s_p[16];
char s_P[16];
char s_c[16];
char s_C[16];
snprintf(s_a, sizeof(s_a), "%d", shamt);
if(immediate < 0)
snprintf(s_i, sizeof(s_i), "%d", immediate);
else
snprintf(s_i, sizeof(s_i), "0x%04x", (uint32)immediate);
snprintf(s_z, sizeof(s_z), "0x%04x", immediate_ze);
snprintf(s_p, sizeof(s_p), "0x%08x", PC + 4 + (immediate << 2));
snprintf(s_P, sizeof(s_P), "0x%08x", ((PC + 4) & 0xF0000000) | (jt << 2));
snprintf(s_c, sizeof(s_c), "CPR%d", rd);
snprintf(s_C, sizeof(s_C), "CCR%d", rd);
ret = std::string(op->mnemonic);
ret.append(10 - ret.size(), ' ');
for(unsigned int i = 0; i < strlen(op->format); i++)
{
switch(op->format[i])
{
case '#':
// sf mx v cv lm
{
char as[16];
as[0] = 0;
if(!strncmp(&op->format[i], "#sf#", 4))
{
i += 3;
snprintf(as, 16, "sf=%d", (int)(bool)(instr & (1 << 19)));
}
else if(!strncmp(&op->format[i], "#mx#", 4))
{
i += 3;
snprintf(as, 16, "mx=%d", (instr >> 17) & 0x3);
}
else if(!strncmp(&op->format[i], "#v#", 3))
{
i += 2;
snprintf(as, 16, "v=%d", (instr >> 15) & 0x3);
}
else if(!strncmp(&op->format[i], "#cv#", 4))
{
i += 3;
snprintf(as, 16, "cv=%d", (instr >> 13) & 0x3);
}
else if(!strncmp(&op->format[i], "#lm#", 4))
{
i += 3;
snprintf(as, 16, "lm=%d", (int)(bool)(instr & (1 << 10)));
}
ret.append(as);
}
break;
case 'F':
{
char s_F[16];
snprintf(s_F, 16, "0x%07x", instr & 0x1FFFFFF);
ret.append(s_F);
}
break;
case 'h':
ret.append(gte_dr_names[rt]);
break;
case 'g':
ret.append(gte_dr_names[rd]);
break;
case 'G':
ret.append(gte_cr_names[rd]);
break;
case '0':
ret.append(cop0_names[rd]);
break;
case 'c':
ret.append(s_c);
break;
case 'C':
ret.append(s_C);
break;
case 'a':
ret.append(s_a);
break;
case 'i':
ret.append(s_i);
break;
case 'z':
ret.append(s_z);
break;
case 'p':
ret.append(s_p);
break;
case 'P':
ret.append(s_P);
break;
case 's':
ret.append(gpr_names[rs]);
break;
case 't':
ret.append(gpr_names[rt]);
break;
case 'd':
ret.append(gpr_names[rd]);
break;
default:
ret.append(1, op->format[i]);
break;
}
}
break;
}
op++;
}
return(ret);
}
}

11
mednafen/psx-0925/dis.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef __MDFN_PSX_DIS_H
#define __MDFN_PSX_DIS_H
namespace MDFN_IEN_PSX
{
std::string DisassembleMIPS(uint32 PC, uint32 instr);
}
#endif

638
mednafen/psx-0925/dma.cpp Normal file
View File

@ -0,0 +1,638 @@
/* 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 "psx.h"
#include "mdec.h"
#include "cdc.h"
#include "spu.h"
// FIXME: 0-length block count?
/* Notes:
Channel 4(SPU):
Write:
Doesn't seem to work properly with CHCR=0x01000001
Hung when CHCR=0x11000601
Channel 6:
DMA hangs if D28 of CHCR is 0?
D1 did not have an apparent effect.
*/
enum
{
CH_MDEC_IN = 0,
CH_MDEC_OUT = 1,
CH_GPU = 2,
CH_CDC = 3,
CH_SPU = 4,
CH_OT = 6,
};
// RunChannels(128 - whatevercounter);
//
// GPU next event, std::max<128, wait_time>, or something similar, for handling FIFO.
namespace MDFN_IEN_PSX
{
static int32 DMACycleCounter;
static uint32 DMAControl;
static uint32 DMAIntControl;
static uint8 DMAIntStatus;
static bool IRQOut;
struct Channel
{
uint32 BaseAddr;
uint32 BlockControl;
uint32 ChanControl;
//
//
//
uint32 CurAddr;
uint32 NextAddr;
uint16 BlockCounter;
uint16 WordCounter;
int32 ClockCounter;
};
static Channel DMACH[7];
static pscpu_timestamp_t lastts;
static const char *PrettyChannelNames[7] = { "MDEC IN", "MDEC OUT", "GPU", "CDC", "SPU", "PIO", "OTC" };
void DMA_Init(void)
{
}
void DMA_Kill(void)
{
}
static INLINE void RecalcIRQOut(void)
{
bool irqo;
irqo = (bool)(DMAIntStatus & ((DMAIntControl >> 16) & 0x7F));
irqo &= (DMAIntControl >> 23) & 1;
// I think it's logical OR, not XOR/invert. Still kind of weird, maybe it actually does something more complicated?
//irqo ^= (DMAIntControl >> 15) & 1;
irqo |= (DMAIntControl >> 15) & 1;
IRQOut = irqo;
IRQ_Assert(IRQ_DMA, irqo);
}
void DMA_ResetTS(void)
{
lastts = 0;
}
void DMA_Power(void)
{
lastts = 0;
memset(DMACH, 0, sizeof(DMACH));
DMACycleCounter = 128;
DMAControl = 0;
DMAIntControl = 0;
DMAIntStatus = 0;
RecalcIRQOut();
}
static void RecalcHalt(void)
{
bool Halt = false;
if((DMACH[0].WordCounter || (DMACH[0].ChanControl & (1 << 24))) && (DMACH[0].ChanControl & 0x200) /*&& MDEC_DMACanWrite()*/)
Halt = true;
if((DMACH[1].WordCounter || (DMACH[1].ChanControl & (1 << 24))) && (DMACH[1].ChanControl & 0x200) && (DMACH[1].WordCounter || MDEC_DMACanRead()))
Halt = true;
if((DMACH[2].WordCounter || (DMACH[2].ChanControl & (1 << 24))) && (DMACH[2].ChanControl & 0x200) && ((DMACH[2].ChanControl & 0x1) && (DMACH[2].WordCounter || GPU->DMACanWrite())))
Halt = true;
if((DMACH[3].WordCounter || (DMACH[3].ChanControl & (1 << 24))) && !(DMACH[3].ChanControl & 0x100))
Halt = true;
if(DMACH[6].WordCounter || (DMACH[6].ChanControl & (1 << 24)))
Halt = true;
//printf("Halt: %d\n", Halt);
CPU->SetHalt(Halt);
}
template<int ch, bool write_mode>
static INLINE bool ChCan(void)
{
#if 0
if(ch != 3)
{
if((DMACH[3].WordCounter || (DMACH[3].ChanControl & (1 << 24))) && !(DMACH[3].ChanControl & 0x100))
{
return(false);
}
}
#endif
switch(ch)
{
case 0: return(true); // MDEC IN
case 1: return(MDEC_DMACanRead()); // MDEC out
case 2:
if(write_mode)
return(GPU->DMACanWrite());
else
return(true); // GPU
case 3: return(true); // CDC
case 4: return(true); // SPU
case 5: return(true); // ??
case 6: return(true); // OT
}
abort();
}
template<int ch, bool write_mode>
static INLINE void ChRW(int32 timestamp, uint32 *V)
{
switch(ch)
{
default:
abort();
case CH_MDEC_IN:
MDEC_DMAWrite(*V);
break;
case CH_MDEC_OUT:
*V = MDEC_DMARead();
break;
case CH_GPU:
if(write_mode)
GPU->WriteDMA(*V);
else
*V = GPU->Read(timestamp, 0);
break;
case CH_CDC:
// 0x1f801018 affects CDC DMA timing.
#if 0
if(DMACH[ch].ChanControl & 0x100) // For CDC DMA(at least): When this bit is set, DMA controller doesn't appear to hog the (RAM?) bus.
{
if(DMACH[ch].ChanControl & 0x00400000) // For CDC DMA(at least): When this bit is set, DMA controller appears to get even less bus time(or has a lower priority??)
{
DMACH[ch].ClockCounter -= 44 * 20 / 12;
}
else
{
DMACH[ch].ClockCounter -= 29 * 20 / 12;
}
}
else
{
DMACH[ch].ClockCounter -= 23 * 20 / 12; // (23 + 1) = 24. (Though closer to 24.5 or 24.4 on average per tests on a PS1)
}
#endif
*V = CDC->DMARead();
break;
case CH_SPU:
// 0x1f801014 affects SPU DMA timing.
// Wild conjecture about 0x1f801014:
//
// & 0x0000000F
// & 0x000001E0 --- Used if (& 0x20000000) == 0?
// & 0x00001000 --- Double total bus cycle time if value == 0?
// & 0x0f000000 --- (value << 1) 33MHz cycles, bus cycle extension(added to 4?)?
// & 0x20000000 ---
//
//
// TODO?: SPU DMA will "complete" much faster if there's a mismatch between the CHCR read/write mode bit and the SPU control register DMA mode.
//
//
// Investigate: SPU DMA doesn't seem to work right if the value written to 0x1F801DAA doesn't have the upper bit set to 1(0x8000) on a PS1.
DMACH[ch].ClockCounter -= 47; // Should be closer to 69, average, but actual timing is...complicated.
if(write_mode)
SPU->WriteDMA(*V);
else
*V = SPU->ReadDMA();
break;
case CH_OT:
if(DMACH[ch].WordCounter == 1)
*V = 0xFFFFFF;
else
*V = (DMACH[ch].CurAddr - 4) & 0x1FFFFF;
break;
}
}
template<int ch, bool write_mode>
static INLINE void RunChannelT(pscpu_timestamp_t timestamp, int32 clocks)
{
//const uint32 dc = (DMAControl >> (ch * 4)) & 0xF;
DMACH[ch].ClockCounter += clocks;
while(DMACH[ch].ClockCounter > 0)
{
if(!DMACH[ch].WordCounter)
{
if(!(DMACH[ch].ChanControl & (1 << 24)))
{
break;
}
if(DMACH[ch].NextAddr & 0x800000)
{
//if(ch == 2)
// PSX_WARNING("[DMA] LL Channel 2 ended normally: %d\n", GPU->GetScanlineNum());
DMACH[ch].ChanControl &= ~(0x11 << 24);
if(DMAIntControl & (1 << (16 + ch)))
{
DMAIntStatus |= 1 << ch;
RecalcIRQOut();
}
break;
}
if(!ChCan<ch, write_mode>())
break;
if((DMACH[ch].ChanControl & (1 << 10)) && write_mode)
{
uint32 header;
DMACH[ch].CurAddr = DMACH[ch].NextAddr & 0x1FFFFC;
header = MainRAM.ReadU32(DMACH[ch].CurAddr);
DMACH[ch].CurAddr = (DMACH[ch].CurAddr + 4) & 0x1FFFFF;
DMACH[ch].WordCounter = header >> 24;
DMACH[ch].NextAddr = header & 0xFFFFFF;
if(DMACH[ch].WordCounter > 0x10)
printf("What the lala? 0x%02x @ 0x%08x\n", DMACH[ch].WordCounter, DMACH[ch].CurAddr - 4);
if(DMACH[ch].WordCounter)
DMACH[ch].ClockCounter -= 15;
else
DMACH[ch].ClockCounter -= 10;
continue;
}
else
{
DMACH[ch].CurAddr = DMACH[ch].NextAddr & 0x1FFFFC;
DMACH[ch].WordCounter = DMACH[ch].BlockControl & 0xFFFF;
DMACH[ch].BlockCounter--;
if(!DMACH[ch].BlockCounter || ch == 6 || ch == 3)
DMACH[ch].NextAddr = 0xFFFFFF;
else
DMACH[ch].NextAddr = (DMACH[ch].CurAddr + ((DMACH[ch].BlockControl & 0xFFFF) << 2)) & 0x1FFFFF;
}
}
if(ch != 2 && ch != 1)
{
if(!ChCan<ch, write_mode>())
break;
}
{
uint32 vtmp;
if(write_mode)
vtmp = MainRAM.ReadU32(DMACH[ch].CurAddr);
ChRW<ch, write_mode>(timestamp, &vtmp);
if(!write_mode)
MainRAM.WriteU32(DMACH[ch].CurAddr, vtmp);
}
if(ch == 6)
DMACH[ch].CurAddr = (DMACH[ch].CurAddr - 4) & 0x1FFFFF;
else
DMACH[ch].CurAddr = (DMACH[ch].CurAddr + 4) & 0x1FFFFF;
DMACH[ch].WordCounter--;
DMACH[ch].ClockCounter--;
}
if(DMACH[ch].ClockCounter > 0)
DMACH[ch].ClockCounter = 0;
}
static INLINE void RunChannel(pscpu_timestamp_t timestamp, int32 clocks, int ch)
{
switch(ch)
{
default: abort();
case 0:
RunChannelT<0, true>(timestamp, clocks);
break;
case 1:
RunChannelT<1, false>(timestamp, clocks);
break;
case 2:
if(DMACH[2].ChanControl & 0x1)
RunChannelT<2, true>(timestamp, clocks);
else
RunChannelT<2, false>(timestamp, clocks);
break;
case 3:
RunChannelT<3, false>(timestamp, clocks);
break;
case 4:
if(DMACH[4].ChanControl & 0x1)
RunChannelT<4, true>(timestamp, clocks);
else
RunChannelT<4, false>(timestamp, clocks);
break;
case 6:
RunChannelT<6, false>(timestamp, clocks);
break;
}
}
static INLINE int32 CalcNextEvent(int32 next_event)
{
if(DMACycleCounter < next_event)
next_event = DMACycleCounter;
return(next_event);
}
pscpu_timestamp_t DMA_Update(const pscpu_timestamp_t timestamp)
{
// uint32 dc = (DMAControl >> (ch * 4)) & 0xF;
int32 clocks = timestamp - lastts;
lastts = timestamp;
GPU->Update(timestamp);
MDEC_Run(clocks);
RunChannel(timestamp, clocks, 0);
RunChannel(timestamp, clocks, 1);
RunChannel(timestamp, clocks, 2);
RunChannel(timestamp, clocks, 3);
RunChannel(timestamp, clocks, 4);
RunChannel(timestamp, clocks, 6);
DMACycleCounter -= clocks;
while(DMACycleCounter <= 0)
DMACycleCounter += 128;
RecalcHalt();
return(timestamp + CalcNextEvent(0x10000000));
}
void DMA_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)
{
int ch = (A & 0x7F) >> 4;
//PSX_WARNING("[DMA] Write: %08x %08x, DMAIntStatus=%08x", A, V, DMAIntStatus);
// FIXME if we ever have "accurate" bus emulation
V <<= (A & 3) * 8;
DMA_Update(timestamp);
if(ch == 7)
{
switch(A & 0xC)
{
case 0x0: //fprintf(stderr, "Global DMA control: 0x%08x\n", V);
DMAControl = V;
RecalcHalt();
break;
case 0x4:
//for(int x = 0; x < 7; x++)
//{
// if(DMACH[x].WordCounter || (DMACH[x].ChanControl & (1 << 24)))
// {
// fprintf(stderr, "Write DMAIntControl while channel %d active: 0x%08x\n", x, V);
// }
//}
DMAIntControl = V & 0x00ff803f;
DMAIntStatus &= ~(V >> 24);
//if(DMAIntStatus ^ (DMAIntStatus & (V >> 16)))
// fprintf(stderr, "DMAINT Fudge: %02x\n", DMAIntStatus ^ (DMAIntStatus & (V >> 16)));
DMAIntStatus &= (V >> 16); // THIS IS ALMOST CERTAINLY WRONG AND A HACK. Remove when CDC emulation is better.
RecalcIRQOut();
break;
default: PSX_WARNING("[DMA] Unknown write: %08x %08x", A, V);
assert(0);
break;
}
return;
}
switch(A & 0xC)
{
case 0x0: DMACH[ch].BaseAddr = V & 0xFFFFFF;
break;
case 0x4: DMACH[ch].BlockControl = V;
break;
case 0xC:
case 0x8:
{
uint32 OldCC = DMACH[ch].ChanControl;
//
// Kludge for DMA timing granularity and other issues. Needs to occur before setting all bits of ChanControl to the new value, to accommodate the
// case of a game cancelling DMA and changing the type of DMA(read/write, etc.) at the same time.
//
if((DMACH[ch].ChanControl & (1 << 24)) && !(V & (1 << 24)))
{
DMACH[ch].ChanControl &= ~(1 << 24); // Clear bit before RunChannel(), so it will only finish the block it's on at most.
RunChannel(timestamp, 128 * 16, ch);
DMACH[ch].BlockCounter = 0;
DMACH[ch].WordCounter = 0;
#if 0 // TODO(maybe, need to work out worst-case performance for abnormally/brokenly large block sizes)
DMACH[ch].ClockCounter = (1 << 30);
RunChannel(timestamp, 1, ch);
DMACH[ch].ClockCounter = 0;
#endif
if(ch == 2)
{
GPU->AbortDMA();
}
PSX_WARNING("[DMA] Forced stop for channel %d -- scanline=%d", ch, GPU->GetScanlineNum());
//MDFN_DispMessage("[DMA] Forced stop for channel %d", ch);
}
if(ch == 6)
DMACH[ch].ChanControl = V & 0x51000002; // Not 100% sure, but close.
else
DMACH[ch].ChanControl = V & 0x71770703;
if(!(OldCC & (1 << 24)) && (V & (1 << 24)))
{
//if(ch == 2)
//if(ch == 4)
//PSX_WARNING("[DMA] Started DMA for channel=%d --- CHCR=0x%08x --- BCR=0x%08x --- scanline=%d", ch, DMACH[ch].ChanControl, DMACH[ch].BlockControl, GPU->GetScanlineNum());
DMACH[ch].ClockCounter = 0;
DMACH[ch].NextAddr = DMACH[ch].BaseAddr & 0x1FFFFC;
DMACH[ch].BlockCounter = DMACH[ch].BlockControl >> 16;
//
// Viewpoint starts a short MEM->GPU LL DMA and apparently has race conditions that can cause a crash if it doesn't finish almost immediately(
// or at least very quickly, which the current DMA granularity has issues with, so run the channel ahead a bit to take of this issue and potentially
// games with similar issues).
//
// Though, Viewpoint isn't exactly a good game, so maybe we shouldn't bother? ;)
//
RunChannel(timestamp, 64, ch); //std::max<int>(128 - DMACycleCounter, 1)); //64); //1); //128 - DMACycleCounter);
}
RecalcHalt();
}
break;
}
PSX_SetEventNT(PSX_EVENT_DMA, timestamp + CalcNextEvent(0x10000000));
}
uint32 DMA_Read(const pscpu_timestamp_t timestamp, uint32 A)
{
int ch = (A & 0x7F) >> 4;
uint32 ret = 0;
//assert(!(A & 3));
//if(ch == 2)
// printf("DMA Read: %08x --- %d\n", A, GPU->GetScanlineNum());
if(ch == 7)
{
switch(A & 0xC)
{
default: PSX_WARNING("[DMA] Unknown read: %08x", A);
assert(0);
break;
case 0x0: ret = DMAControl;
break;
case 0x4: ret = DMAIntControl | (DMAIntStatus << 24) | (IRQOut << 31);
break;
}
}
else switch(A & 0xC)
{
case 0x0: ret = DMACH[ch].BaseAddr;
break;
case 0x4: ret = DMACH[ch].BlockControl;
break;
case 0xC:
case 0x8: ret = DMACH[ch].ChanControl;
break;
}
ret >>= (A & 3) * 8;
//PSX_WARNING("[DMA] Read: %08x %08x", A, ret);
return(ret);
}
int DMA_StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT StateRegs[] =
{
SFVAR(DMACycleCounter),
SFVAR(DMAControl),
SFVAR(DMAIntControl),
SFVAR(DMAIntStatus),
SFVAR(IRQOut),
#define SFDMACH(n) SFVARN(DMACH[n].BaseAddr, #n "BaseAddr"), \
SFVARN(DMACH[n].BlockControl, #n "BlockControl"), \
SFVARN(DMACH[n].ChanControl, #n "ChanControl"), \
SFVARN(DMACH[n].CurAddr, #n "CurAddr"), \
SFVARN(DMACH[n].NextAddr, #n "NextAddr"), \
SFVARN(DMACH[n].BlockCounter, #n "BlockCounter"), \
SFVARN(DMACH[n].WordCounter, #n "WordCounter"), \
SFVARN(DMACH[n].ClockCounter, #n "ClockCounter")
SFDMACH(0),
SFDMACH(1),
SFDMACH(2),
SFDMACH(3),
SFDMACH(4),
SFDMACH(5),
SFDMACH(6),
#undef SFDMACH
SFVAR(lastts),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "DMA");
if(load)
{
}
return(ret);
}
}

24
mednafen/psx-0925/dma.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef __MDFN_PSX_DMA_H
#define __MDFN_PSX_DMA_H
namespace MDFN_IEN_PSX
{
bool DMA_GPUWriteActive(void);
pscpu_timestamp_t DMA_Update(const pscpu_timestamp_t timestamp);
void DMA_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V);
uint32 DMA_Read(const pscpu_timestamp_t timestamp, uint32 A);
void DMA_ResetTS(void);
void DMA_Power(void);
void DMA_Init(void);
void DMA_Kill(void);
int DMA_StateAction(StateMem *sm, int load, int data_only);
}
#endif

View File

@ -0,0 +1,906 @@
/* 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 "psx.h"
#include "frontio.h"
#include "../FileWrapper.h"
#include "input/gamepad.h"
#include "input/dualanalog.h"
#include "input/dualshock.h"
#include "input/mouse.h"
#include "input/negcon.h"
#include "input/guncon.h"
#include "input/justifier.h"
#include "input/memcard.h"
#include "input/multitap.h"
#define PSX_FIODBGINFO(format, ...) { /* printf(format " -- timestamp=%d -- PAD temp\n", ## __VA_ARGS__, timestamp); */ }
namespace MDFN_IEN_PSX
{
InputDevice::InputDevice()
{
}
InputDevice::~InputDevice()
{
}
void InputDevice::Power(void)
{
}
void InputDevice::Update(const pscpu_timestamp_t timestamp)
{
}
void InputDevice::ResetTS(void)
{
}
void InputDevice::SetAMCT(bool)
{
}
void InputDevice::SetCrosshairsColor(uint32 color)
{
}
bool InputDevice::RequireNoFrameskip(void)
{
return(false);
}
pscpu_timestamp_t InputDevice::GPULineHook(const pscpu_timestamp_t timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock)
{
return(PSX_EVENT_MAXTS);
}
void InputDevice::UpdateInput(const void *data)
{
}
void InputDevice::SetDTR(bool new_dtr)
{
}
bool InputDevice::GetDSR(void)
{
return(0);
}
bool InputDevice::Clock(bool TxD, int32 &dsr_pulse_delay)
{
dsr_pulse_delay = 0;
return(1);
}
uint32 InputDevice::GetNVSize(void)
{
return(0);
}
void InputDevice::ReadNV(uint8 *buffer, uint32 offset, uint32 count)
{
}
void InputDevice::WriteNV(const uint8 *buffer, uint32 offset, uint32 count)
{
}
uint64 InputDevice::GetNVDirtyCount(void)
{
return(0);
}
void InputDevice::ResetNVDirtyCount(void)
{
}
static INLINE unsigned EP_to_MP(unsigned ep)
{
#if 0
return((bool)(ep & 0x4));
#else
return(ep == 1 || ep >= 5);
#endif
}
static INLINE unsigned EP_to_SP(unsigned ep)
{
#if 0
return(ep & 0x3);
#else
if(ep < 2)
return(0);
else if(ep < 5)
return(ep - 2 + 1);
else
return(ep - 5 + 1);
#endif
}
void FrontIO::MapDevicesToPorts(void)
{
for(unsigned i = 0; i < 2; i++)
{
if(emulate_multitap[i])
{
Ports[i] = DevicesTap[i];
MCPorts[i] = DummyDevice;
}
else
{
Ports[i] = Devices[i];
MCPorts[i] = emulate_memcards[i] ? DevicesMC[i] : DummyDevice;
}
}
for(unsigned i = 0; i < 8; i++)
{
unsigned mp = EP_to_MP(i);
if(emulate_multitap[mp])
DevicesTap[mp]->SetSubDevice(EP_to_SP(i), Devices[i], emulate_memcards[i] ? DevicesMC[i] : DummyDevice);
else
DevicesTap[mp]->SetSubDevice(EP_to_SP(i), DummyDevice, DummyDevice);
}
}
FrontIO::FrontIO(bool emulate_memcards_[8], bool emulate_multitap_[2])
{
memcpy(emulate_memcards, emulate_memcards_, sizeof(emulate_memcards));
memcpy(emulate_multitap, emulate_multitap_, sizeof(emulate_multitap));
DummyDevice = new InputDevice();
for(unsigned i = 0; i < 8; i++)
{
DeviceData[i] = NULL;
Devices[i] = new InputDevice();
DevicesMC[i] = Device_Memcard_Create();
chair_colors[i] = 1 << 24;
Devices[i]->SetCrosshairsColor(chair_colors[i]);
}
for(unsigned i = 0; i < 2; i++)
{
DevicesTap[i] = new InputDevice_Multitap();
}
MapDevicesToPorts();
}
void FrontIO::SetAMCT(bool enabled)
{
for(unsigned i = 0; i < 8; i++)
{
Devices[i]->SetAMCT(enabled);
}
amct_enabled = enabled;
}
void FrontIO::SetCrosshairsColor(unsigned port, uint32 color)
{
assert(port >= 0 && port < 8);
chair_colors[port] = color;
Devices[port]->SetCrosshairsColor(color);
}
FrontIO::~FrontIO()
{
for(int i = 0; i < 8; i++)
{
if(Devices[i])
{
delete Devices[i];
Devices[i] = NULL;
}
if(DevicesMC[i])
{
delete DevicesMC[i];
DevicesMC[i] = NULL;
}
}
for(unsigned i = 0; i < 2; i++)
{
if(DevicesTap[i])
{
delete DevicesTap[i];
DevicesTap[i] = NULL;
}
}
if(DummyDevice)
{
delete DummyDevice;
DummyDevice = NULL;
}
}
pscpu_timestamp_t FrontIO::CalcNextEventTS(pscpu_timestamp_t timestamp, int32 next_event)
{
pscpu_timestamp_t ret;
if(ClockDivider > 0 && ClockDivider < next_event)
next_event = ClockDivider;
for(int i = 0; i < 4; i++)
if(dsr_pulse_delay[i] > 0 && next_event > dsr_pulse_delay[i])
next_event = dsr_pulse_delay[i];
ret = timestamp + next_event;
if(irq10_pulse_ts[0] < ret)
ret = irq10_pulse_ts[0];
if(irq10_pulse_ts[1] < ret)
ret = irq10_pulse_ts[1];
return(ret);
}
void FrontIO::CheckStartStopPending(pscpu_timestamp_t timestamp, bool skip_event_set)
{
//const bool prior_ReceiveInProgress = ReceiveInProgress;
//const bool prior_TransmitInProgress = TransmitInProgress;
bool trigger_condition = false;
trigger_condition = (ReceivePending && (Control & 0x4)) || (TransmitPending && (Control & 0x1));
if(trigger_condition)
{
if(ReceivePending)
{
ReceivePending = false;
ReceiveInProgress = true;
ReceiveBufferAvail = false;
ReceiveBuffer = 0;
ReceiveBitCounter = 0;
}
if(TransmitPending)
{
TransmitPending = false;
TransmitInProgress = true;
TransmitBitCounter = 0;
}
ClockDivider = 0x44;
}
if(!(Control & 0x5))
{
ReceiveInProgress = false;
TransmitInProgress = false;
}
if(!ReceiveInProgress && !TransmitInProgress)
ClockDivider = 0;
if(!(skip_event_set))
PSX_SetEventNT(PSX_EVENT_FIO, CalcNextEventTS(timestamp, 0x10000000));
}
// DSR IRQ bit setting appears(from indirect tests on real PS1) to be level-sensitive, not edge-sensitive
INLINE void FrontIO::DoDSRIRQ(void)
{
if(Control & 0x1000)
{
PSX_FIODBGINFO("[DSR] IRQ");
istatus = true;
IRQ_Assert(IRQ_SIO, true);
}
}
void FrontIO::Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V)
{
assert(!(A & 0x1));
PSX_FIODBGINFO("[FIO] Write: %08x %08x", A, V);
Update(timestamp);
switch(A & 0xF)
{
case 0x0:
TransmitBuffer = V;
TransmitPending = true;
TransmitInProgress = false;
break;
case 0x8:
Mode = V & 0x013F;
break;
case 0xa:
if(ClockDivider > 0 && ((V & 0x2000) != (Control & 0x2000)) && ((Control & 0x2) == (V & 0x2)) )
fprintf(stderr, "FIO device selection changed during comm %04x->%04x", Control, V);
//printf("Control: %d, %04x\n", timestamp, V);
Control = V & 0x3F2F;
if(V & 0x10)
{
istatus = false;
IRQ_Assert(IRQ_SIO, false);
}
if(V & 0x40) // Reset
{
istatus = false;
IRQ_Assert(IRQ_SIO, false);
ClockDivider = 0;
ReceivePending = false;
TransmitPending = false;
ReceiveInProgress = false;
TransmitInProgress = false;
ReceiveBufferAvail = false;
TransmitBuffer = 0;
ReceiveBuffer = 0;
ReceiveBitCounter = 0;
TransmitBitCounter = 0;
Mode = 0;
Control = 0;
Baudrate = 0;
}
Ports[0]->SetDTR((Control & 0x2) && !(Control & 0x2000));
MCPorts[0]->SetDTR((Control & 0x2) && !(Control & 0x2000));
Ports[1]->SetDTR((Control & 0x2) && (Control & 0x2000));
MCPorts[1]->SetDTR((Control & 0x2) && (Control & 0x2000));
#if 1
if(!((Control & 0x2) && !(Control & 0x2000)))
{
dsr_pulse_delay[0] = 0;
dsr_pulse_delay[2] = 0;
dsr_active_until_ts[0] = -1;
dsr_active_until_ts[2] = -1;
}
if(!((Control & 0x2) && (Control & 0x2000)))
{
dsr_pulse_delay[1] = 0;
dsr_pulse_delay[3] = 0;
dsr_active_until_ts[1] = -1;
dsr_active_until_ts[3] = -1;
}
#endif
// TODO: Uncomment out in the future once our CPU emulation is a bit more accurate with timing, to prevent causing problems with games
// that may clear the IRQ in an unsafe pattern that only works because its execution was slow enough to allow DSR to go inactive. (Whether or not
// such games even exist though is unknown!)
//if(timestamp < dsr_active_until_ts[0] || timestamp < dsr_active_until_ts[1] || timestamp < dsr_active_until_ts[2] || timestamp < dsr_active_until_ts[3])
// DoDSRIRQ();
break;
case 0xe:
Baudrate = V;
//MDFN_DispMessage("%02x\n", V);
break;
}
CheckStartStopPending(timestamp, false);
}
uint32 FrontIO::Read(pscpu_timestamp_t timestamp, uint32 A)
{
uint32 ret = 0;
assert(!(A & 0x1));
Update(timestamp);
switch(A & 0xF)
{
case 0x0:
ret = ReceiveBuffer | (ReceiveBuffer << 8) | (ReceiveBuffer << 16) | (ReceiveBuffer << 24);
ReceiveBufferAvail = false;
ReceivePending = true;
ReceiveInProgress = false;
CheckStartStopPending(timestamp, false);
break;
case 0x4:
ret = 0;
if(!TransmitPending && !TransmitInProgress)
ret |= 0x1;
if(ReceiveBufferAvail)
ret |= 0x2;
if(timestamp < dsr_active_until_ts[0] || timestamp < dsr_active_until_ts[1] || timestamp < dsr_active_until_ts[2] || timestamp < dsr_active_until_ts[3])
ret |= 0x80;
if(istatus)
ret |= 0x200;
break;
case 0x8:
ret = Mode;
break;
case 0xa:
ret = Control;
break;
case 0xe:
ret = Baudrate;
break;
}
if((A & 0xF) != 0x4)
PSX_FIODBGINFO("[FIO] Read: %08x %08x", A, ret);
return(ret);
}
pscpu_timestamp_t FrontIO::Update(pscpu_timestamp_t timestamp)
{
int32 clocks = timestamp - lastts;
bool need_start_stop_check = false;
for(int i = 0; i < 4; i++)
if(dsr_pulse_delay[i] > 0)
{
dsr_pulse_delay[i] -= clocks;
if(dsr_pulse_delay[i] <= 0)
{
dsr_active_until_ts[i] = timestamp + 32 + dsr_pulse_delay[i];
DoDSRIRQ();
}
}
for(int i = 0; i < 2; i++)
{
if(timestamp >= irq10_pulse_ts[i])
{
//printf("Yay: %d %u\n", i, timestamp);
irq10_pulse_ts[i] = PSX_EVENT_MAXTS;
IRQ_Assert(IRQ_PIO, true);
IRQ_Assert(IRQ_PIO, false);
}
}
if(ClockDivider > 0)
{
ClockDivider -= clocks;
while(ClockDivider <= 0)
{
if(ReceiveInProgress || TransmitInProgress)
{
bool rxd = 0, txd = 0;
const uint32 BCMask = 0x07;
if(TransmitInProgress)
{
txd = (TransmitBuffer >> TransmitBitCounter) & 1;
TransmitBitCounter = (TransmitBitCounter + 1) & BCMask;
if(!TransmitBitCounter)
{
need_start_stop_check = true;
PSX_FIODBGINFO("[FIO] Data transmitted: %08x", TransmitBuffer);
TransmitInProgress = false;
if(Control & 0x400)
{
istatus = true;
IRQ_Assert(IRQ_SIO, true);
}
}
}
rxd = Ports[0]->Clock(txd, dsr_pulse_delay[0]) & Ports[1]->Clock(txd, dsr_pulse_delay[1]) &
MCPorts[0]->Clock(txd, dsr_pulse_delay[2]) & MCPorts[1]->Clock(txd, dsr_pulse_delay[3]);
if(ReceiveInProgress)
{
ReceiveBuffer &= ~(1 << ReceiveBitCounter);
ReceiveBuffer |= rxd << ReceiveBitCounter;
ReceiveBitCounter = (ReceiveBitCounter + 1) & BCMask;
if(!ReceiveBitCounter)
{
need_start_stop_check = true;
PSX_FIODBGINFO("[FIO] Data received: %08x", ReceiveBuffer);
ReceiveInProgress = false;
ReceiveBufferAvail = true;
if(Control & 0x800)
{
istatus = true;
IRQ_Assert(IRQ_SIO, true);
}
}
}
ClockDivider += 0x44; //88; //99;
}
else
break;
}
}
lastts = timestamp;
if(need_start_stop_check)
{
CheckStartStopPending(timestamp, true);
}
return(CalcNextEventTS(timestamp, 0x10000000));
}
void FrontIO::ResetTS(void)
{
for(int i = 0; i < 8; i++)
{
Devices[i]->Update(lastts); // Maybe eventually call Update() from FrontIO::Update() and remove this(but would hurt speed)?
Devices[i]->ResetTS();
DevicesMC[i]->Update(lastts); // Maybe eventually call Update() from FrontIO::Update() and remove this(but would hurt speed)?
DevicesMC[i]->ResetTS();
}
for(int i = 0; i < 2; i++)
{
DevicesTap[i]->Update(lastts);
DevicesTap[i]->ResetTS();
}
for(int i = 0; i < 2; i++)
{
if(irq10_pulse_ts[i] != PSX_EVENT_MAXTS)
irq10_pulse_ts[i] -= lastts;
}
for(int i = 0; i < 4; i++)
{
if(dsr_active_until_ts[i] >= 0)
{
dsr_active_until_ts[i] -= lastts;
//printf("SPOOONY: %d %d\n", i, dsr_active_until_ts[i]);
}
}
lastts = 0;
}
void FrontIO::Power(void)
{
for(int i = 0; i < 4; i++)
{
dsr_pulse_delay[i] = 0;
dsr_active_until_ts[i] = -1;
}
for(int i = 0; i < 2; i++)
{
irq10_pulse_ts[i] = PSX_EVENT_MAXTS;
}
lastts = 0;
//
//
ClockDivider = 0;
ReceivePending = false;
TransmitPending = false;
ReceiveInProgress = false;
TransmitInProgress = false;
ReceiveBufferAvail = false;
TransmitBuffer = 0;
ReceiveBuffer = 0;
ReceiveBitCounter = 0;
TransmitBitCounter = 0;
Mode = 0;
Control = 0;
Baudrate = 0;
for(int i = 0; i < 8; i++)
{
Devices[i]->Power();
DevicesMC[i]->Power();
}
istatus = false;
}
void FrontIO::UpdateInput(void)
{
for(int i = 0; i < 8; i++)
Devices[i]->UpdateInput(DeviceData[i]);
}
void FrontIO::SetInput(unsigned int port, const char *type, void *ptr)
{
delete Devices[port];
Devices[port] = NULL;
if(port < 2)
irq10_pulse_ts[port] = PSX_EVENT_MAXTS;
if(!strcmp(type, "gamepad"))
Devices[port] = Device_Gamepad_Create();
else if(!strcmp(type, "dualanalog"))
Devices[port] = Device_DualAnalog_Create(false);
else if(!strcmp(type, "analogjoy"))
Devices[port] = Device_DualAnalog_Create(true);
else if(!strcmp(type, "dualshock"))
{
char name[256];
trio_snprintf(name, 256, _("DualShock on port %u"), port + 1);
Devices[port] = Device_DualShock_Create(std::string(name));
}
else if(!strcmp(type, "mouse"))
Devices[port] = Device_Mouse_Create();
else if(!strcmp(type, "negcon"))
Devices[port] = Device_neGcon_Create();
else if(!strcmp(type, "guncon"))
Devices[port] = Device_GunCon_Create();
else if(!strcmp(type, "justifier"))
Devices[port] = Device_Justifier_Create();
else
Devices[port] = new InputDevice();
Devices[port]->SetAMCT(amct_enabled);
Devices[port]->SetCrosshairsColor(chair_colors[port]);
DeviceData[port] = ptr;
MapDevicesToPorts();
}
uint64 FrontIO::GetMemcardDirtyCount(unsigned int which)
{
assert(which < 8);
return(DevicesMC[which]->GetNVDirtyCount());
}
void FrontIO::LoadMemcard(unsigned int which, const char *path)
{
assert(which < 8);
try
{
if(DevicesMC[which]->GetNVSize())
{
FileWrapper mf(path, FileWrapper::MODE_READ);
std::vector<uint8> tmpbuf;
tmpbuf.resize(DevicesMC[which]->GetNVSize());
if(mf.size() != (int64)tmpbuf.size())
throw(MDFN_Error(0, _("Memory card file \"%s\" is an incorrect size(%d bytes). The correct size is %d bytes."), path, (int)mf.size(), (int)tmpbuf.size()));
mf.read(&tmpbuf[0], tmpbuf.size());
DevicesMC[which]->WriteNV(&tmpbuf[0], 0, tmpbuf.size());
DevicesMC[which]->ResetNVDirtyCount(); // There's no need to rewrite the file if it's the same data.
}
}
catch(MDFN_Error &e)
{
if(e.GetErrno() != ENOENT)
throw(e);
}
}
void FrontIO::SaveMemcard(unsigned int which, const char *path)
{
assert(which < 8);
if(DevicesMC[which]->GetNVSize() && DevicesMC[which]->GetNVDirtyCount())
{
FileWrapper mf(path, FileWrapper::MODE_WRITE); // TODO: MODE_WRITE_ATOMIC_OVERWRITE
std::vector<uint8> tmpbuf;
tmpbuf.resize(DevicesMC[which]->GetNVSize());
DevicesMC[which]->ReadNV(&tmpbuf[0], 0, tmpbuf.size());
mf.write(&tmpbuf[0], tmpbuf.size());
mf.close(); // Call before resetting the NV dirty count!
DevicesMC[which]->ResetNVDirtyCount();
}
}
bool FrontIO::RequireNoFrameskip(void)
{
for(unsigned i = 0; i < 8; i++)
if(Devices[i]->RequireNoFrameskip())
return(true);
return(false);
}
void FrontIO::GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock)
{
Update(timestamp);
for(unsigned i = 0; i < 8; i++)
{
pscpu_timestamp_t plts = Devices[i]->GPULineHook(line_timestamp, vsync, pixels, format, width, pix_clock_offset, pix_clock);
if(i < 2)
{
irq10_pulse_ts[i] = plts;
if(irq10_pulse_ts[i] <= timestamp)
{
irq10_pulse_ts[i] = PSX_EVENT_MAXTS;
IRQ_Assert(IRQ_PIO, true);
IRQ_Assert(IRQ_PIO, false);
}
}
}
PSX_SetEventNT(PSX_EVENT_FIO, CalcNextEventTS(timestamp, 0x10000000));
}
static InputDeviceInfoStruct InputDeviceInfoPSXPort[] =
{
// None
{
"none",
"none",
NULL,
NULL,
0,
NULL
},
// Gamepad(SCPH-1080)
{
"gamepad",
"Digital Gamepad",
"PlayStation digital gamepad; SCPH-1080.",
NULL,
sizeof(Device_Gamepad_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_Gamepad_IDII,
},
// Dual Shock Gamepad(SCPH-1200)
{
"dualshock",
"DualShock",
"DualShock gamepad; SCPH-1200. Emulation in Mednafen includes the analog mode toggle button.",
NULL,
sizeof(Device_DualShock_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_DualShock_IDII,
},
// Dual Analog Gamepad(SCPH-1180), forced to analog mode.
{
"dualanalog",
"Dual Analog",
"Dual Analog gamepad; SCPH-1180. It is the predecessor/prototype to the more advanced DualShock. Emulated in Mednafen as forced to analog mode, and without rumble.",
NULL,
sizeof(Device_DualAnalog_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_DualAnalog_IDII,
},
// Analog joystick(SCPH-1110), forced to analog mode - emulated through a tweak to dual analog gamepad emulation.
{
"analogjoy",
"Analog Joystick",
"Flight-game-oriented dual-joystick controller; SCPH-1110. Emulated in Mednafen as forced to analog mode.",
NULL,
sizeof(Device_AnalogJoy_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_AnalogJoy_IDII,
},
{
"mouse",
"Mouse",
NULL,
NULL,
sizeof(Device_Mouse_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_Mouse_IDII,
},
{
"negcon",
"neGcon",
"Namco's unconventional twisty racing-game-oriented gamepad; NPC-101.",
NULL,
sizeof(Device_neGcon_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_neGcon_IDII,
},
{
"guncon",
"GunCon",
"Namco's light gun; NPC-103.",
NULL,
sizeof(Device_GunCon_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_GunCon_IDII,
},
{
"justifier",
"Konami Justifier",
"Konami's light gun; SLUH-00017. Rumored to be wrought of the coagulated rage of all who tried to shoot The Dog. If the game you want to play supports the \"GunCon\", you should use that instead. NOTE: Currently does not work properly when on any of ports 1B-1D and 2B-2D.",
NULL,
sizeof(Device_Justifier_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_Justifier_IDII,
},
};
static const InputPortInfoStruct PortInfo[] =
{
{ "port1", "Port 1/1A", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port2", "Port 2/2A", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port3", "Port 1B", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port4", "Port 1C", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port5", "Port 1D", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port6", "Port 2B", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port7", "Port 2C", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port8", "Port 2D", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
};
InputInfoStruct FIO_InputInfo =
{
sizeof(PortInfo) / sizeof(InputPortInfoStruct),
PortInfo
};
}

142
mednafen/psx-0925/frontio.h Normal file
View File

@ -0,0 +1,142 @@
#ifndef __MDFN_PSX_FRONTIO_H
#define __MDFN_PSX_FRONTIO_H
namespace MDFN_IEN_PSX
{
class InputDevice_Multitap;
class InputDevice
{
public:
InputDevice();
virtual ~InputDevice();
virtual void Power(void);
virtual void UpdateInput(const void *data);
virtual bool RequireNoFrameskip(void);
virtual pscpu_timestamp_t GPULineHook(const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock);
virtual void Update(const pscpu_timestamp_t timestamp); // Partially-implemented, don't rely on for timing any more fine-grained than a video frame for now.
virtual void ResetTS(void);
//
//
//
virtual void SetAMCT(bool enabled);
virtual void SetCrosshairsColor(uint32 color);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void); // Currently unused.
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
//
//
virtual uint32 GetNVSize(void);
virtual void ReadNV(uint8 *buffer, uint32 offset, uint32 count);
virtual void WriteNV(const uint8 *buffer, uint32 offset, uint32 count);
//
// Dirty count should be incremented on each call to a method this class that causes at least 1 write to occur to the
// nonvolatile memory(IE Clock() in the correct command phase, and WriteNV()).
//
virtual uint64 GetNVDirtyCount(void);
virtual void ResetNVDirtyCount(void);
};
class FrontIO
{
public:
FrontIO(bool emulate_memcards_[8], bool emulate_multitap_[2]);
~FrontIO();
void Power(void);
void Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V);
uint32 Read(pscpu_timestamp_t timestamp, uint32 A);
pscpu_timestamp_t CalcNextEventTS(pscpu_timestamp_t timestamp, int32 next_event);
pscpu_timestamp_t Update(pscpu_timestamp_t timestamp);
void ResetTS(void);
bool RequireNoFrameskip(void);
void GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock);
void UpdateInput(void);
void SetInput(unsigned int port, const char *type, void *ptr);
void SetAMCT(bool enabled);
void SetCrosshairsColor(unsigned port, uint32 color);
uint64 GetMemcardDirtyCount(unsigned int which);
void LoadMemcard(unsigned int which, const char *path);
void SaveMemcard(unsigned int which, const char *path); //, bool force_save = false);
private:
void DoDSRIRQ(void);
void CheckStartStopPending(pscpu_timestamp_t timestamp, bool skip_event_set = false);
void MapDevicesToPorts(void);
bool emulate_memcards[8];
bool emulate_multitap[2];
InputDevice *Ports[2];
InputDevice *MCPorts[2];
InputDevice *DummyDevice;
InputDevice_Multitap *DevicesTap[2];
InputDevice *Devices[8];
void *DeviceData[8];
InputDevice *DevicesMC[8];
//
//
//
int32 ClockDivider;
bool ReceivePending;
bool TransmitPending;
bool ReceiveInProgress;
bool TransmitInProgress;
bool ReceiveBufferAvail;
uint8 ReceiveBuffer;
uint8 TransmitBuffer;
int32 ReceiveBitCounter;
int32 TransmitBitCounter;
uint16 Mode;
uint16 Control;
uint16 Baudrate;
bool istatus;
//
//
pscpu_timestamp_t irq10_pulse_ts[2];
int32 dsr_pulse_delay[4];
int32 dsr_active_until_ts[4];
int32 lastts;
//
//
bool amct_enabled;
uint32 chair_colors[8];
};
extern InputInfoStruct FIO_InputInfo;
}
#endif

1365
mednafen/psx-0925/gpu.cpp Normal file

File diff suppressed because it is too large Load Diff

325
mednafen/psx-0925/gpu.h Normal file
View File

@ -0,0 +1,325 @@
// WARNING WARNING WARNING: ONLY use CanRead() method of BlitterFIFO, and NOT CanWrite(), since the FIFO is larger than the actual PS1 GPU FIFO to accommodate
// our lack of fancy superscalarish command sequencer.
#ifndef __MDFN_PSX_GPU_H
#define __MDFN_PSX_GPU_H
#include "../cdrom/SimpleFIFO.h"
namespace MDFN_IEN_PSX
{
class PS_GPU;
struct CTEntry
{
uint8 len;
uint8 fifo_fb_len;
bool ss_cmd;
const char *name;
void (PS_GPU::*func[8])(const uint32 *cb);
};
struct tri_vertex
{
int32 x, y;
int32 u, v;
int32 r, g, b;
};
struct i_group;
struct i_deltas;
struct line_point
{
int32 x, y;
uint8 r, g, b;
};
class PS_GPU
{
public:
PS_GPU(bool pal_clock_and_tv);
~PS_GPU();
void Power(void);
void ResetTS(void);
void StartFrame(EmulateSpecStruct *espec);
pscpu_timestamp_t Update(const pscpu_timestamp_t timestamp);
void Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V);
INLINE bool CalcFIFOReadyBit(void)
{
if(InCmd & (INCMD_PLINE | INCMD_QUAD))
return(false);
if(BlitterFIFO.CanRead() == 0)
return(true);
if(InCmd & (INCMD_FBREAD | INCMD_FBWRITE))
return(false);
if(BlitterFIFO.CanRead() >= Commands[0][BlitterFIFO.ReadUnit(true) >> 24].fifo_fb_len)
return(false);
return(true);
}
INLINE bool DMACanWrite(void)
{
return CalcFIFOReadyBit();
}
INLINE void AbortDMA(void)
{
BlitterFIFO.Flush();
InCmd = INCMD_NONE;
}
void WriteDMA(uint32 V);
uint32 Read(const pscpu_timestamp_t timestamp, uint32 A);
inline int32 GetScanlineNum(void)
{
return(scanline);
}
INLINE uint16 PeekRAM(uint32 A)
{
return(GPURAM[(A >> 10) & 0x1FF][A & 0x3FF]);
}
INLINE void PokeRAM(uint32 A, uint16 V)
{
GPURAM[(A >> 10) & 0x1FF][A & 0x3FF] = V;
}
private:
void ProcessFIFO(void);
void WriteCB(uint32 data);
void SoftReset(void);
// Y, X
uint16 GPURAM[512][1024];
uint32 DMAControl;
//
// Drawing stuff
//
//int32 TexPageX; // 0, 64, 128, 192, etc up to 960
//int32 TexPageY; // 0 or 256
//uint32 abr; // Semi-transparency mode(0~3)
//bool dtd; // Dithering enable
int32 ClipX0;
int32 ClipY0;
int32 ClipX1;
int32 ClipY1;
int32 OffsX;
int32 OffsY;
bool dtd;
bool dfe;
uint32 MaskSetOR;
uint32 MaskEvalAND;
uint8 tww, twh, twx, twy;
struct
{
uint8 TexWindowXLUT_Pre[16];
uint8 TexWindowXLUT[256];
uint8 TexWindowXLUT_Post[16];
};
struct
{
uint8 TexWindowYLUT_Pre[16];
uint8 TexWindowYLUT[256];
uint8 TexWindowYLUT_Post[16];
};
void RecalcTexWindowLUT(void);
int32 TexPageX;
int32 TexPageY;
uint32 SpriteFlip;
uint32 abr;
uint32 TexMode;
struct
{
uint8 RGB8SAT_Under[256];
uint8 RGB8SAT[256];
uint8 RGB8SAT_Over[256];
};
uint8 DitherLUT[4][4][512]; // Y, X, 8-bit source value(256 extra for saturation)
bool LineSkipTest(unsigned y);
template<int BlendMode, bool MaskEval_TA, bool textured>
void PlotPixel(int32 x, int32 y, uint16 pix);
template<uint32 TexMode_TA>
uint16 GetTexel(uint32 clut_offset, int32 u, int32 v);
uint16 ModTexel(uint16 texel, int32 r, int32 g, int32 b, const int32 dither_x, const int32 dither_y);
template<bool goraud, bool textured, int BlendMode, bool TexMult, uint32 TexMode, bool MaskEval_TA>
void DrawSpan(int y, uint32 clut_offset, const int32 x_start, const int32 x_bound, const int32 bv_x, i_group ig, const i_deltas &idl);
template<bool shaded, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
void DrawTriangle(tri_vertex *vertices, uint32 clut);
template<int numvertices, bool shaded, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
void Command_DrawPolygon(const uint32 *cb);
template<bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA, bool FlipX, bool FlipY>
void DrawSprite(int32 x_arg, int32 y_arg, int32 w, int32 h, uint8 u_arg, uint8 v_arg, uint32 color, uint32 clut_offset);
template<uint8 raw_size, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
void Command_DrawSprite(const uint32 *cb);
template<bool goraud, int BlendMode, bool MaskEval_TA>
void DrawLine(line_point *vertices);
template<bool polyline, bool goraud, int BlendMode, bool MaskEval_TA>
void Command_DrawLine(const uint32 *cb);
void Command_ClearCache(const uint32 *cb);
void Command_FBFill(const uint32 *cb);
void Command_FBCopy(const uint32 *cb);
void Command_FBWrite(const uint32 *cb);
void Command_FBRead(const uint32 *cb);
void Command_DrawMode(const uint32 *cb);
void Command_TexWindow(const uint32 *cb);
void Command_Clip0(const uint32 *cb);
void Command_Clip1(const uint32 *cb);
void Command_DrawingOffset(const uint32 *cb);
void Command_MaskSetting(const uint32 *cb);
static CTEntry Commands[4][256];
SimpleFIFO<uint32> BlitterFIFO;
uint32 DataReadBuffer;
//
//
//
// Powers of 2 for faster multiple equality testing(just for multi-testing; InCmd itself will only contain 0, or a power of 2).
enum
{
INCMD_NONE = 0,
INCMD_PLINE = (1 << 0),
INCMD_QUAD = (1 << 1),
INCMD_FBWRITE = (1 << 2),
INCMD_FBREAD = (1 << 3)
};
uint8 InCmd;
uint8 InCmd_CC;
tri_vertex InQuad_F3Vertices[3];
uint32 InQuad_clut;
line_point InPLine_PrevPoint;
uint32 FBRW_X;
uint32 FBRW_Y;
uint32 FBRW_W;
uint32 FBRW_H;
uint32 FBRW_CurY;
uint32 FBRW_CurX;
//
// Display Parameters
//
uint32 DisplayMode;
bool DisplayOff;
uint32 DisplayFB_XStart;
uint32 DisplayFB_YStart;
uint32 HorizStart;
uint32 HorizEnd;
uint32 VertStart;
uint32 VertEnd;
//
// Display work vars
//
/*
uint32 DisplayMode_Latch;
bool DisplayOff_Latch;
uint32 DisplayFB_XStart_Latch;
uint32 DisplayFB_YStart_Latch;
uint32 HorizStart_Latch;
uint32 HorizEnd_Latch;
uint32 VertStart_Latch;
uint32 VertEnd_Latch;
*/
uint32 DisplayFB_CurYOffset;
uint32 DisplayFB_CurLineYReadout;
uint32 DisplayHeightCounter;
//
//
//
uint32 LinesPerField;
uint32 VisibleStartLine;
bool FrameInterlaced;
bool PALMode;
bool HeightMode;
uint32 scanline;
bool field;
bool field_atvs;
bool PhaseChange;
uint32 DotClockCounter;
uint64 GPUClockCounter;
uint32 GPUClockRatio;
int32 LineClockCounter;
int32 LinePhase;
int32 DrawTimeAvail;
pscpu_timestamp_t lastts;
//
//
//
EmulateSpecStruct *espec;
MDFN_Surface *surface;
MDFN_Rect *DisplayRect;
MDFN_Rect *LineWidths;
bool skip;
bool HardwarePALType;
uint32 OutputLUT[32768];
void ReorderRGB_Var(uint32 out_Rshift, uint32 out_Gshift, uint32 out_Bshift, bool bpp24, const uint16 *src, uint32 *dest, const int32 dx_start, const int32 dx_end, int32 fb_x);
template<uint32 out_Rshift, uint32 out_Gshift, uint32 out_Bshift>
void ReorderRGB(bool bpp24, const uint16 *src, uint32 *dest, const int32 dx_start, const int32 dx_end, int32 fb_x) NO_INLINE;
};
}
#endif

View File

@ -0,0 +1,195 @@
#define POLY_HELPER_SUB(cv, tm, mam) \
&PS_GPU::Command_DrawPolygon<3 + ((cv & 0x8) >> 3), ((cv & 0x10) >> 4), ((cv & 0x4) >> 2), ((cv & 0x2) >> 1) ? BLENDMODE_MAC : -1, ((cv & 1) ^ 1) & ((cv & 0x4) >> 2), tm, mam >
#define POLY_HELPER(cv) { 1 + (3 /*+ ((cv & 0x8) >> 3)*/) * ( 1 + ((cv & 0x4) >> 2) + ((cv & 0x10) >> 4) ) - ((cv & 0x10) >> 4), \
1, false, "Polygon", { POLY_HELPER_SUB(cv, ((cv & 0x4) ? 0 : 0), 0), POLY_HELPER_SUB(cv, ((cv & 0x4) ? 1 : 0), 0), \
POLY_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 0), POLY_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 0), \
POLY_HELPER_SUB(cv, ((cv & 0x4) ? 0 : 0), 1), POLY_HELPER_SUB(cv, ((cv & 0x4) ? 1 : 0), 1), \
POLY_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 1), POLY_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 1), \
} }
//
//
#define SPR_HELPER_SUB(cv, tm, mam) &PS_GPU::Command_DrawSprite<(cv >> 3) & 0x3, ((cv & 0x4) >> 2), ((cv & 0x2) >> 1) ? BLENDMODE_MAC : -1, ((cv & 1) ^ 1) & ((cv & 0x4) >> 2), tm, mam>
#define SPR_HELPER(cv) { 2 + ((cv & 0x4) >> 2) + ((cv & 0x18) ? 0 : 1), 2 | ((cv & 0x4) >> 2) | ((cv & 0x18) ? 0 : 1), false, "Sprite", { \
SPR_HELPER_SUB(cv, ((cv & 0x4) ? 0 : 0), 0), SPR_HELPER_SUB(cv, ((cv & 0x4) ? 1 : 0), 0), \
SPR_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 0), SPR_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 0), \
SPR_HELPER_SUB(cv, ((cv & 0x4) ? 0 : 0), 1), SPR_HELPER_SUB(cv, ((cv & 0x4) ? 1 : 0), 1), \
SPR_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 1), SPR_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 1), \
} }
//
//
#define LINE_HELPER_SUB(cv, mam) &PS_GPU::Command_DrawLine<((cv & 0x08) >> 3), ((cv & 0x10) >> 4), ((cv & 0x2) >> 1) ? BLENDMODE_MAC : -1, mam>
#define LINE_HELPER(cv) { 3 + ((cv & 0x10) >> 4), 1, false, "Line", \
{ LINE_HELPER_SUB(cv, 0), LINE_HELPER_SUB(cv, 0), LINE_HELPER_SUB(cv, 0), LINE_HELPER_SUB(cv, 0), \
LINE_HELPER_SUB(cv, 1), LINE_HELPER_SUB(cv, 1), LINE_HELPER_SUB(cv, 1), LINE_HELPER_SUB(cv, 1), } }
//
//
#define OTHER_HELPER(arg_cs, arg_fbcs, arg_ss, arg_name, arg_ptr) { arg_cs, arg_fbcs, arg_ss, arg_name, { arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr } }
#define NULLCMD() { 1, 1, true, NULL, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }
/* 0x00 */
NULLCMD(),
OTHER_HELPER(1, 2, false, "Clear Cache", &PS_GPU::Command_ClearCache),
OTHER_HELPER(3, 3, false, "FB Fill", &PS_GPU::Command_FBFill),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
/* 0x10 */
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
/* 0x20 */
POLY_HELPER(0x20),
POLY_HELPER(0x21),
POLY_HELPER(0x22),
POLY_HELPER(0x23),
POLY_HELPER(0x24),
POLY_HELPER(0x25),
POLY_HELPER(0x26),
POLY_HELPER(0x27),
POLY_HELPER(0x28),
POLY_HELPER(0x29),
POLY_HELPER(0x2a),
POLY_HELPER(0x2b),
POLY_HELPER(0x2c),
POLY_HELPER(0x2d),
POLY_HELPER(0x2e),
POLY_HELPER(0x2f),
POLY_HELPER(0x30),
POLY_HELPER(0x31),
POLY_HELPER(0x32),
POLY_HELPER(0x33),
POLY_HELPER(0x34),
POLY_HELPER(0x35),
POLY_HELPER(0x36),
POLY_HELPER(0x37),
POLY_HELPER(0x38),
POLY_HELPER(0x39),
POLY_HELPER(0x3a),
POLY_HELPER(0x3b),
POLY_HELPER(0x3c),
POLY_HELPER(0x3d),
POLY_HELPER(0x3e),
POLY_HELPER(0x3f),
LINE_HELPER(0x40),
LINE_HELPER(0x41),
LINE_HELPER(0x42),
LINE_HELPER(0x43),
LINE_HELPER(0x44),
LINE_HELPER(0x45),
LINE_HELPER(0x46),
LINE_HELPER(0x47),
LINE_HELPER(0x48),
LINE_HELPER(0x49),
LINE_HELPER(0x4a),
LINE_HELPER(0x4b),
LINE_HELPER(0x4c),
LINE_HELPER(0x4d),
LINE_HELPER(0x4e),
LINE_HELPER(0x4f),
LINE_HELPER(0x50),
LINE_HELPER(0x51),
LINE_HELPER(0x52),
LINE_HELPER(0x53),
LINE_HELPER(0x54),
LINE_HELPER(0x55),
LINE_HELPER(0x56),
LINE_HELPER(0x57),
LINE_HELPER(0x58),
LINE_HELPER(0x59),
LINE_HELPER(0x5a),
LINE_HELPER(0x5b),
LINE_HELPER(0x5c),
LINE_HELPER(0x5d),
LINE_HELPER(0x5e),
LINE_HELPER(0x5f),
SPR_HELPER(0x60),
SPR_HELPER(0x61),
SPR_HELPER(0x62),
SPR_HELPER(0x63),
SPR_HELPER(0x64),
SPR_HELPER(0x65),
SPR_HELPER(0x66),
SPR_HELPER(0x67),
SPR_HELPER(0x68),
SPR_HELPER(0x69),
SPR_HELPER(0x6a),
SPR_HELPER(0x6b),
SPR_HELPER(0x6c),
SPR_HELPER(0x6d),
SPR_HELPER(0x6e),
SPR_HELPER(0x6f),
SPR_HELPER(0x70),
SPR_HELPER(0x71),
SPR_HELPER(0x72),
SPR_HELPER(0x73),
SPR_HELPER(0x74),
SPR_HELPER(0x75),
SPR_HELPER(0x76),
SPR_HELPER(0x77),
SPR_HELPER(0x78),
SPR_HELPER(0x79),
SPR_HELPER(0x7a),
SPR_HELPER(0x7b),
SPR_HELPER(0x7c),
SPR_HELPER(0x7d),
SPR_HELPER(0x7e),
SPR_HELPER(0x7f),
/* 0x80 */
OTHER_HELPER(4, 2, false, "FB Copy", &PS_GPU::Command_FBCopy),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
/* 0x90 */
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
/* 0xA0 */
OTHER_HELPER(3, 2, false, "FB Write", &PS_GPU::Command_FBWrite),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
/* 0xB0 */
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
/* 0xC0 */
OTHER_HELPER(3, 2, false, "FB Read", &PS_GPU::Command_FBRead),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
/* 0xD0 */
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
/* 0xE0 */
NULLCMD(),
OTHER_HELPER(1, 2, false, "Draw mode settings", &PS_GPU::Command_DrawMode),
OTHER_HELPER(1, 2, false, "Texture window settings", &PS_GPU::Command_TexWindow),
OTHER_HELPER(1, 1, true, "Drawing area top left", &PS_GPU::Command_Clip0),
OTHER_HELPER(1, 1, true, "Drawing area bottom right", &PS_GPU::Command_Clip1),
OTHER_HELPER(1, 1, true, "Drawing offset", &PS_GPU::Command_DrawingOffset),
OTHER_HELPER(1, 2, false, "Mask settings", &PS_GPU::Command_MaskSetting),
NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
/* 0xF0 */
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),

View File

@ -0,0 +1,249 @@
struct line_fxp_coord
{
int64 x, y;
int32 r, g, b;
};
struct line_fxp_step
{
int64 dx_dk, dy_dk;
int32 dr_dk, dg_dk, db_dk;
};
enum { Line_XY_FractBits = 32 };
enum { Line_RGB_FractBits = 12 };
template<bool goraud>
static INLINE void LinePointToFXPCoord(const line_point &point, const line_fxp_step &step, line_fxp_coord &coord)
{
coord.x = ((int64)point.x << Line_XY_FractBits) | (1LL << (Line_XY_FractBits - 1));
coord.y = ((int64)point.y << Line_XY_FractBits) | (1LL << (Line_XY_FractBits - 1));
if(goraud)
{
coord.r = (point.r << Line_RGB_FractBits) | (1 << (Line_RGB_FractBits - 1));
coord.g = (point.g << Line_RGB_FractBits) | (1 << (Line_RGB_FractBits - 1));
coord.b = (point.b << Line_RGB_FractBits) | (1 << (Line_RGB_FractBits - 1));
}
// Not sure if this is correct or just roughly corresponds to behavior of real system(need more testing):
if(step.dx_dk < 0)
coord.x--;
if(step.dy_dk < 0)
coord.y--;
if(step.dr_dk < 0)
coord.r--;
if(step.dg_dk < 0)
coord.g--;
if(step.db_dk < 0)
coord.b--;
}
template<typename T, unsigned bits>
static INLINE T LineDivide(T delta, int32 dk)
{
delta <<= bits;
if(delta < 0)
delta -= dk - 1;
if(delta > 0)
delta += dk - 1;
return(delta / dk);
}
template<bool goraud>
static INLINE void LinePointsToFXPStep(const line_point &point0, const line_point &point1, const int32 dk, line_fxp_step &step)
{
if(!dk)
{
step.dx_dk = 0;
step.dy_dk = 0;
if(goraud)
{
step.dr_dk = 0;
step.dg_dk = 0;
step.db_dk = 0;
}
return;
}
step.dx_dk = LineDivide<int64, Line_XY_FractBits>(point1.x - point0.x, dk);
step.dy_dk = LineDivide<int64, Line_XY_FractBits>(point1.y - point0.y, dk);
if(goraud)
{
step.dr_dk = LineDivide<int32, Line_RGB_FractBits>(point1.r - point0.r, dk);
step.dg_dk = LineDivide<int32, Line_RGB_FractBits>(point1.g - point0.g, dk);
step.db_dk = LineDivide<int32, Line_RGB_FractBits>(point1.b - point0.b, dk);
}
}
template<bool goraud>
static INLINE void AddLineStep(line_fxp_coord &point, const line_fxp_step &step, int32 count = 1)
{
point.x += step.dx_dk * count;
point.y += step.dy_dk * count;
if(goraud)
{
point.r += step.dr_dk * count;
point.g += step.dg_dk * count;
point.b += step.db_dk * count;
}
}
template<bool goraud, int BlendMode, bool MaskEval_TA>
void PS_GPU::DrawLine(line_point *points)
{
int32 i_dx;
int32 i_dy;
int32 k;
line_fxp_coord cur_point;
line_fxp_step step;
i_dx = abs(points[1].x - points[0].x);
i_dy = abs(points[1].y - points[0].y);
k = (i_dx > i_dy) ? i_dx : i_dy;
if(i_dx >= 1024)
{
//PSX_WARNING("[GPU] Line too long: i_dx=%d", i_dx);
return;
}
if(i_dy >= 512)
{
//PSX_WARNING("[GPU] Line too long: i_dy=%d", i_dy);
return;
}
// May not be correct(do tests for the case of k == i_dy on real thing.
if(points[0].x > points[1].x)
{
line_point tmp = points[1];
points[1] = points[0];
points[0] = tmp;
}
DrawTimeAvail -= k * ((BlendMode >= 0) ? 2 : 1);
//
//
//
LinePointsToFXPStep<goraud>(points[0], points[1], k, step);
LinePointToFXPCoord<goraud>(points[0], step, cur_point);
//
//
//
for(int32 i = 0; i <= k; i++) // <= is not a typo.
{
// Sign extension is not necessary here for x and y, due to the maximum values that ClipX1 and ClipY1 can contain.
const int32 x = (cur_point.x >> Line_XY_FractBits) & 2047;
const int32 y = (cur_point.y >> Line_XY_FractBits) & 2047;
uint16 pix = 0x8000;
if(!LineSkipTest(y))
{
uint8 r, g, b;
if(goraud)
{
r = cur_point.r >> Line_RGB_FractBits;
g = cur_point.g >> Line_RGB_FractBits;
b = cur_point.b >> Line_RGB_FractBits;
}
else
{
r = points[0].r;
g = points[0].g;
b = points[0].b;
}
if(goraud && dtd)
{
pix |= DitherLUT[y & 3][x & 3][r] << 0;
pix |= DitherLUT[y & 3][x & 3][g] << 5;
pix |= DitherLUT[y & 3][x & 3][b] << 10;
}
else
{
pix |= (r >> 3) << 0;
pix |= (g >> 3) << 5;
pix |= (b >> 3) << 10;
}
// FIXME: There has to be a faster way than checking for being inside the drawing area for each pixel.
if(x >= ClipX0 && x <= ClipX1 && y >= ClipY0 && y <= ClipY1)
PlotPixel<BlendMode, MaskEval_TA, false>(x, y, pix);
}
AddLineStep<goraud>(cur_point, step);
}
}
template<bool polyline, bool goraud, int BlendMode, bool MaskEval_TA>
void PS_GPU::Command_DrawLine(const uint32 *cb)
{
const uint8 cc = cb[0] >> 24; // For pline handling later.
line_point points[2];
DrawTimeAvail -= 16; // FIXME, correct time.
if(polyline && InCmd == INCMD_PLINE)
{
//printf("PLINE N\n");
points[0] = InPLine_PrevPoint;
}
else
{
points[0].r = (*cb >> 0) & 0xFF;
points[0].g = (*cb >> 8) & 0xFF;
points[0].b = (*cb >> 16) & 0xFF;
cb++;
points[0].x = sign_x_to_s32(11, ((*cb >> 0) & 0xFFFF)) + OffsX;
points[0].y = sign_x_to_s32(11, ((*cb >> 16) & 0xFFFF)) + OffsY;
cb++;
}
if(goraud)
{
points[1].r = (*cb >> 0) & 0xFF;
points[1].g = (*cb >> 8) & 0xFF;
points[1].b = (*cb >> 16) & 0xFF;
cb++;
}
else
{
points[1].r = points[0].r;
points[1].g = points[0].g;
points[1].b = points[0].b;
}
points[1].x = sign_x_to_s32(11, ((*cb >> 0) & 0xFFFF)) + OffsX;
points[1].y = sign_x_to_s32(11, ((*cb >> 16) & 0xFFFF)) + OffsY;
cb++;
if(polyline)
{
InPLine_PrevPoint = points[1];
if(InCmd != INCMD_PLINE)
{
InCmd = INCMD_PLINE;
InCmd_CC = cc;
}
}
DrawLine<goraud, BlendMode, MaskEval_TA>(points);
}

View File

@ -0,0 +1,489 @@
struct i_group
{
int32 u, v;
int32 r, g, b;
int32 dummy0[3];
};
struct i_deltas
{
int32 du_dx, dv_dx;
int32 dr_dx, dg_dx, db_dx;
int32 dummy0[3];
int32 du_dy, dv_dy;
int32 dr_dy, dg_dy, db_dy;
int32 dummy1[3];
};
static INLINE int64 MakePolyXFP(int32 x)
{
return ((int64)x << 32) + ((1LL << 32) - (1 << 11));
}
static INLINE int64 MakePolyXFPStep(int32 dx, int32 dy)
{
int64 ret;
int64 dx_ex = (int64)dx << 32;
if(dx_ex < 0)
dx_ex -= dy - 1;
if(dx_ex > 0)
dx_ex += dy - 1;
ret = dx_ex / dy;
return(ret);
}
static INLINE int32 GetPolyXFP_Int(int64 xfp)
{
return(xfp >> 32);
}
//#define CALCIS(x,y) ( A.x * (B.y - C.y) + B.x * (C.y - A.y) + C.x * (A.y - B.y) )
#define CALCIS(x,y) (((B.x - A.x) * (C.y - B.y)) - ((C.x - B.x) * (B.y - A.y)))
static INLINE bool CalcIDeltas(i_deltas &idl, const tri_vertex &A, const tri_vertex &B, const tri_vertex &C)
{
int64 num = ((int64)COORD_MF_INT(1)) << 32;
int64 denom = CALCIS(x, y);
int64 one_div;
if(!denom)
return(false);
//num -= abs(denom) - 1;
// num += abs(denom) >> 1;
one_div = num / denom;
idl.dr_dx = ((one_div * CALCIS(r, y)) + 0x00000000) >> 32;
idl.dr_dy = ((one_div * CALCIS(x, r)) + 0x00000000) >> 32;
idl.dg_dx = ((one_div * CALCIS(g, y)) + 0x00000000) >> 32;
idl.dg_dy = ((one_div * CALCIS(x, g)) + 0x00000000) >> 32;
idl.db_dx = ((one_div * CALCIS(b, y)) + 0x00000000) >> 32;
idl.db_dy = ((one_div * CALCIS(x, b)) + 0x00000000) >> 32;
idl.du_dx = ((one_div * CALCIS(u, y)) + 0x00000000) >> 32;
idl.du_dy = ((one_div * CALCIS(x, u)) + 0x00000000) >> 32;
idl.dv_dx = ((one_div * CALCIS(v, y)) + 0x00000000) >> 32;
idl.dv_dy = ((one_div * CALCIS(x, v)) + 0x00000000) >> 32;
// printf(" du_dx=%08x, du_dy=%08x\n", idl.du_dx, idl.du_dy);
return(true);
}
#undef CALCIS
template<bool goraud, bool textured>
static INLINE void AddIDeltas_DX(i_group &ig, const i_deltas &idl)
{
if(textured)
{
ig.u += idl.du_dx;
ig.v += idl.dv_dx;
}
if(goraud)
{
ig.r += idl.dr_dx;
ig.g += idl.dg_dx;
ig.b += idl.db_dx;
}
}
template<bool goraud, bool textured>
static INLINE void AddIDeltas_DY(i_group &ig, const i_deltas &idl, int32 count = 1)
{
if(textured)
{
ig.u += idl.du_dy * count;
ig.v += idl.dv_dy * count;
}
if(goraud)
{
ig.r += idl.dr_dy * count;
ig.g += idl.dg_dy * count;
ig.b += idl.db_dy * count;
}
}
template<bool goraud, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
INLINE void PS_GPU::DrawSpan(int y, uint32 clut_offset, const int32 x_start, const int32 x_bound, const int32 bv_x, i_group ig, const i_deltas &idl)
{
int32 xs = x_start, xb = x_bound;
if(LineSkipTest(y))
return;
if(xs < xb) // (xs != xb)
{
if(xs < ClipX0)
xs = ClipX0;
if(xb > (ClipX1 + 1))
xb = ClipX1 + 1;
if(xs < xb)
{
DrawTimeAvail -= (xb - xs);
if(goraud || textured)
{
DrawTimeAvail -= (xb - xs);
}
else if((BlendMode >= 0) || MaskEval_TA)
{
DrawTimeAvail -= (((xb + 1) & ~1) - (xs & ~1)) >> 1;
}
}
if(textured)
{
ig.u += (xs - bv_x) * idl.du_dx;
ig.v += (xs - bv_x) * idl.dv_dx;
}
if(goraud)
{
ig.r += (xs - bv_x) * idl.dr_dx;
ig.g += (xs - bv_x) * idl.dg_dx;
ig.b += (xs - bv_x) * idl.db_dx;
}
for(int32 x = xs; x < xb; x++)
{
uint32 r, g, b;
if(goraud)
{
r = RGB8SAT[COORD_GET_INT(ig.r)];
g = RGB8SAT[COORD_GET_INT(ig.g)];
b = RGB8SAT[COORD_GET_INT(ig.b)];
}
else
{
r = COORD_GET_INT(ig.r);
g = COORD_GET_INT(ig.g);
b = COORD_GET_INT(ig.b);
}
if(textured)
{
uint16 fbw = GetTexel<TexMode_TA>(clut_offset, COORD_GET_INT(ig.u), COORD_GET_INT(ig.v));
if(fbw)
{
if(TexMult)
{
if(dtd)
fbw = ModTexel(fbw, r, g, b, x & 3, y & 3);
else
fbw = ModTexel(fbw, r, g, b, 3, 2); //x & 3, y & 3);
}
PlotPixel<BlendMode, MaskEval_TA, true>(x, y, fbw);
}
}
else
{
uint16 pix = 0x8000;
if(goraud && dtd)
{
pix |= DitherLUT[y & 3][x & 3][r] << 0;
pix |= DitherLUT[y & 3][x & 3][g] << 5;
pix |= DitherLUT[y & 3][x & 3][b] << 10;
}
else
{
pix |= (r >> 3) << 0;
pix |= (g >> 3) << 5;
pix |= (b >> 3) << 10;
}
PlotPixel<BlendMode, MaskEval_TA, false>(x, y, pix);
}
AddIDeltas_DX<goraud, textured>(ig, idl);
//AddStep<goraud, textured>(perp_coord, perp_step);
}
}
}
template<bool goraud, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
void PS_GPU::DrawTriangle(tri_vertex *vertices, uint32 clut)
{
i_deltas idl;
#if 0
vertices[0].y = COORD_MF_INT(rand());
vertices[1].y = COORD_MF_INT(rand());
vertices[2].y = COORD_MF_INT(rand());
vertices[0].x = COORD_MF_INT(rand());
vertices[1].x = COORD_MF_INT(rand());
vertices[2].x = COORD_MF_INT(rand());
#endif
if(vertices[2].y < vertices[1].y)
{
tri_vertex tmp = vertices[1];
vertices[1] = vertices[2];
vertices[2] = tmp;
}
if(vertices[1].y < vertices[0].y)
{
tri_vertex tmp = vertices[0];
vertices[0] = vertices[1];
vertices[1] = tmp;
}
if(vertices[2].y < vertices[1].y)
{
tri_vertex tmp = vertices[1];
vertices[1] = vertices[2];
vertices[2] = tmp;
}
if(vertices[0].y == vertices[2].y)
return;
if((vertices[2].y - vertices[0].y) >= 512)
{
//PSX_WARNING("[GPU] Triangle height too large: %d", (vertices[2].y - vertices[0].y));
return;
}
if(abs(vertices[2].x - vertices[0].x) >= 1024 ||
abs(vertices[2].x - vertices[1].x) >= 1024 ||
abs(vertices[1].x - vertices[0].x) >= 1024)
{
//PSX_WARNING("[GPU] Triangle width too large: %d %d %d", abs(vertices[2].x - vertices[0].x), abs(vertices[2].x - vertices[1].x), abs(vertices[1].x - vertices[0].x));
return;
}
if(!CalcIDeltas(idl, vertices[0], vertices[1], vertices[2]))
return;
// [0] should be top vertex, [2] should be bottom vertex, [1] should be off to the side vertex.
//
//
int32 y_start = vertices[0].y;
int32 y_middle = vertices[1].y;
int32 y_bound = vertices[2].y;
int64 base_coord;
int64 base_step;
int64 bound_coord_ul;
int64 bound_coord_us;
int64 bound_coord_ll;
int64 bound_coord_ls;
bool right_facing;
//bool bottom_up;
i_group ig;
ig.u = COORD_MF_INT(vertices[0].u) + (1 << (COORD_FBS - 1));
ig.v = COORD_MF_INT(vertices[0].v) + (1 << (COORD_FBS - 1));
ig.r = COORD_MF_INT(vertices[0].r);
ig.g = COORD_MF_INT(vertices[0].g);
ig.b = COORD_MF_INT(vertices[0].b);
base_coord = MakePolyXFP(vertices[0].x); //COORD_MF_INT(vertices[0].x) + ((1 << COORD_FBS) - 1);
base_step = MakePolyXFPStep((vertices[2].x - vertices[0].x), (vertices[2].y - vertices[0].y)); //ROUND_HELPER(COORD_MF_INT(vertices[2].x - vertices[0].x), (vertices[2].y - vertices[0].y));
bound_coord_ul = MakePolyXFP(vertices[0].x); // + ((1 << COORD_FBS) - 1);
bound_coord_ll = MakePolyXFP(vertices[1].x); // + ((1 << COORD_FBS) - 1);
//
//
//
if(vertices[1].y == vertices[0].y)
{
bound_coord_us = 0;
right_facing = (bool)(vertices[1].x > vertices[0].x);
}
else
{
bound_coord_us = MakePolyXFPStep((vertices[1].x - vertices[0].x), (vertices[1].y - vertices[0].y));
right_facing = (bool)(bound_coord_us > base_step);
}
if(vertices[2].y == vertices[1].y)
bound_coord_ls = 0;
else
bound_coord_ls = MakePolyXFPStep((vertices[2].x - vertices[1].x), (vertices[2].y - vertices[1].y));
if(y_start < ClipY0)
{
int32 count = ClipY0 - y_start;
y_start = ClipY0;
base_coord += base_step * count;
bound_coord_ul += bound_coord_us * count;
AddIDeltas_DY<goraud, textured>(ig, idl, count);
if(y_middle < ClipY0)
{
int32 count_ls = ClipY0 - y_middle;
y_middle = ClipY0;
bound_coord_ll += bound_coord_ls * count_ls;
}
}
if(y_bound > (ClipY1 + 1))
{
y_bound = ClipY1 + 1;
if(y_middle > y_bound)
y_middle = y_bound;
}
if(right_facing)
{
for(int32 y = y_start; y < y_middle; y++)
{
DrawSpan<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(y, clut, GetPolyXFP_Int(base_coord), GetPolyXFP_Int(bound_coord_ul), vertices[0].x, ig, idl);
base_coord += base_step;
bound_coord_ul += bound_coord_us;
AddIDeltas_DY<goraud, textured>(ig, idl);
}
for(int32 y = y_middle; y < y_bound; y++)
{
DrawSpan<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(y, clut, GetPolyXFP_Int(base_coord), GetPolyXFP_Int(bound_coord_ll), vertices[0].x, ig, idl);
base_coord += base_step;
bound_coord_ll += bound_coord_ls;
AddIDeltas_DY<goraud, textured>(ig, idl);
}
}
else
{
for(int32 y = y_start; y < y_middle; y++)
{
DrawSpan<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(y, clut, GetPolyXFP_Int(bound_coord_ul), GetPolyXFP_Int(base_coord), vertices[0].x, ig, idl);
base_coord += base_step;
bound_coord_ul += bound_coord_us;
AddIDeltas_DY<goraud, textured>(ig, idl);
}
for(int32 y = y_middle; y < y_bound; y++)
{
DrawSpan<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(y, clut, GetPolyXFP_Int(bound_coord_ll), GetPolyXFP_Int(base_coord), vertices[0].x, ig, idl);
base_coord += base_step;
bound_coord_ll += bound_coord_ls;
AddIDeltas_DY<goraud, textured>(ig, idl);
}
}
#if 0
printf("[GPU] Vertices: %d:%d(r=%d, g=%d, b=%d) -> %d:%d(r=%d, g=%d, b=%d) -> %d:%d(r=%d, g=%d, b=%d)\n\n\n", vertices[0].x, vertices[0].y,
vertices[0].r, vertices[0].g, vertices[0].b,
vertices[1].x, vertices[1].y,
vertices[1].r, vertices[1].g, vertices[1].b,
vertices[2].x, vertices[2].y,
vertices[2].r, vertices[2].g, vertices[2].b);
#endif
}
template<int numvertices, bool goraud, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
void PS_GPU::Command_DrawPolygon(const uint32 *cb)
{
const unsigned cb0 = cb[0];
tri_vertex vertices[3];
uint32 clut = 0;
unsigned sv = 0;
//uint32 tpage = 0;
// Base timing is approximate, and could be improved.
if(numvertices == 4 && InCmd == INCMD_QUAD)
DrawTimeAvail -= (28 + 18);
else
DrawTimeAvail -= (64 + 18);
if(goraud && textured)
DrawTimeAvail -= 150 * 3;
else if(goraud)
DrawTimeAvail -= 96 * 3;
else if(textured)
DrawTimeAvail -= 60 * 3;
if(numvertices == 4)
{
if(InCmd == INCMD_QUAD)
{
memcpy(&vertices[0], &InQuad_F3Vertices[1], 2 * sizeof(tri_vertex));
clut = InQuad_clut;
sv = 2;
}
}
//else
// memset(vertices, 0, sizeof(vertices));
for(unsigned v = sv; v < 3; v++)
{
if(v == 0 || goraud)
{
uint32 raw_color = (*cb & 0xFFFFFF);
vertices[v].r = raw_color & 0xFF;
vertices[v].g = (raw_color >> 8) & 0xFF;
vertices[v].b = (raw_color >> 16) & 0xFF;
cb++;
}
else
{
vertices[v].r = vertices[0].r;
vertices[v].g = vertices[0].g;
vertices[v].b = vertices[0].b;
}
vertices[v].x = sign_x_to_s32(11, ((int16)(*cb & 0xFFFF))) + OffsX;
vertices[v].y = sign_x_to_s32(11, ((int16)(*cb >> 16))) + OffsY;
cb++;
if(textured)
{
vertices[v].u = (*cb & 0xFF);
vertices[v].v = (*cb >> 8) & 0xFF;
if(v == 0)
{
clut = ((*cb >> 16) & 0xFFFF) << 4;
}
cb++;
}
}
if(numvertices == 4)
{
if(InCmd == INCMD_QUAD)
{
InCmd = INCMD_NONE;
}
else
{
InCmd = INCMD_QUAD;
InCmd_CC = cb0 >> 24;
memcpy(&InQuad_F3Vertices[0], &vertices[0], sizeof(tri_vertex) * 3);
InQuad_clut = clut;
}
}
DrawTriangle<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(vertices, clut);
}

View File

@ -0,0 +1,232 @@
template<bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA, bool FlipX, bool FlipY>
void PS_GPU::DrawSprite(int32 x_arg, int32 y_arg, int32 w, int32 h, uint8 u_arg, uint8 v_arg, uint32 color, uint32 clut_offset)
{
const int32 r = color & 0xFF;
const int32 g = (color >> 8) & 0xFF;
const int32 b = (color >> 16) & 0xFF;
const uint16 fill_color = 0x8000 | ((r >> 3) << 0) | ((g >> 3) << 5) | ((b >> 3) << 10);
int32 x_start, x_bound;
int32 y_start, y_bound;
uint8 u, v;
int v_inc = 1, u_inc = 1;
//printf("[GPU] Sprite: x=%d, y=%d, w=%d, h=%d\n", x_arg, y_arg, w, h);
x_start = x_arg;
x_bound = x_arg + w;
y_start = y_arg;
y_bound = y_arg + h;
if(textured)
{
u = u_arg;
v = v_arg;
if(FlipX)
{
u_inc = -1;
u |= 1;
}
// FIXME: Something weird happens when lower bit of u is set and we're not doing horizontal flip, but I'm not sure what it is exactly(needs testing)
// It may only happen to the first pixel, so look for that case too during testing.
//else
// u = (u + 1) & ~1;
if(FlipY)
{
v_inc = -1;
}
}
if(x_start < ClipX0)
{
if(textured)
u += (ClipX0 - x_start) * u_inc;
x_start = ClipX0;
}
if(y_start < ClipY0)
{
if(textured)
v += (ClipY0 - y_start) * v_inc;
y_start = ClipY0;
}
if(x_bound > (ClipX1 + 1))
x_bound = ClipX1 + 1;
if(y_bound > (ClipY1 + 1))
y_bound = ClipY1 + 1;
if(y_bound > y_start && x_bound > x_start)
{
//
// Note(TODO): From tests on a PS1, even a 0-width sprite takes up time to "draw" proportional to its height.
//
int32 suck_time = (x_bound - x_start) * (y_bound - y_start);
// Disabled until we can get it to take into account texture windowing, which can cause large sprites to be drawn entirely from cache(and not suffer from a texturing
// penalty); and disabled until we find a game that needs more accurate sprite draw timing. :b
#if 0
if(textured)
{
// Empirically-observed approximations of time(66MHz cycles) taken to draw large textured sprites in the various texture depths, when the texture data and CLUT data
// was zero(non-zero takes longer to draw, TODO test that more):
// 4bpp - area * 2
// 8bpp - area * 3
// 15/16bpp - area * 5
// (other factors come into more importance for smaller sprites)
static const int cw[4] = { 64, 32, 32, 32 };
static const int ch[4] = { 64, 64, 32, 32 };
static const int mm[4] = { 2 - 1, 3 - 1, 5 - 1, 5 - 1 };
// Parts of the first few(up to texture cache height) horizontal lines can be in cache, so assume they are.
suck_time += mm[TexMode_TA] * std::max<int>(0, (x_bound - x_start) - cw[TexMode_TA]) * std::min<int>(ch[TexMode_TA], y_bound - y_start);
// The rest of the horizontal lines should not possibly have parts in the cache now.
suck_time += mm[TexMode_TA] * (x_bound - x_start) * std::max<int>(0, (y_bound - y_start) - ch[TexMode_TA]);
}
else
#endif
if((BlendMode >= 0) || MaskEval_TA)
{
suck_time += ((((x_bound + 1) & ~1) - (x_start & ~1)) * (y_bound - y_start)) >> 1;
}
DrawTimeAvail -= suck_time;
}
//HeightMode && !dfe && ((y & 1) == ((DisplayFB_YStart + !field_atvs) & 1)) && !DisplayOff
//printf("%d:%d, %d, %d ---- heightmode=%d displayfb_ystart=%d field_atvs=%d displayoff=%d\n", w, h, scanline, dfe, HeightMode, DisplayFB_YStart, field_atvs, DisplayOff);
for(int32 y = y_start; y < y_bound; y++)
{
uint8 u_r;
if(textured)
u_r = u;
if(!LineSkipTest(y))
{
for(int32 x = x_start; x < x_bound; x++)
{
if(textured)
{
uint16 fbw = GetTexel<TexMode_TA>(clut_offset, u_r, v);
if(fbw)
{
if(TexMult)
{
fbw = ModTexel(fbw, r, g, b, 3, 2);
}
PlotPixel<BlendMode, MaskEval_TA, true>(x, y, fbw);
}
}
else
PlotPixel<BlendMode, MaskEval_TA, false>(x, y, fill_color);
if(textured)
u_r += u_inc;
}
}
if(textured)
v += v_inc;
}
}
template<uint8 raw_size, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
void PS_GPU::Command_DrawSprite(const uint32 *cb)
{
int32 x, y;
int32 w, h;
uint8 u = 0, v = 0;
uint32 color = 0;
uint32 clut = 0;
DrawTimeAvail -= 16; // FIXME, correct time.
color = *cb & 0x00FFFFFF;
cb++;
x = sign_x_to_s32(11, (*cb & 0xFFFF));
y = sign_x_to_s32(11, (*cb >> 16));
cb++;
if(textured)
{
u = *cb & 0xFF;
v = (*cb >> 8) & 0xFF;
clut = ((*cb >> 16) & 0xFFFF) << 4;
cb++;
}
switch(raw_size)
{
default:
case 0:
w = (*cb & 0x3FF);
h = (*cb >> 16) & 0x1FF;
cb++;
break;
case 1:
w = 1;
h = 1;
break;
case 2:
w = 8;
h = 8;
break;
case 3:
w = 16;
h = 16;
break;
}
//printf("SPRITE: %d %d %d -- %d %d\n", raw_size, x, y, w, h);
x = sign_x_to_s32(11, x + OffsX);
y = sign_x_to_s32(11, y + OffsY);
switch(SpriteFlip & 0x3000)
{
case 0x0000:
if(!TexMult || color == 0x808080)
DrawSprite<textured, BlendMode, false, TexMode_TA, MaskEval_TA, false, false>(x, y, w, h, u, v, color, clut);
else
DrawSprite<textured, BlendMode, true, TexMode_TA, MaskEval_TA, false, false>(x, y, w, h, u, v, color, clut);
break;
case 0x1000:
if(!TexMult || color == 0x808080)
DrawSprite<textured, BlendMode, false, TexMode_TA, MaskEval_TA, true, false>(x, y, w, h, u, v, color, clut);
else
DrawSprite<textured, BlendMode, true, TexMode_TA, MaskEval_TA, true, false>(x, y, w, h, u, v, color, clut);
break;
case 0x2000:
if(!TexMult || color == 0x808080)
DrawSprite<textured, BlendMode, false, TexMode_TA, MaskEval_TA, false, true>(x, y, w, h, u, v, color, clut);
else
DrawSprite<textured, BlendMode, true, TexMode_TA, MaskEval_TA, false, true>(x, y, w, h, u, v, color, clut);
break;
case 0x3000:
if(!TexMult || color == 0x808080)
DrawSprite<textured, BlendMode, false, TexMode_TA, MaskEval_TA, true, true>(x, y, w, h, u, v, color, clut);
else
DrawSprite<textured, BlendMode, true, TexMode_TA, MaskEval_TA, true, true>(x, y, w, h, u, v, color, clut);
break;
}
}

1739
mednafen/psx-0925/gte.cpp Normal file

File diff suppressed because it is too large Load Diff

21
mednafen/psx-0925/gte.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef __MDFN_PSX_GTE_H
#define __MDFN_PSX_GTE_H
namespace MDFN_IEN_PSX
{
void GTE_Power(void);
int GTE_StateAction(StateMem *sm, int load, int data_only);
int32 GTE_Instruction(uint32 instr);
void GTE_WriteCR(unsigned int which, uint32 value);
void GTE_WriteDR(unsigned int which, uint32 value);
uint32 GTE_ReadCR(unsigned int which);
uint32 GTE_ReadDR(unsigned int which);
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,285 @@
#include "../psx.h"
#include "../frontio.h"
#include "dualanalog.h"
namespace MDFN_IEN_PSX
{
class InputDevice_DualAnalog : public InputDevice
{
public:
InputDevice_DualAnalog(bool joystick_mode_);
virtual ~InputDevice_DualAnalog();
virtual void Power(void);
virtual void UpdateInput(const void *data);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void);
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
private:
bool joystick_mode;
bool dtr;
uint8 buttons[2];
uint8 axes[2][2];
int32 command_phase;
uint32 bitpos;
uint8 receive_buffer;
uint8 command;
uint8 transmit_buffer[8];
uint32 transmit_pos;
uint32 transmit_count;
};
InputDevice_DualAnalog::InputDevice_DualAnalog(bool joystick_mode_) : joystick_mode(joystick_mode_)
{
Power();
}
InputDevice_DualAnalog::~InputDevice_DualAnalog()
{
}
void InputDevice_DualAnalog::Power(void)
{
dtr = 0;
buttons[0] = buttons[1] = 0;
command_phase = 0;
bitpos = 0;
receive_buffer = 0;
command = 0;
memset(transmit_buffer, 0, sizeof(transmit_buffer));
transmit_pos = 0;
transmit_count = 0;
}
void InputDevice_DualAnalog::UpdateInput(const void *data)
{
uint8 *d8 = (uint8 *)data;
buttons[0] = d8[0];
buttons[1] = d8[1];
for(int stick = 0; stick < 2; stick++)
{
for(int axis = 0; axis < 2; axis++)
{
int32 tmp;
tmp = 32768 + MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 4) - ((int32)MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 8) * 32768 / 32767);
tmp >>= 8;
axes[stick][axis] = tmp;
}
}
//printf("%d %d %d %d\n", axes[0][0], axes[0][1], axes[1][0], axes[1][1]);
}
void InputDevice_DualAnalog::SetDTR(bool new_dtr)
{
if(!dtr && new_dtr)
{
command_phase = 0;
bitpos = 0;
transmit_pos = 0;
transmit_count = 0;
}
else if(dtr && !new_dtr)
{
//if(bitpos || transmit_count)
// printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
dtr = new_dtr;
}
bool InputDevice_DualAnalog::GetDSR(void)
{
if(!dtr)
return(0);
if(!bitpos && transmit_count)
return(1);
return(0);
}
bool InputDevice_DualAnalog::Clock(bool TxD, int32 &dsr_pulse_delay)
{
bool ret = 1;
dsr_pulse_delay = 0;
if(!dtr)
return(1);
if(transmit_count)
ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
receive_buffer &= ~(1 << bitpos);
receive_buffer |= TxD << bitpos;
bitpos = (bitpos + 1) & 0x7;
if(!bitpos)
{
//printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
if(transmit_count)
{
transmit_pos++;
transmit_count--;
}
switch(command_phase)
{
case 0:
if(receive_buffer != 0x01)
command_phase = -1;
else
{
transmit_buffer[0] = joystick_mode ? 0x53 : 0x73;
transmit_pos = 0;
transmit_count = 1;
command_phase++;
}
break;
case 1:
command = receive_buffer;
command_phase++;
transmit_buffer[0] = 0x5A;
//if(command != 0x42)
// fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command);
if(command == 0x42)
{
transmit_buffer[1] = 0xFF ^ buttons[0];
transmit_buffer[2] = 0xFF ^ buttons[1];
transmit_buffer[3] = axes[0][0];
transmit_buffer[4] = axes[0][1];
transmit_buffer[5] = axes[1][0];
transmit_buffer[6] = axes[1][1];
transmit_pos = 0;
transmit_count = 7;
}
else
{
command_phase = -1;
transmit_buffer[1] = 0;
transmit_buffer[2] = 0;
transmit_pos = 0;
transmit_count = 0;
}
break;
case 2:
//if(receive_buffer)
// printf("%d: %02x\n", 7 - transmit_count, receive_buffer);
break;
}
}
if(!bitpos && transmit_count)
dsr_pulse_delay = 0x40; //0x100;
return(ret);
}
InputDevice *Device_DualAnalog_Create(bool joystick_mode)
{
return new InputDevice_DualAnalog(joystick_mode);
}
InputDeviceInputInfoStruct Device_DualAnalog_IDII[24] =
{
{ "select", "SELECT", 4, IDIT_BUTTON, NULL },
{ "l3", "Left Stick, Button(L3)", 18, IDIT_BUTTON, NULL },
{ "r3", "Right stick, Button(R3)", 23, IDIT_BUTTON, NULL },
{ "start", "START", 5, IDIT_BUTTON, NULL },
{ "up", "D-Pad UP ↑", 0, IDIT_BUTTON, "down" },
{ "right", "D-Pad RIGHT →", 3, IDIT_BUTTON, "left" },
{ "down", "D-Pad DOWN ↓", 1, IDIT_BUTTON, "up" },
{ "left", "D-Pad LEFT ←", 2, IDIT_BUTTON, "right" },
{ "l2", "L2 (rear left shoulder)", 11, IDIT_BUTTON, NULL },
{ "r2", "R2 (rear right shoulder)", 13, IDIT_BUTTON, NULL },
{ "l1", "L1 (front left shoulder)", 10, IDIT_BUTTON, NULL },
{ "r1", "R1 (front right shoulder)", 12, IDIT_BUTTON, NULL },
{ "triangle", "△ (upper)", 6, IDIT_BUTTON_CAN_RAPID, NULL },
{ "circle", "○ (right)", 9, IDIT_BUTTON_CAN_RAPID, NULL },
{ "cross", "x (lower)", 7, IDIT_BUTTON_CAN_RAPID, NULL },
{ "square", "□ (left)", 8, IDIT_BUTTON_CAN_RAPID, NULL },
{ "rstick_right", "Right Stick RIGHT →", 22, IDIT_BUTTON_ANALOG },
{ "rstick_left", "Right Stick LEFT ←", 21, IDIT_BUTTON_ANALOG },
{ "rstick_down", "Right Stick DOWN ↓", 20, IDIT_BUTTON_ANALOG },
{ "rstick_up", "Right Stick UP ↑", 19, IDIT_BUTTON_ANALOG },
{ "lstick_right", "Left Stick RIGHT →", 17, IDIT_BUTTON_ANALOG },
{ "lstick_left", "Left Stick LEFT ←", 16, IDIT_BUTTON_ANALOG },
{ "lstick_down", "Left Stick DOWN ↓", 15, IDIT_BUTTON_ANALOG },
{ "lstick_up", "Left Stick UP ↑", 14, IDIT_BUTTON_ANALOG },
};
// Not sure if all these buttons are named correctly!
InputDeviceInputInfoStruct Device_AnalogJoy_IDII[24] =
{
{ "select", "SELECT", 8, IDIT_BUTTON, NULL },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ "start", "START", 9, IDIT_BUTTON, NULL },
{ "up", "Thumbstick UP ↑", 14, IDIT_BUTTON, "down" },
{ "right", "Thumbstick RIGHT →", 17, IDIT_BUTTON, "left" },
{ "down", "Thumbstick DOWN ↓", 15, IDIT_BUTTON, "up" },
{ "left", "Thumbstick LEFT ←", 16, IDIT_BUTTON, "right" },
{ "l2", "Left stick, Trigger", 2, IDIT_BUTTON, NULL },
{ "r2", "Left stick, Pinky", 3, IDIT_BUTTON, NULL },
{ "l1", "Left stick, L-thumb", 0, IDIT_BUTTON, NULL },
{ "r1", "Left stick, R-thumb", 1, IDIT_BUTTON, NULL },
{ "triangle", "Right stick, Pinky", 13, IDIT_BUTTON, NULL },
{ "circle", "Right stick, R-thumb", 11, IDIT_BUTTON, NULL },
{ "cross", "Right stick, L-thumb", 10, IDIT_BUTTON, NULL },
{ "square", "Right stick, Trigger", 12, IDIT_BUTTON, NULL },
{ "rstick_right", "Right Stick, RIGHT →", 21, IDIT_BUTTON_ANALOG },
{ "rstick_left", "Right Stick, LEFT ←", 20, IDIT_BUTTON_ANALOG },
{ "rstick_down", "Right Stick, BACK ↓", 19, IDIT_BUTTON_ANALOG },
{ "rstick_up", "Right Stick, FORE ↑", 18, IDIT_BUTTON_ANALOG },
{ "lstick_right", "Left Stick, RIGHT →", 7, IDIT_BUTTON_ANALOG },
{ "lstick_left", "Left Stick, LEFT ←", 6, IDIT_BUTTON_ANALOG },
{ "lstick_down", "Left Stick, BACK ↓", 5, IDIT_BUTTON_ANALOG },
{ "lstick_up", "Left Stick, FORE ↑", 4, IDIT_BUTTON_ANALOG },
};
}

View File

@ -0,0 +1,11 @@
#ifndef __MDFN_PSX_INPUT_DUALANALOG_H
#define __MDFN_PSX_INPUT_DUALANALOG_H
namespace MDFN_IEN_PSX
{
InputDevice *Device_DualAnalog_Create(bool joystick_mode);
extern InputDeviceInputInfoStruct Device_DualAnalog_IDII[24];
extern InputDeviceInputInfoStruct Device_AnalogJoy_IDII[24];
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
#ifndef __MDFN_PSX_INPUT_DUALSHOCK_H
#define __MDFN_PSX_INPUT_DUALSHOCK_H
#include <string>
namespace MDFN_IEN_PSX
{
InputDevice *Device_DualShock_Create(const std::string &name);
extern InputDeviceInputInfoStruct Device_DualShock_IDII[26];
}
#endif

View File

@ -0,0 +1,216 @@
#include "../psx.h"
#include "../frontio.h"
#include "gamepad.h"
namespace MDFN_IEN_PSX
{
class InputDevice_Gamepad : public InputDevice
{
public:
InputDevice_Gamepad();
virtual ~InputDevice_Gamepad();
virtual void Power(void);
virtual void UpdateInput(const void *data);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void);
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
private:
bool dtr;
uint8 buttons[2];
int32 command_phase;
uint32 bitpos;
uint8 receive_buffer;
uint8 command;
uint8 transmit_buffer[3];
uint32 transmit_pos;
uint32 transmit_count;
};
InputDevice_Gamepad::InputDevice_Gamepad()
{
Power();
}
InputDevice_Gamepad::~InputDevice_Gamepad()
{
}
void InputDevice_Gamepad::Power(void)
{
dtr = 0;
buttons[0] = buttons[1] = 0;
command_phase = 0;
bitpos = 0;
receive_buffer = 0;
command = 0;
memset(transmit_buffer, 0, sizeof(transmit_buffer));
transmit_pos = 0;
transmit_count = 0;
}
void InputDevice_Gamepad::UpdateInput(const void *data)
{
uint8 *d8 = (uint8 *)data;
buttons[0] = d8[0];
buttons[1] = d8[1];
}
void InputDevice_Gamepad::SetDTR(bool new_dtr)
{
if(!dtr && new_dtr)
{
command_phase = 0;
bitpos = 0;
transmit_pos = 0;
transmit_count = 0;
}
else if(dtr && !new_dtr)
{
//if(bitpos || transmit_count)
// printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
dtr = new_dtr;
}
bool InputDevice_Gamepad::GetDSR(void)
{
if(!dtr)
return(0);
if(!bitpos && transmit_count)
return(1);
return(0);
}
bool InputDevice_Gamepad::Clock(bool TxD, int32 &dsr_pulse_delay)
{
bool ret = 1;
dsr_pulse_delay = 0;
if(!dtr)
return(1);
if(transmit_count)
ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
receive_buffer &= ~(1 << bitpos);
receive_buffer |= TxD << bitpos;
bitpos = (bitpos + 1) & 0x7;
if(!bitpos)
{
//printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
if(transmit_count)
{
transmit_pos++;
transmit_count--;
}
switch(command_phase)
{
case 0:
if(receive_buffer != 0x01)
command_phase = -1;
else
{
transmit_buffer[0] = 0x41;
transmit_pos = 0;
transmit_count = 1;
command_phase++;
}
break;
case 1:
command = receive_buffer;
command_phase++;
transmit_buffer[0] = 0x5A;
//if(command != 0x42)
// fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command);
//assert(command == 0x42);
if(command == 0x42)
{
transmit_buffer[1] = 0xFF ^ buttons[0];
transmit_buffer[2] = 0xFF ^ buttons[1];
transmit_pos = 0;
transmit_count = 3;
}
else
{
command_phase = -1;
transmit_buffer[1] = 0;
transmit_buffer[2] = 0;
transmit_pos = 0;
transmit_count = 0;
}
break;
}
}
if(!bitpos && transmit_count)
dsr_pulse_delay = 0x40; //0x100;
return(ret);
}
InputDevice *Device_Gamepad_Create(void)
{
return new InputDevice_Gamepad();
}
InputDeviceInputInfoStruct Device_Gamepad_IDII[16] =
{
{ "select", "SELECT", 4, IDIT_BUTTON, NULL },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ "start", "START", 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" },
{ "l2", "L2 (rear left shoulder)", 11, IDIT_BUTTON, NULL },
{ "r2", "R2 (rear right shoulder)", 13, IDIT_BUTTON, NULL },
{ "l1", "L1 (front left shoulder)", 10, IDIT_BUTTON, NULL },
{ "r1", "R1 (front right shoulder)", 12, IDIT_BUTTON, NULL },
{ "triangle", "△ (upper)", 6, IDIT_BUTTON_CAN_RAPID, NULL },
{ "circle", "○ (right)", 9, IDIT_BUTTON_CAN_RAPID, NULL },
{ "cross", "x (lower)", 7, IDIT_BUTTON_CAN_RAPID, NULL },
{ "square", "□ (left)", 8, IDIT_BUTTON_CAN_RAPID, NULL },
};
}

View File

@ -0,0 +1,11 @@
#ifndef __MDFN_PSX_INPUT_GAMEPAD_H
#define __MDFN_PSX_INPUT_GAMEPAD_H
namespace MDFN_IEN_PSX
{
InputDevice *Device_Gamepad_Create(void);
extern InputDeviceInputInfoStruct Device_Gamepad_IDII[16];
}
#endif

View File

@ -0,0 +1,396 @@
/* 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 "../psx.h"
#include "../frontio.h"
#include "guncon.h"
namespace MDFN_IEN_PSX
{
class InputDevice_GunCon : public InputDevice
{
public:
InputDevice_GunCon(void);
virtual ~InputDevice_GunCon();
virtual void Power(void);
virtual void UpdateInput(const void *data);
virtual void SetCrosshairsColor(uint32 color);
virtual bool RequireNoFrameskip(void);
virtual pscpu_timestamp_t GPULineHook(const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void);
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
private:
bool dtr;
uint8 buttons;
bool trigger_eff;
bool trigger_noclear;
uint16 hit_x, hit_y;
int32 nom_x, nom_y;
int32 os_shot_counter;
bool prev_oss;
int32 command_phase;
uint32 bitpos;
uint8 receive_buffer;
uint8 command;
uint8 transmit_buffer[16];
uint32 transmit_pos;
uint32 transmit_count;
//
// Video timing stuff
bool prev_vsync;
int line_counter;
//
unsigned chair_r, chair_g, chair_b;
bool draw_chair;
};
InputDevice_GunCon::InputDevice_GunCon(void) : chair_r(0), chair_g(0), chair_b(0), draw_chair(false)
{
Power();
}
InputDevice_GunCon::~InputDevice_GunCon()
{
}
void InputDevice_GunCon::SetCrosshairsColor(uint32 color)
{
chair_r = (color >> 16) & 0xFF;
chair_g = (color >> 8) & 0xFF;
chair_b = (color >> 0) & 0xFF;
draw_chair = (color != (1 << 24));
}
void InputDevice_GunCon::Power(void)
{
dtr = 0;
buttons = 0;
trigger_eff = 0;
trigger_noclear = 0;
hit_x = 0;
hit_y = 0;
nom_x = 0;
nom_y = 0;
os_shot_counter = 0;
prev_oss = 0;
command_phase = 0;
bitpos = 0;
receive_buffer = 0;
command = 0;
memset(transmit_buffer, 0, sizeof(transmit_buffer));
transmit_pos = 0;
transmit_count = 0;
prev_vsync = 0;
line_counter = 0;
}
void InputDevice_GunCon::UpdateInput(const void *data)
{
uint8 *d8 = (uint8 *)data;
nom_x = MDFN_de32lsb(&d8[0]);
nom_y = MDFN_de32lsb(&d8[4]);
trigger_noclear = (bool)(d8[8] & 0x1);
trigger_eff |= trigger_noclear;
buttons = d8[8] >> 1;
if(os_shot_counter > 0) // FIXME if UpdateInput() is ever called more than once per video frame(at ~50 or ~60Hz).
os_shot_counter--;
// Eeeeiiiiiight.
if((d8[8] & 0x8) && !prev_oss && os_shot_counter == 0)
os_shot_counter = 4;
prev_oss = d8[8] & 0x8;
//MDFN_DispMessage("%08x %08x", nom_x, nom_y);
}
bool InputDevice_GunCon::RequireNoFrameskip(void)
{
return(true);
}
pscpu_timestamp_t InputDevice_GunCon::GPULineHook(const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width,
const unsigned pix_clock_offset, const unsigned pix_clock)
{
if(vsync && !prev_vsync)
line_counter = 0;
if(pixels && pix_clock)
{
const int avs = 22; // Not 22 for PAL, fixme.
int32 gx;
int32 gy;
gx = ((int64)nom_x * width / MDFNGameInfo->nominal_width + 0x8000) >> 16;
gy = (nom_y + 0x8000) >> 16;
for(int32 ix = gx; ix < (gx + (int32)(pix_clock / 762925)); ix++)
{
if(ix >= 0 && (unsigned)ix < width && line_counter >= (avs + gy) && line_counter < (avs + gy + 8))
{
int r, g, b, a;
format->DecodeColor(pixels[ix], r, g, b, a);
if((r + g + b) >= 0x40) // Wrong, but not COMPLETELY ABSOLUTELY wrong, at least. ;)
{
hit_x = (int64)(ix + pix_clock_offset) * 8000000 / pix_clock; // GunCon has what appears to be an 8.00MHz ceramic resonator in it.
hit_y = line_counter;
}
}
}
if(draw_chair)
{
if(line_counter == (avs + gy))
{
const int ic = pix_clock / 762925;
for(int32 x = std::max<int32>(0, gx - ic); x < std::min<int32>(width, gx + ic); x++)
{
int r, g, b, a;
int nr, ng, nb;
format->DecodeColor(pixels[x], r, g, b, a);
nr = (r + chair_r * 3) >> 2;
ng = (g + chair_g * 3) >> 2;
nb = (b + chair_b * 3) >> 2;
if(abs((r * 76 + g * 150 + b * 29) - (nr * 76 + ng * 150 + nb * 29)) < 16384)
{
nr >>= 1;
ng >>= 1;
nb >>= 1;
}
pixels[x] = format->MakeColor(nr, ng, nb, a);
}
}
else if(line_counter >= (avs + gy - 8) && line_counter <= (avs + gy + 8))
{
int r, g, b, a;
int nr, ng, nb;
format->DecodeColor(pixels[gx], r, g, b, a);
nr = (r + chair_r * 3) >> 2;
ng = (g + chair_g * 3) >> 2;
nb = (b + chair_b * 3) >> 2;
if(abs((r * 76 + g * 150 + b * 29) - (nr * 76 + ng * 150 + nb * 29)) < 16384)
{
nr >>= 1;
ng >>= 1;
nb >>= 1;
}
pixels[gx] = format->MakeColor(nr, ng, nb, a);
}
}
}
line_counter++;
return(PSX_EVENT_MAXTS);
}
void InputDevice_GunCon::SetDTR(bool new_dtr)
{
if(!dtr && new_dtr)
{
command_phase = 0;
bitpos = 0;
transmit_pos = 0;
transmit_count = 0;
}
else if(dtr && !new_dtr)
{
//if(bitpos || transmit_count)
// printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
dtr = new_dtr;
}
bool InputDevice_GunCon::GetDSR(void)
{
if(!dtr)
return(0);
if(!bitpos && transmit_count)
return(1);
return(0);
}
bool InputDevice_GunCon::Clock(bool TxD, int32 &dsr_pulse_delay)
{
bool ret = 1;
dsr_pulse_delay = 0;
if(!dtr)
return(1);
if(transmit_count)
ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
receive_buffer &= ~(1 << bitpos);
receive_buffer |= TxD << bitpos;
bitpos = (bitpos + 1) & 0x7;
if(!bitpos)
{
//printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
if(transmit_count)
{
transmit_pos++;
transmit_count--;
}
switch(command_phase)
{
case 0:
if(receive_buffer != 0x01)
command_phase = -1;
else
{
transmit_buffer[0] = 0x63;
transmit_pos = 0;
transmit_count = 1;
command_phase++;
}
break;
case 2:
//if(receive_buffer)
// printf("%02x\n", receive_buffer);
break;
case 1:
command = receive_buffer;
command_phase++;
transmit_buffer[0] = 0x5A;
//puts("MOO");
//if(command != 0x42)
// fprintf(stderr, "GunCon unhandled command: 0x%02x\n", command);
//assert(command == 0x42);
if(command == 0x42)
{
transmit_buffer[1] = 0xFF ^ ((buttons & 0x01) << 3);
transmit_buffer[2] = 0xFF ^ (trigger_eff << 5) ^ ((buttons & 0x02) << 5);
if(os_shot_counter > 0)
{
hit_x = 0x01;
hit_y = 0x0A;
transmit_buffer[2] |= (1 << 5);
if(os_shot_counter == 2 || os_shot_counter == 3)
{
transmit_buffer[2] &= ~(1 << 5);
}
}
MDFN_en16lsb(&transmit_buffer[3], hit_x);
MDFN_en16lsb(&transmit_buffer[5], hit_y);
hit_x = 0x01;
hit_y = 0x0A;
transmit_pos = 0;
transmit_count = 7;
trigger_eff = trigger_noclear;
}
else
{
command_phase = -1;
transmit_buffer[1] = 0;
transmit_buffer[2] = 0;
transmit_pos = 0;
transmit_count = 0;
}
break;
}
}
if(!bitpos && transmit_count)
dsr_pulse_delay = 100; //0x80; //0x40;
return(ret);
}
InputDevice *Device_GunCon_Create(void)
{
return new InputDevice_GunCon();
}
InputDeviceInputInfoStruct Device_GunCon_IDII[6] =
{
{ "x_axis", "X Axis", -1, IDIT_X_AXIS },
{ "y_axis", "Y Axis", -1, IDIT_Y_AXIS },
{ "trigger", "Trigger", 0, IDIT_BUTTON, NULL },
{ "a", "A", 1, IDIT_BUTTON, NULL },
{ "b", "B", 2, IDIT_BUTTON, NULL },
{ "offscreen_shot", "Offscreen Shot(Simulated)", 3, IDIT_BUTTON, NULL }, // Useful for "Judge Dredd", and probably not much else.
};
}

View File

@ -0,0 +1,11 @@
#ifndef __MDFN_PSX_INPUT_GUNCON_H
#define __MDFN_PSX_INPUT_GUNCON_H
namespace MDFN_IEN_PSX
{
InputDevice *Device_GunCon_Create(void);
extern InputDeviceInputInfoStruct Device_GunCon_IDII[6];
}
#endif

View File

@ -0,0 +1,393 @@
/* 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 "../psx.h"
#include "../frontio.h"
#include "justifier.h"
namespace MDFN_IEN_PSX
{
class InputDevice_Justifier : public InputDevice
{
public:
InputDevice_Justifier(void);
virtual ~InputDevice_Justifier();
virtual void Power(void);
virtual void UpdateInput(const void *data);
virtual void SetCrosshairsColor(uint32 color);
virtual bool RequireNoFrameskip(void);
virtual pscpu_timestamp_t GPULineHook(const pscpu_timestamp_t timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void);
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
private:
bool dtr;
uint8 buttons;
bool trigger_eff;
bool trigger_noclear;
bool need_hit_detect;
int32 nom_x, nom_y;
int32 os_shot_counter;
bool prev_oss;
int32 command_phase;
uint32 bitpos;
uint8 receive_buffer;
uint8 command;
uint8 transmit_buffer[16];
uint32 transmit_pos;
uint32 transmit_count;
//
// Video timing stuff
bool prev_vsync;
int line_counter;
//
unsigned chair_r, chair_g, chair_b;
bool draw_chair;
};
InputDevice_Justifier::InputDevice_Justifier(void) : chair_r(0), chair_g(0), chair_b(0), draw_chair(false)
{
Power();
}
InputDevice_Justifier::~InputDevice_Justifier()
{
}
void InputDevice_Justifier::SetCrosshairsColor(uint32 color)
{
chair_r = (color >> 16) & 0xFF;
chair_g = (color >> 8) & 0xFF;
chair_b = (color >> 0) & 0xFF;
draw_chair = (color != (1 << 24));
}
void InputDevice_Justifier::Power(void)
{
dtr = 0;
buttons = 0;
trigger_eff = 0;
trigger_noclear = 0;
need_hit_detect = false;
nom_x = 0;
nom_y = 0;
os_shot_counter = 0;
prev_oss = 0;
command_phase = 0;
bitpos = 0;
receive_buffer = 0;
command = 0;
memset(transmit_buffer, 0, sizeof(transmit_buffer));
transmit_pos = 0;
transmit_count = 0;
prev_vsync = 0;
line_counter = 0;
}
void InputDevice_Justifier::UpdateInput(const void *data)
{
uint8 *d8 = (uint8 *)data;
nom_x = MDFN_de32lsb(&d8[0]);
nom_y = MDFN_de32lsb(&d8[4]);
trigger_noclear = (bool)(d8[8] & 0x1);
trigger_eff |= trigger_noclear;
buttons = (d8[8] >> 1) & 0x3;
if(os_shot_counter > 0) // FIXME if UpdateInput() is ever called more than once per video frame(at ~50 or ~60Hz).
os_shot_counter--;
if((d8[8] & 0x8) && !prev_oss && os_shot_counter == 0)
os_shot_counter = 10;
prev_oss = d8[8] & 0x8;
}
bool InputDevice_Justifier::RequireNoFrameskip(void)
{
return(true);
}
pscpu_timestamp_t InputDevice_Justifier::GPULineHook(const pscpu_timestamp_t timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width,
const unsigned pix_clock_offset, const unsigned pix_clock)
{
pscpu_timestamp_t ret = PSX_EVENT_MAXTS;
if(vsync && !prev_vsync)
line_counter = 0;
if(pixels && pix_clock)
{
const int avs = 22; // Not 22 for PAL, fixme.
int32 gx;
int32 gy;
int32 gxa;
gx = ((int64)nom_x * width / MDFNGameInfo->nominal_width + 0x8000) >> 16;
gy = (nom_y + 0x8000) >> 16;
gxa = gx; // - (pix_clock / 400000);
//if(gxa < 0 && gx >= 0)
// gxa = 0;
if(!os_shot_counter && need_hit_detect && gxa >= 0 && gxa < (int)width && line_counter >= (avs + gy - 1) && line_counter <= (avs + gy + 1))
{
int r, g, b, a;
format->DecodeColor(pixels[gxa], r, g, b, a);
if((r + g + b) >= 0x40) // Wrong, but not COMPLETELY ABSOLUTELY wrong, at least. ;)
{
ret = timestamp + (int64)(gxa + pix_clock_offset) * (44100 * 768) / pix_clock - 181;
}
}
if(draw_chair)
{
if(line_counter == (avs + gy))
{
const int ic = pix_clock / 762925;
for(int32 x = std::max<int32>(0, gx - ic); x < std::min<int32>(width, gx + ic); x++)
{
int r, g, b, a;
int nr, ng, nb;
format->DecodeColor(pixels[x], r, g, b, a);
nr = (r + chair_r * 3) >> 2;
ng = (g + chair_g * 3) >> 2;
nb = (b + chair_b * 3) >> 2;
if(abs((r * 76 + g * 150 + b * 29) - (nr * 76 + ng * 150 + nb * 29)) < 16384)
{
nr >>= 1;
ng >>= 1;
nb >>= 1;
}
pixels[x] = format->MakeColor(nr, ng, nb, a);
}
}
else if(line_counter >= (avs + gy - 8) && line_counter <= (avs + gy + 8))
{
int r, g, b, a;
int nr, ng, nb;
format->DecodeColor(pixels[gx], r, g, b, a);
nr = (r + chair_r * 3) >> 2;
ng = (g + chair_g * 3) >> 2;
nb = (b + chair_b * 3) >> 2;
if(abs((r * 76 + g * 150 + b * 29) - (nr * 76 + ng * 150 + nb * 29)) < 16384)
{
nr >>= 1;
ng >>= 1;
nb >>= 1;
}
pixels[gx] = format->MakeColor(nr, ng, nb, a);
}
}
}
line_counter++;
return(ret);
}
void InputDevice_Justifier::SetDTR(bool new_dtr)
{
if(!dtr && new_dtr)
{
command_phase = 0;
bitpos = 0;
transmit_pos = 0;
transmit_count = 0;
}
else if(dtr && !new_dtr)
{
//if(bitpos || transmit_count)
// printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
dtr = new_dtr;
}
bool InputDevice_Justifier::GetDSR(void)
{
if(!dtr)
return(0);
if(!bitpos && transmit_count)
return(1);
return(0);
}
bool InputDevice_Justifier::Clock(bool TxD, int32 &dsr_pulse_delay)
{
bool ret = 1;
dsr_pulse_delay = 0;
if(!dtr)
return(1);
if(transmit_count)
ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
receive_buffer &= ~(1 << bitpos);
receive_buffer |= TxD << bitpos;
bitpos = (bitpos + 1) & 0x7;
if(!bitpos)
{
//printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
if(transmit_count)
{
transmit_pos++;
transmit_count--;
}
switch(command_phase)
{
case 0:
if(receive_buffer != 0x01)
command_phase = -1;
else
{
transmit_buffer[0] = 0x31;
transmit_pos = 0;
transmit_count = 1;
command_phase++;
}
break;
case 2:
//if(receive_buffer)
// printf("%02x\n", receive_buffer);
command_phase++;
break;
case 3:
need_hit_detect = receive_buffer & 0x10; // TODO, see if it's (val&0x10) == 0x10, or some other mask value.
command_phase++;
break;
case 1:
command = receive_buffer;
command_phase++;
transmit_buffer[0] = 0x5A;
//if(command != 0x42)
// fprintf(stderr, "Justifier unhandled command: 0x%02x\n", command);
//assert(command == 0x42);
if(command == 0x42)
{
transmit_buffer[1] = 0xFF ^ ((buttons & 2) << 2);
transmit_buffer[2] = 0xFF ^ (trigger_eff << 7) ^ ((buttons & 1) << 6);
if(os_shot_counter > 0)
{
transmit_buffer[2] |= (1 << 7);
if(os_shot_counter == 6 || os_shot_counter == 5)
{
transmit_buffer[2] &= ~(1 << 7);
}
}
transmit_pos = 0;
transmit_count = 3;
trigger_eff = trigger_noclear;
}
else
{
command_phase = -1;
transmit_buffer[1] = 0;
transmit_buffer[2] = 0;
transmit_pos = 0;
transmit_count = 0;
}
break;
}
}
if(!bitpos && transmit_count)
dsr_pulse_delay = 200;
return(ret);
}
InputDevice *Device_Justifier_Create(void)
{
return new InputDevice_Justifier();
}
InputDeviceInputInfoStruct Device_Justifier_IDII[6] =
{
{ "x_axis", "X Axis", -1, IDIT_X_AXIS },
{ "y_axis", "Y Axis", -1, IDIT_Y_AXIS },
{ "trigger", "Trigger", 0, IDIT_BUTTON, NULL },
{ "o", "O", 1, IDIT_BUTTON, NULL },
{ "start", "Start", 2, IDIT_BUTTON, NULL },
{ "offscreen_shot", "Offscreen Shot(Simulated)", 3, IDIT_BUTTON, NULL },
};
}

View File

@ -0,0 +1,11 @@
#ifndef __MDFN_PSX_INPUT_JUSTIFIER_H
#define __MDFN_PSX_INPUT_JUSTIFIER_H
namespace MDFN_IEN_PSX
{
InputDevice *Device_Justifier_Create(void);
extern InputDeviceInputInfoStruct Device_Justifier_IDII[6];
}
#endif

View File

@ -0,0 +1,448 @@
/* 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
*/
// I could find no other commands than 'R', 'W', and 'S' (not sure what 'S' is for, however)
#include "../psx.h"
#include "../frontio.h"
#include "memcard.h"
namespace MDFN_IEN_PSX
{
class InputDevice_Memcard : public InputDevice
{
public:
InputDevice_Memcard();
virtual ~InputDevice_Memcard();
virtual void Power(void);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void);
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
//
//
virtual uint32 GetNVSize(void);
virtual void ReadNV(uint8 *buffer, uint32 offset, uint32 size);
virtual void WriteNV(const uint8 *buffer, uint32 offset, uint32 size);
virtual uint64 GetNVDirtyCount(void);
virtual void ResetNVDirtyCount(void);
private:
bool presence_new;
uint8 card_data[1 << 17];
uint8 rw_buffer[128];
uint8 write_xor;
uint64 dirty_count;
bool dtr;
int32 command_phase;
uint32 bitpos;
uint8 receive_buffer;
uint8 command;
uint16 addr;
uint8 calced_xor;
uint8 transmit_buffer;
uint32 transmit_count;
};
InputDevice_Memcard::InputDevice_Memcard()
{
Power();
dirty_count = 0;
// Init memcard as formatted.
assert(sizeof(card_data) == (1 << 17));
memset(card_data, 0x00, sizeof(card_data));
card_data[0x00] = 0x4D;
card_data[0x01] = 0x43;
card_data[0x7F] = 0x0E;
for(unsigned int A = 0x80; A < 0x800; A += 0x80)
{
card_data[A + 0x00] = 0xA0;
card_data[A + 0x08] = 0xFF;
card_data[A + 0x09] = 0xFF;
card_data[A + 0x7F] = 0xA0;
}
for(unsigned int A = 0x0800; A < 0x1200; A += 0x80)
{
card_data[A + 0x00] = 0xFF;
card_data[A + 0x01] = 0xFF;
card_data[A + 0x02] = 0xFF;
card_data[A + 0x03] = 0xFF;
card_data[A + 0x08] = 0xFF;
card_data[A + 0x09] = 0xFF;
}
}
InputDevice_Memcard::~InputDevice_Memcard()
{
}
void InputDevice_Memcard::Power(void)
{
dtr = 0;
//buttons[0] = buttons[1] = 0;
command_phase = 0;
bitpos = 0;
receive_buffer = 0;
command = 0;
transmit_buffer = 0;
transmit_count = 0;
addr = 0;
presence_new = true;
}
void InputDevice_Memcard::SetDTR(bool new_dtr)
{
if(!dtr && new_dtr)
{
command_phase = 0;
bitpos = 0;
transmit_count = 0;
}
else if(dtr && !new_dtr)
{
if(command_phase > 0)
PSX_WARNING("[MCR] Communication aborted???");
}
dtr = new_dtr;
}
bool InputDevice_Memcard::GetDSR(void)
{
if(!dtr)
return(0);
if(!bitpos && transmit_count)
return(1);
return(0);
}
bool InputDevice_Memcard::Clock(bool TxD, int32 &dsr_pulse_delay)
{
bool ret = 1;
dsr_pulse_delay = 0;
if(!dtr)
return(1);
if(transmit_count)
ret = (transmit_buffer >> bitpos) & 1;
receive_buffer &= ~(1 << bitpos);
receive_buffer |= TxD << bitpos;
bitpos = (bitpos + 1) & 0x7;
if(!bitpos)
{
//if(command_phase > 0 || transmit_count)
// printf("[MCRDATA] Received_data=0x%02x, Sent_data=0x%02x\n", receive_buffer, transmit_buffer);
if(transmit_count)
{
transmit_count--;
}
switch(command_phase)
{
case 0:
if(receive_buffer != 0x81)
command_phase = -1;
else
{
//printf("[MCR] Device selected\n");
transmit_buffer = presence_new ? 0x08 : 0x00;
transmit_count = 1;
command_phase++;
}
break;
case 1:
command = receive_buffer;
//printf("[MCR] Command received: %c\n", command);
if(command == 'R' || command == 'W')
{
command_phase++;
transmit_buffer = 0x5A;
transmit_count = 1;
}
else
{
if(command == 'S')
{
PSX_WARNING("[MCR] Memcard S command unsupported.");
}
command_phase = -1;
transmit_buffer = 0;
transmit_count = 0;
}
break;
case 2:
transmit_buffer = 0x5D;
transmit_count = 1;
command_phase++;
break;
case 3:
transmit_buffer = 0x00;
transmit_count = 1;
if(command == 'R')
command_phase = 1000;
else if(command == 'W')
command_phase = 2000;
break;
//
// Read
//
case 1000:
addr = receive_buffer << 8;
transmit_buffer = receive_buffer;
transmit_count = 1;
command_phase++;
break;
case 1001:
addr |= receive_buffer & 0xFF;
transmit_buffer = '\\';
transmit_count = 1;
command_phase++;
break;
case 1002:
//printf("[MCR] READ ADDR=0x%04x\n", addr);
if(addr >= (sizeof(card_data) >> 7))
addr = 0xFFFF;
calced_xor = 0;
transmit_buffer = ']';
transmit_count = 1;
command_phase++;
// TODO: enable this code(or something like it) when CPU instruction timing is a bit better.
//
//dsr_pulse_delay = 32000;
//goto SkipDPD;
//
break;
case 1003:
transmit_buffer = addr >> 8;
calced_xor ^= transmit_buffer;
transmit_count = 1;
command_phase++;
break;
case 1004:
transmit_buffer = addr & 0xFF;
calced_xor ^= transmit_buffer;
if(addr == 0xFFFF)
{
transmit_count = 1;
command_phase = -1;
}
else
{
transmit_count = 1;
command_phase = 1024;
}
break;
// Transmit actual 128 bytes data
case (1024 + 0) ... (1024 + 128 - 1):
transmit_buffer = card_data[(addr << 7) + (command_phase - 1024)];
calced_xor ^= transmit_buffer;
transmit_count = 1;
command_phase++;
break;
// XOR
case (1024 + 128):
transmit_buffer = calced_xor;
transmit_count = 1;
command_phase++;
break;
// End flag
case (1024 + 129):
transmit_buffer = 'G';
transmit_count = 1;
command_phase = -1;
break;
//
// Write
//
case 2000:
calced_xor = receive_buffer;
addr = receive_buffer << 8;
transmit_buffer = receive_buffer;
transmit_count = 1;
command_phase++;
break;
case 2001:
calced_xor ^= receive_buffer;
addr |= receive_buffer & 0xFF;
//printf("[MCR] WRITE ADDR=0x%04x\n", addr);
transmit_buffer = receive_buffer;
transmit_count = 1;
command_phase = 2048;
break;
case (2048 + 0) ... (2048 + 128 - 1):
calced_xor ^= receive_buffer;
rw_buffer[command_phase - 2048] = receive_buffer;
transmit_buffer = receive_buffer;
transmit_count = 1;
command_phase++;
break;
case (2048 + 128): // XOR
write_xor = receive_buffer;
transmit_buffer = '\\';
transmit_count = 1;
command_phase++;
break;
case (2048 + 129):
transmit_buffer = ']';
transmit_count = 1;
command_phase++;
break;
case (2048 + 130): // End flag
//MDFN_DispMessage("%02x %02x", calced_xor, write_xor);
//printf("[MCR] Write End. Actual_XOR=0x%02x, CW_XOR=0x%02x\n", calced_xor, write_xor);
if(calced_xor != write_xor)
transmit_buffer = 'N';
else if(addr >= (sizeof(card_data) >> 7))
transmit_buffer = 0xFF;
else
{
transmit_buffer = 'G';
presence_new = false;
// If the current data is different from the data to be written, increment the dirty count.
// memcpy()'ing over to card_data is also conditionalized here for a slight optimization.
if(memcmp(&card_data[addr << 7], rw_buffer, 128))
{
memcpy(&card_data[addr << 7], rw_buffer, 128);
dirty_count++;
}
}
transmit_count = 1;
command_phase = -1;
break;
}
//if(command_phase != -1 || transmit_count)
// printf("[MCR] Receive: 0x%02x, Send: 0x%02x -- %d\n", receive_buffer, transmit_buffer, command_phase);
}
if(!bitpos && transmit_count)
dsr_pulse_delay = 0x100;
//SkipDPD: ;
return(ret);
}
uint32 InputDevice_Memcard::GetNVSize(void)
{
return(sizeof(card_data));
}
void InputDevice_Memcard::ReadNV(uint8 *buffer, uint32 offset, uint32 size)
{
while(size--)
{
*buffer = card_data[offset & (sizeof(card_data) - 1)];
buffer++;
offset++;
}
}
void InputDevice_Memcard::WriteNV(const uint8 *buffer, uint32 offset, uint32 size)
{
if(size)
dirty_count++;
while(size--)
{
card_data[offset & (sizeof(card_data) - 1)] = *buffer;
buffer++;
offset++;
}
}
uint64 InputDevice_Memcard::GetNVDirtyCount(void)
{
return(dirty_count);
}
void InputDevice_Memcard::ResetNVDirtyCount(void)
{
dirty_count = 0;
}
InputDevice *Device_Memcard_Create(void)
{
return new InputDevice_Memcard();
}
}

View File

@ -0,0 +1,11 @@
#ifndef __MDFN_PSX_INPUT_MEMCARD_H
#define __MDFN_PSX_INPUT_MEMCARD_H
namespace MDFN_IEN_PSX
{
InputDevice *Device_Memcard_Create(void);
}
#endif

View File

@ -0,0 +1,252 @@
#include "../psx.h"
#include "../frontio.h"
#include "mouse.h"
namespace MDFN_IEN_PSX
{
class InputDevice_Mouse : public InputDevice
{
public:
InputDevice_Mouse();
virtual ~InputDevice_Mouse();
virtual void Power(void);
virtual void UpdateInput(const void *data);
virtual void Update(const pscpu_timestamp_t timestamp);
virtual void ResetTS(void);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
private:
int32 lastts;
int32 clear_timeout;
bool dtr;
uint8 button;
uint8 button_post_mask;
int32 accum_xdelta;
int32 accum_ydelta;
int32 command_phase;
uint32 bitpos;
uint8 receive_buffer;
uint8 command;
uint8 transmit_buffer[5];
uint32 transmit_pos;
uint32 transmit_count;
};
InputDevice_Mouse::InputDevice_Mouse()
{
Power();
}
InputDevice_Mouse::~InputDevice_Mouse()
{
}
void InputDevice_Mouse::Update(const pscpu_timestamp_t timestamp)
{
int32 cycles = timestamp - lastts;
clear_timeout += cycles;
if(clear_timeout >= (33868800 / 4))
{
//puts("Mouse timeout\n");
clear_timeout = 0;
accum_xdelta = 0;
accum_ydelta = 0;
button &= button_post_mask;
}
lastts = timestamp;
}
void InputDevice_Mouse::ResetTS(void)
{
lastts = 0;
}
void InputDevice_Mouse::Power(void)
{
lastts = 0;
clear_timeout = 0;
dtr = 0;
button = 0;
button_post_mask = 0;
accum_xdelta = 0;
accum_ydelta = 0;
command_phase = 0;
bitpos = 0;
receive_buffer = 0;
command = 0;
memset(transmit_buffer, 0, sizeof(transmit_buffer));
transmit_pos = 0;
transmit_count = 0;
}
void InputDevice_Mouse::UpdateInput(const void *data)
{
accum_xdelta += (int32)MDFN_de32lsb((uint8*)data + 0);
accum_ydelta += (int32)MDFN_de32lsb((uint8*)data + 4);
if(accum_xdelta > 30 * 127) accum_xdelta = 30 * 127;
if(accum_xdelta < 30 * -128) accum_xdelta = 30 * -128;
if(accum_ydelta > 30 * 127) accum_ydelta = 30 * 127;
if(accum_ydelta < 30 * -128) accum_ydelta = 30 * -128;
button |= *((uint8 *)data + 8);
button_post_mask = *((uint8 *)data + 8);
//if(button)
// MDFN_DispMessage("Button\n");
//printf("%d %d\n", accum_xdelta, accum_ydelta);
}
void InputDevice_Mouse::SetDTR(bool new_dtr)
{
if(!dtr && new_dtr)
{
command_phase = 0;
bitpos = 0;
transmit_pos = 0;
transmit_count = 0;
}
else if(dtr && !new_dtr)
{
//if(bitpos || transmit_count)
// printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
dtr = new_dtr;
}
bool InputDevice_Mouse::Clock(bool TxD, int32 &dsr_pulse_delay)
{
bool ret = 1;
dsr_pulse_delay = 0;
if(!dtr)
return(1);
if(transmit_count)
ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
receive_buffer &= ~(1 << bitpos);
receive_buffer |= TxD << bitpos;
bitpos = (bitpos + 1) & 0x7;
if(!bitpos)
{
//printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
if(transmit_count)
{
transmit_pos++;
transmit_count--;
}
switch(command_phase)
{
case 0:
if(receive_buffer != 0x01)
command_phase = -1;
else
{
transmit_buffer[0] = 0x12;
transmit_pos = 0;
transmit_count = 1;
command_phase++;
}
break;
case 1:
command = receive_buffer;
command_phase++;
transmit_buffer[0] = 0x5A;
if(command == 0x42)
{
int32 xdelta = accum_xdelta;
int32 ydelta = accum_ydelta;
if(xdelta < -128) xdelta = -128;
if(xdelta > 127) xdelta = 127;
if(ydelta < -128) ydelta = -128;
if(ydelta > 127) ydelta = 127;
transmit_buffer[1] = 0xFF;
transmit_buffer[2] = 0xFC ^ (button << 2);
transmit_buffer[3] = xdelta;
transmit_buffer[4] = ydelta;
accum_xdelta -= xdelta;
accum_ydelta -= ydelta;
button &= button_post_mask;
transmit_pos = 0;
transmit_count = 5;
clear_timeout = 0;
}
else
{
command_phase = -1;
transmit_pos = 0;
transmit_count = 0;
}
break;
}
}
if(!bitpos && transmit_count)
dsr_pulse_delay = 0x40; //0x100;
return(ret);
}
InputDevice *Device_Mouse_Create(void)
{
return new InputDevice_Mouse();
}
InputDeviceInputInfoStruct Device_Mouse_IDII[4] =
{
{ "x_axis", "X Axis", -1, IDIT_X_AXIS_REL },
{ "y_axis", "Y Axis", -1, IDIT_Y_AXIS_REL },
{ "right", "Right Button", 1, IDIT_BUTTON, NULL },
{ "left", "Left Button", 0, IDIT_BUTTON, NULL },
};
}

View File

@ -0,0 +1,11 @@
#ifndef __MDFN_PSX_INPUT_MOUSE_H
#define __MDFN_PSX_INPUT_MOUSE_H
namespace MDFN_IEN_PSX
{
InputDevice *Device_Mouse_Create(void);
extern InputDeviceInputInfoStruct Device_Mouse_IDII[4];
}
#endif

View File

@ -0,0 +1,335 @@
#include "../psx.h"
#include "../frontio.h"
#include "multitap.h"
/*
Notes from tests on real thing(not necessarily emulated the same way here):
Manual port selection read mode:
Write 0x01-0x04 instead of 0x01 as first byte, selects port(1=A,2=B,3=C,4=D) to access.
Ports that don't exist(0x00, 0x05-0xFF) or don't have a device plugged in will not respond(no DSR pulse).
Full read mode:
Bit0 of third byte(from-zero-index=0x02) should be set to 1 to enter full read mode, on subsequent reads.
Appears to require a controller to be plugged into the port specified by the first byte as per manual port selection read mode,
to write the byte necessary to enter full-read mode; but once the third byte with the bit set has been written, no controller in
that port is required for doing full reads(and the manual port selection is ignored when doing a full read).
However, if there are no controllers plugged in, or the first byte written in a full-mode communication has one or more bits in the upper
nybble set to 1, the returned data will be short:
% 0: 0xff
% 1: 0x80
% 2: 0x5a
Example full-read bytestream(with controllers plugged into port A, port B, and port C, with port D empty):
% 0: 0xff
% 1: 0x80
% 2: 0x5a
% 3: 0x73 (Port A controller data start)
% 4: 0x5a
% 5: 0xff
% 6: 0xff
% 7: 0x80
% 8: 0x8c
% 9: 0x79
% 10: 0x8f
% 11: 0x53 (Port B controller data start)
% 12: 0x5a
% 13: 0xff
% 14: 0xff
% 15: 0x80
% 16: 0x80
% 17: 0x75
% 18: 0x8e
% 19: 0x41 (Port C controller data start)
% 20: 0x5a
% 21: 0xff
% 22: 0xff
% 23: 0xff
% 24: 0xff
% 25: 0xff
% 26: 0xff
% 27: 0xff (Port D controller data start)
% 28: 0xff
% 29: 0xff
% 30: 0xff
% 31: 0xff
% 32: 0xff
% 33: 0xff
% 34: 0xff
*/
namespace MDFN_IEN_PSX
{
InputDevice_Multitap::InputDevice_Multitap()
{
for(int i = 0; i < 4; i++)
{
pad_devices[i] = NULL;
mc_devices[i] = NULL;
}
Power();
}
InputDevice_Multitap::~InputDevice_Multitap()
{
}
void InputDevice_Multitap::SetSubDevice(unsigned int sub_index, InputDevice *device, InputDevice *mc_device)
{
assert(sub_index < 4);
//printf("%d\n", sub_index);
pad_devices[sub_index] = device;
mc_devices[sub_index] = mc_device;
}
void InputDevice_Multitap::Power(void)
{
selected_device = -1;
bit_counter = 0;
receive_buffer = 0;
byte_counter = 0;
mc_mode = false;
full_mode = false;
full_mode_setting = false;
for(int i = 0; i < 4; i++)
{
if(pad_devices[i])
pad_devices[i]->Power();
if(mc_devices[i])
mc_devices[i]->Power();
}
}
void InputDevice_Multitap::SetDTR(bool new_dtr)
{
bool old_dtr = dtr;
dtr = new_dtr;
if(!dtr)
{
bit_counter = 0;
byte_counter = 0;
receive_buffer = 0;
selected_device = -1;
mc_mode = false;
full_mode = false;
}
if(!old_dtr && dtr)
{
full_mode = full_mode_setting;
//if(full_mode) {
// printf("Full mode start\n"); }
}
for(int i = 0; i < 4; i++)
{
pad_devices[i]->SetDTR(dtr);
mc_devices[i]->SetDTR(dtr);
}
}
bool InputDevice_Multitap::GetDSR(void)
{
return(0);
}
bool InputDevice_Multitap::Clock(bool TxD, int32 &dsr_pulse_delay)
{
if(!dtr)
return(1);
bool ret = 1;
bool mangled_txd = TxD;
int32 tmp_pulse_delay[2][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
//printf("Receive bit: %d\n", TxD);
//printf("TxD %d\n", TxD);
receive_buffer &= ~ (1 << bit_counter);
receive_buffer |= TxD << bit_counter;
if(1)
{
uint8 sub_clock = 0;
uint8 sub_rxd_ignore = 0;
if(full_mode)
{
if(byte_counter == 0)
{
sub_clock = 0;
sub_rxd_ignore = 0xF;
}
else if(byte_counter == 1)
{
ret = (0x80 >> bit_counter) & 1;
sub_clock = false;
sub_rxd_ignore = 0xF;
}
else if(byte_counter == 2)
{
ret = (0x5A >> bit_counter) & 1;
sub_rxd_ignore = 0xF;
if(!mc_mode)
{
sub_clock = 0xF;
mangled_txd = (0x01 >> bit_counter) & 1;
}
}
else if(byte_counter == 0x03 || byte_counter == (0x03 + 0x08 * 1) || byte_counter == (0x03 + 0x08 * 2) || byte_counter == (0x03 + 0x08 * 3))
{
sub_clock = 1 << selected_device;
sub_rxd_ignore = 0;
mangled_txd = (command >> bit_counter) & 1;
}
else
{
sub_clock = 1 << selected_device;
sub_rxd_ignore = 0;
// Not sure about this, would need to test with rumble-capable device on real thing?
//mangled_txd = (0x00 >> bit_counter) & 1;
}
}
else
{
if(byte_counter == 0)
{
if(bit_counter < 4)
mangled_txd = (0x01 >> bit_counter) & 1;
sub_clock = 0xF;
sub_rxd_ignore = 0xF;
}
else if((unsigned)selected_device < 4)
{
sub_clock = 1 << selected_device;
sub_rxd_ignore = 0;
}
}
for(int i = 0; i < 4; i++)
{
if(sub_clock & (1 << i))
{
ret &= pad_devices[i]->Clock(mangled_txd, tmp_pulse_delay[0][i]) | ((sub_rxd_ignore >> i) & 1);
ret &= mc_devices[i]->Clock(mangled_txd, tmp_pulse_delay[1][i]) | ((sub_rxd_ignore >> i) & 1);
}
}
}
#if 0
{
static uint8 sendy = 0;
sendy &= ~(1 << bit_counter);
sendy |= ret << bit_counter;
if(bit_counter == 7)
printf("Multitap to PSX: 0x%02x\n", sendy);
}
#endif
bit_counter = (bit_counter + 1) & 0x7;
if(bit_counter == 0)
{
if(byte_counter == 0)
{
mc_mode = (bool)(receive_buffer & 0xF0);
//printf("Full mode: %d %d %d\n", full_mode, bit_counter, byte_counter);
if(full_mode)
selected_device = 0;
else
{
//printf("Device select: %02x\n", receive_buffer);
selected_device = ((receive_buffer & 0xF) - 1) & 0xFF;
}
}
if(byte_counter == 1)
{
command = receive_buffer;
//printf("Multitap sub-command: %02x\n", command);
}
if((!mc_mode || full_mode) && byte_counter == 2 && command == 0x42)
{
//printf("Full mode setting: %02x\n", receive_buffer);
full_mode_setting = receive_buffer & 0x01;
}
// Handle DSR stuff
if(full_mode)
{
if(byte_counter == 0 || byte_counter == 1)
dsr_pulse_delay = 0x40;
else if(byte_counter == 2 || byte_counter == 3)
{
//int32 td = 0;
//for(int i = 0; i < 4; i++)
//{
// td = std::max<int32>(td, tmp_pulse_delay[0][i]);
// td = std::max<int32>(td, tmp_pulse_delay[1][i]);
//}
//dsr_pulse_delay = td;
//printf("%d %d\n", byte_counter, dsr_pulse_delay);
// Just route the first port's DSR through here; at least one game relies on this(Formula One 2000), or else it freezes. Well, even when it doesn't
// freeze, the game crashes(as of Jan 20, 2012), but that's not the multitap emulation's fault. :b
dsr_pulse_delay = std::max<int32>(tmp_pulse_delay[0][0], tmp_pulse_delay[1][0]);
}
else if(byte_counter > 3 && byte_counter < 34)
{
dsr_pulse_delay = 0x80;
}
}
else
{
if((unsigned)selected_device < 4)
{
dsr_pulse_delay = std::max<int32>(tmp_pulse_delay[0][selected_device], tmp_pulse_delay[1][selected_device]);
}
}
//
//
//
//printf("Byte Counter Increment\n");
if(byte_counter < 255)
byte_counter++;
if(full_mode && (byte_counter == (0x03 + 0x08 * 1) || byte_counter == (0x03 + 0x08 * 2) || byte_counter == (0x03 + 0x08 * 3)))
{
//printf("Device Select Increment\n");
selected_device++;
}
}
return(ret);
}
}

View File

@ -0,0 +1,45 @@
#ifndef __MDFN_PSX_INPUT_MULTITAP_H
#define __MDFN_PSX_INPUT_MULTITAP_H
namespace MDFN_IEN_PSX
{
class InputDevice_Multitap : public InputDevice
{
public:
InputDevice_Multitap();
virtual ~InputDevice_Multitap();
virtual void Power(void);
void SetSubDevice(unsigned int sub_index, InputDevice *device, InputDevice *mc_device);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void);
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
private:
InputDevice *pad_devices[4];
InputDevice *mc_devices[4];
bool dtr;
int selected_device;
bool full_mode_setting;
bool full_mode;
bool mc_mode;
uint8 command;
uint8 receive_buffer;
uint8 bit_counter;
uint8 byte_counter;
};
}
#endif

View File

@ -0,0 +1,259 @@
/* 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 "../psx.h"
#include "../frontio.h"
#include "negcon.h"
namespace MDFN_IEN_PSX
{
class InputDevice_neGcon : public InputDevice
{
public:
InputDevice_neGcon(void);
virtual ~InputDevice_neGcon();
virtual void Power(void);
virtual void UpdateInput(const void *data);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void);
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
private:
bool dtr;
uint8 buttons[2];
uint8 twist;
uint8 anabuttons[3];
int32 command_phase;
uint32 bitpos;
uint8 receive_buffer;
uint8 command;
uint8 transmit_buffer[8];
uint32 transmit_pos;
uint32 transmit_count;
};
InputDevice_neGcon::InputDevice_neGcon(void)
{
Power();
}
InputDevice_neGcon::~InputDevice_neGcon()
{
}
void InputDevice_neGcon::Power(void)
{
dtr = 0;
buttons[0] = buttons[1] = 0;
twist = 0;
anabuttons[0] = 0;
anabuttons[1] = 0;
anabuttons[2] = 0;
command_phase = 0;
bitpos = 0;
receive_buffer = 0;
command = 0;
memset(transmit_buffer, 0, sizeof(transmit_buffer));
transmit_pos = 0;
transmit_count = 0;
}
void InputDevice_neGcon::UpdateInput(const void *data)
{
uint8 *d8 = (uint8 *)data;
buttons[0] = d8[0];
buttons[1] = d8[1];
twist = ((32768 + MDFN_de32lsb((const uint8 *)data + 4) - (((int32)MDFN_de32lsb((const uint8 *)data + 8) * 32768 + 16383) / 32767)) * 255 + 32767) / 65535;
anabuttons[0] = (MDFN_de32lsb((const uint8 *)data + 12) * 255 + 16383) / 32767;
anabuttons[1] = (MDFN_de32lsb((const uint8 *)data + 16) * 255 + 16383) / 32767;
anabuttons[2] = (MDFN_de32lsb((const uint8 *)data + 20) * 255 + 16383) / 32767;
//printf("%02x %02x %02x %02x\n", twist, anabuttons[0], anabuttons[1], anabuttons[2]);
}
void InputDevice_neGcon::SetDTR(bool new_dtr)
{
if(!dtr && new_dtr)
{
command_phase = 0;
bitpos = 0;
transmit_pos = 0;
transmit_count = 0;
}
else if(dtr && !new_dtr)
{
//if(bitpos || transmit_count)
// printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
dtr = new_dtr;
}
bool InputDevice_neGcon::GetDSR(void)
{
if(!dtr)
return(0);
if(!bitpos && transmit_count)
return(1);
return(0);
}
bool InputDevice_neGcon::Clock(bool TxD, int32 &dsr_pulse_delay)
{
bool ret = 1;
dsr_pulse_delay = 0;
if(!dtr)
return(1);
if(transmit_count)
ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
receive_buffer &= ~(1 << bitpos);
receive_buffer |= TxD << bitpos;
bitpos = (bitpos + 1) & 0x7;
if(!bitpos)
{
//printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
if(transmit_count)
{
transmit_pos++;
transmit_count--;
}
switch(command_phase)
{
case 0:
if(receive_buffer != 0x01)
command_phase = -1;
else
{
transmit_buffer[0] = 0x23;
transmit_pos = 0;
transmit_count = 1;
command_phase++;
dsr_pulse_delay = 256;
}
break;
case 1:
command = receive_buffer;
command_phase++;
transmit_buffer[0] = 0x5A;
//if(command != 0x42)
// fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command);
if(command == 0x42)
{
transmit_buffer[1] = 0xFF ^ buttons[0];
transmit_buffer[2] = 0xFF ^ buttons[1];
transmit_buffer[3] = twist; // Twist, 0x00 through 0xFF, 0x80 center.
transmit_buffer[4] = anabuttons[0]; // Analog button I, 0x00 through 0xFF, 0x00 = no pressing, 0xFF = max.
transmit_buffer[5] = anabuttons[1]; // Analog button II, ""
transmit_buffer[6] = anabuttons[2]; // Left shoulder analog button, ""
transmit_pos = 0;
transmit_count = 7;
dsr_pulse_delay = 256;
}
else
{
command_phase = -1;
transmit_buffer[1] = 0;
transmit_buffer[2] = 0;
transmit_pos = 0;
transmit_count = 0;
}
break;
case 2:
if(transmit_count > 0)
dsr_pulse_delay = 128;
break;
}
}
return(ret);
}
InputDevice *Device_neGcon_Create(void)
{
return new InputDevice_neGcon();
}
InputDeviceInputInfoStruct Device_neGcon_IDII[21] =
{
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ "start", "START", 4, IDIT_BUTTON, NULL },
{ "up", "D-Pad UP ↑", 0, IDIT_BUTTON, "down" },
{ "right", "D-Pad RIGHT →", 3, IDIT_BUTTON, "left" },
{ "down", "D-Pad DOWN ↓", 1, IDIT_BUTTON, "up" },
{ "left", "D-Pad LEFT ←", 2, IDIT_BUTTON, "right" },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ "r", "Right Shoulder", 12, IDIT_BUTTON },
{ "b", "B", 9, IDIT_BUTTON, NULL },
{ "a", "A", 10, IDIT_BUTTON, NULL },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ "twist_cwise", "Twist ↓|↑ (Analog, Turn Right)", 6, IDIT_BUTTON_ANALOG },
{ "twist_ccwise", "Twist ↑|↓ (Analog, Turn Left)", 5, IDIT_BUTTON_ANALOG },
{ "i", "I (Analog)", 8, IDIT_BUTTON_ANALOG },
{ "ii", "II (Analog)", 7, IDIT_BUTTON_ANALOG },
{ "l", "Left Shoulder (Analog)", 11, IDIT_BUTTON_ANALOG },
};
}

View File

@ -0,0 +1,9 @@
#ifndef __MDFN_PSX_INPUT_NEGCON_H
#define __MDFN_PSX_INPUT_NEGCON_H
namespace MDFN_IEN_PSX
{
InputDevice *Device_neGcon_Create(void);
extern InputDeviceInputInfoStruct Device_neGcon_IDII[21];
}
#endif

174
mednafen/psx-0925/irq.cpp Normal file
View File

@ -0,0 +1,174 @@
/* 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 "psx.h"
namespace MDFN_IEN_PSX
{
static uint16 Asserted;
static uint16 Mask;
static uint16 Status;
static INLINE void Recalc(void)
{
CPU->AssertIRQ(0, (bool)(Status & Mask));
}
void IRQ_Power(void)
{
Asserted = 0;
Status = 0;
Mask = 0;
Recalc();
}
int IRQ_StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT StateRegs[] =
{
SFVAR(Asserted),
SFVAR(Mask),
SFVAR(Status),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "IRQ");
if(load)
{
Recalc();
}
return(ret);
}
void IRQ_Assert(int which, bool status)
{
uint32 old_Asserted = Asserted;
//PSX_WARNING("[IRQ] Assert: %d %d", which, status);
//if(which == IRQ_SPU && status && (Asserted & (1 << which)))
// MDFN_DispMessage("SPU IRQ glitch??");
Asserted &= ~(1 << which);
if(status)
{
Asserted |= 1 << which;
//Status |= 1 << which;
Status |= (old_Asserted ^ Asserted) & Asserted;
}
Recalc();
}
void IRQ_Write(uint32 A, uint32 V)
{
// FIXME if we ever have "accurate" bus emulation
V <<= (A & 3) * 8;
//printf("[IRQ] Write: 0x%08x 0x%08x --- PAD TEMP\n", A, V);
if(A & 4)
Mask = V;
else
{
Status &= V;
//Status |= Asserted;
}
Recalc();
}
uint32 IRQ_Read(uint32 A)
{
uint32 ret = 0;
if(A & 4)
ret = Mask;
else
ret = Status;
// FIXME: Might want to move this out to psx.cpp eventually.
ret |= 0x1F800000;
ret >>= (A & 3) * 8;
//printf("[IRQ] Read: 0x%08x 0x%08x --- PAD TEMP\n", A, ret);
return(ret);
}
void IRQ_Reset(void)
{
Asserted = 0;
Status = 0;
Mask = 0;
Recalc();
}
uint32 IRQ_GetRegister(unsigned int which, char *special, const uint32 special_len)
{
uint32 ret = 0;
switch(which)
{
case IRQ_GSREG_ASSERTED:
ret = Asserted;
break;
case IRQ_GSREG_STATUS:
ret = Status;
break;
case IRQ_GSREG_MASK:
ret = Mask;
break;
}
return(ret);
}
void IRQ_SetRegister(unsigned int which, uint32 value)
{
switch(which)
{
case IRQ_GSREG_ASSERTED:
Asserted = value;
Recalc();
break;
case IRQ_GSREG_STATUS:
Status = value;
Recalc();
break;
case IRQ_GSREG_MASK:
Mask = value;
Recalc();
break;
}
}
}

43
mednafen/psx-0925/irq.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef __MDFN_PSX_IRQ_H
#define __MDFN_PSX_IRQ_H
namespace MDFN_IEN_PSX
{
enum
{
IRQ_VSYNC = 0,
IRQ_GPU = 1,
IRQ_CD = 2,
IRQ_DMA = 3, // Probably
IRQ_TIMER_0 = 4,
IRQ_TIMER_1 = 5,
IRQ_TIMER_2 = 6,
IRQ_SIO = 7,
IRQ_SPU = 9,
IRQ_PIO = 10, // Probably
};
void IRQ_Power(void);
void IRQ_Assert(int which, bool asserted);
void IRQ_Write(uint32 A, uint32 V);
uint32 IRQ_Read(uint32 A);
enum
{
IRQ_GSREG_ASSERTED = 0,
IRQ_GSREG_STATUS = 1,
IRQ_GSREG_MASK = 2
};
uint32 IRQ_GetRegister(unsigned int which, char *special, const uint32 special_len);
void IRQ_SetRegister(unsigned int which, uint32 value);
int IRQ_StateAction(StateMem *sm, int load, int data_only);
};
#endif

543
mednafen/psx-0925/mdec.cpp Normal file
View File

@ -0,0 +1,543 @@
/* 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 "psx.h"
#include "mdec.h"
#include "../cdrom/SimpleFIFO.h"
#include <math.h>
#if defined(__SSE2__)
#include <xmmintrin.h>
#include <emmintrin.h>
#endif
#if defined(ARCH_POWERPC_ALTIVEC) && defined(HAVE_ALTIVEC_H)
#include <altivec.h>
#endif
namespace MDFN_IEN_PSX
{
static bool block_ready;
static int32 block_y[2][2][8][8];
static int32 block_cb[8][8]; // [y >> 1][x >> 1]
static int32 block_cr[8][8]; // [y >> 1][x >> 1]
static int32 run_time;
static uint32 Command;
static uint8 QMatrix[2][64];
static uint32 QMIndex;
static int16 IDCTMatrix[64] MDFN_ALIGN(16);
static uint32 IDCTMIndex;
static uint8 QScale;
static int16 Coeff[6][64] MDFN_ALIGN(16);
static uint32 CoeffIndex;
static uint32 DecodeWB;
static SimpleFIFO<uint16> InputBuffer(65536);
static SimpleFIFO<uint16> OutBuffer(384);
static uint32 InCounter;
static bool BlockEnd;
static bool DecodeEnd;
static const uint8 ZigZag[64] =
{
0x00, 0x01, 0x08, 0x10, 0x09, 0x02, 0x03, 0x0A,
0x11, 0x18, 0x20, 0x19, 0x12, 0x0B, 0x04, 0x05,
0x0C, 0x13, 0x1A, 0x21, 0x28, 0x30, 0x29, 0x22,
0x1B, 0x14, 0x0D, 0x06, 0x07, 0x0E, 0x15, 0x1C,
0x23, 0x2A, 0x31, 0x38, 0x39, 0x32, 0x2B, 0x24,
0x1D, 0x16, 0x0F, 0x17, 0x1E, 0x25, 0x2C, 0x33,
0x3A, 0x3B, 0x34, 0x2D, 0x26, 0x1F, 0x27, 0x2E,
0x35, 0x3C, 0x3D, 0x36, 0x2F, 0x37, 0x3E, 0x3F
};
void MDEC_Power(void)
{
run_time = 0;
block_ready = false;
Command = 0;
memset(QMatrix, 0, sizeof(QMatrix));
QMIndex = 0;
memset(IDCTMatrix, 0, sizeof(IDCTMatrix));
IDCTMIndex = 0;
QScale = 0;
memset(Coeff, 0, sizeof(Coeff));
CoeffIndex = 0;
DecodeWB = 0;
OutBuffer.Flush();
InCounter = 0;
BlockEnd = 0;
DecodeEnd = 0;
}
int MDEC_StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT StateRegs[] =
{
SFVAR(block_ready),
SFARRAY32(&block_y[0][0][0][0], sizeof(block_y) / sizeof(block_y[0][0][0][0])),
SFARRAY32(&block_cb[0][0], sizeof(block_cb) / sizeof(block_cb[0][0])),
SFARRAY32(&block_cr[0][0], sizeof(block_cr) / sizeof(block_cr[0][0])),
SFVAR(run_time),
SFVAR(Command),
SFARRAY(&QMatrix[0][0], sizeof(QMatrix) / sizeof(QMatrix[0][0])),
SFVAR(QMIndex),
SFARRAY16(&IDCTMatrix[0], sizeof(IDCTMatrix) / sizeof(IDCTMatrix[0])),
SFVAR(IDCTMIndex),
SFVAR(QScale),
SFARRAY16(&Coeff[0][0], sizeof(Coeff) / sizeof(Coeff[0][0])),
SFVAR(CoeffIndex),
SFVAR(DecodeWB),
#define SFFIFO16(fifoobj) SFARRAY16(&fifoobj.data[0], fifoobj.data.size()), \
SFVAR(fifoobj.read_pos), \
SFVAR(fifoobj.write_pos), \
SFVAR(fifoobj.in_count)
SFFIFO16(InputBuffer),
SFFIFO16(OutBuffer),
#undef SFFIFO
SFVAR(InCounter),
SFVAR(BlockEnd),
SFVAR(DecodeEnd),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "MDEC");
if(load)
{
}
return(ret);
}
static INLINE void WriteQTab(uint8 V)
{
QMatrix[QMIndex >> 6][QMIndex & 0x3F] = V;
QMIndex = (QMIndex + 1) & 0x7F;
}
static void DecodeImage(void);
static INLINE void WriteImageData(uint16 V)
{
const uint32 qmw = (bool)(DecodeWB < 2);
//printf("MDEC DMA SubWrite: %04x\n", V);
if(!CoeffIndex)
{
if(DecodeWB == 0 && V == 0xFE00)
{
InputBuffer.Flush();
return;
}
QScale = V >> 10;
Coeff[DecodeWB][ZigZag[0]] = sign_10_to_s16(V & 0x3FF) * QMatrix[qmw][0];
CoeffIndex++;
}
else
{
if(V == 0xFE00)
{
BlockEnd = true;
while(CoeffIndex < 64)
Coeff[DecodeWB][ZigZag[CoeffIndex++]] = 0;
}
else
{
uint32 rlcount = V >> 10;
for(uint32 i = 0; i < rlcount && CoeffIndex < 64; i++)
{
Coeff[DecodeWB][ZigZag[CoeffIndex]] = 0;
CoeffIndex++;
}
if(CoeffIndex < 64)
{
Coeff[DecodeWB][ZigZag[CoeffIndex]] = (sign_10_to_s16(V & 0x3FF) * QScale * QMatrix[qmw][CoeffIndex]) >> 3; // Arithmetic right shift or division(negative differs)?
CoeffIndex++;
}
}
}
if(CoeffIndex == 64 && BlockEnd)
{
BlockEnd = false;
CoeffIndex = 0;
//printf("Block %d finished\n", DecodeWB);
DecodeWB++;
if(DecodeWB == 6)
{
DecodeWB = 0;
DecodeImage();
}
}
}
static void IDCT(int16 *in_coeff, int32 *out_coeff)
{
#if defined(__SSE2__)
for(int i = 0; i < 8 * 8; i++)
{
__m128i sum = _mm_set1_epi32(0);
__m128i m0 = _mm_load_si128((__m128i *)&IDCTMatrix[((i & 7) * 8) + 0]);
int32 tmp[4] MDFN_ALIGN(16);
for(int v = 0; v < 8; v++)
{
__m128i c = _mm_load_si128((__m128i *)&in_coeff[v * 8]);
__m128i m1 = _mm_set1_epi16(IDCTMatrix[(i & ~7) + v]);
__m128i m = _mm_mulhi_epi16(m0, m1);
sum = _mm_add_epi32(sum, _mm_madd_epi16(c, m));
}
sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6)));
sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, (1 << 0) | (0 << 2)));
sum = _mm_srai_epi32(sum, 16);
//_mm_store_ss((float *)(out_coeff + i), (__m128)sum);
_mm_store_si128((__m128i*)tmp, sum);
out_coeff[i] = tmp[0]; //((tmp[0] + tmp[1]) + (tmp[2] + tmp[3])) >> 16;
}
#elif defined(ARCH_POWERPC_ALTIVEC)
static const uint8 snail_cake[16] MDFN_ALIGN(16) = {
0x00, 0x01, 0x10, 0x11,
0x04, 0x05, 0x14, 0x15,
0x08, 0x09, 0x18, 0x19,
0x0C, 0x0D, 0x1C, 0x1D };
vector unsigned char snail_pizza = vec_ld(0, snail_cake);
for(int i = 0; i < 8 * 8; i++)
{
vector signed int sum = vec_splat_s32(0);
vector signed short m0 = vec_ld((((i & 7) * 8) + 0) * sizeof(signed short), IDCTMatrix);
int32 tmp[4] MDFN_ALIGN(16);
for(int v = 0; v < 8; v++)
{
vector signed short c = vec_ld((v * 8) * sizeof(signed short), in_coeff);
vector signed short m1 = vec_splats(IDCTMatrix[(i & ~7) + v]);
#if 0
vector signed short m = vec_madds(m0, m1, vec_splat_s16(0)); // Has incorrect behavior for what we need.
#endif
vector signed int te = vec_mule(m0, m1);
vector signed int to = vec_mulo(m0, m1);
vector signed short m = (vector signed short)vec_perm(te, to, snail_pizza);
sum = vec_msum(c, m, sum);
}
vec_st(sum, 0, tmp);
out_coeff[i] = ((tmp[0] + tmp[1]) + (tmp[2] + tmp[3])) >> 16;
}
#else
for(int y = 0; y < 8; y++)
{
for(int x = 0; x < 8; x++)
{
int32 sum = 0;
for(int v = 0; v < 8; v++)
{
int16 *c = &in_coeff[v * 8];
int16 *m0 = &IDCTMatrix[(x * 8) + 0];
int16 *m1 = &IDCTMatrix[(y * 8) + v];
for(int u = 0; u < 8; u++)
{
sum += c[u] * ((m0[u] * m1[0]) >> 16);
}
}
out_coeff[y * 8 + x] = sum >> 16;
}
}
#endif
}
static void YCbCr_to_RGB(const int32 y, const int32 cb, const int32 cr, int &r, int &g, int &b)
{
r = (y + 128) + ((91881 * cr) >> 16);
g = (y + 128) - ((22525 * cb) >> 16) - ((46812 * cr) >> 16);
b = (y + 128) + ((116130 * cb) >> 16);
if(r < 0) r = 0;
if(r > 255) r = 255;
if(g < 0) g = 0;
if(g > 255) g = 255;
if(b < 0) b = 0;
if(b > 255) b = 255;
}
static void DecodeImage(void)
{
//puts("DECODE");
run_time -= 2048; //4096; //256; //1024; //2048; //8192; //1024; //4096;
IDCT(Coeff[0], &block_cr[0][0]);
IDCT(Coeff[1], &block_cb[0][0]);
IDCT(Coeff[2], &block_y[0][0][0][0]);
IDCT(Coeff[3], &block_y[0][1][0][0]);
IDCT(Coeff[4], &block_y[1][0][0][0]);
IDCT(Coeff[5], &block_y[1][1][0][0]);
block_ready = true;
}
static void EncodeImage(void)
{
//printf("ENCODE, %d\n", (Command & 0x08000000) ? 256 : 384);
block_ready = false;
if(!(Command & 0x08000000))
{
uint8 output[16][16][3]; // [y][x][cc]
for(int y = 0; y < 16; y++)
{
for(int x = 0; x < 16; x++)
{
int r, g, b;
YCbCr_to_RGB(block_y[(y >> 3) & 1][(x >> 3) & 1][y & 7][x & 7], block_cb[y >> 1][x >> 1], block_cr[y >> 1][x >> 1], r, g, b);
//r = y * 15;
//g = x * 15;
//b = 0;
output[y][x][0] = r;
output[y][x][1] = g;
output[y][x][2] = b;
}
}
for(int i = 0; i < 384; i++)
{
if(OutBuffer.CanWrite())
OutBuffer.WriteUnit((&output[0][0][0])[i * 2 + 0] | ((&output[0][0][0])[i * 2 + 1] << 8));
}
}
else
{
uint16 pixel_or = (Command & 0x02000000) ? 0x8000 : 0x0000;
for(int y = 0; y < 16; y++)
{
for(int x = 0; x < 16; x++)
{
int r, g, b;
YCbCr_to_RGB(block_y[(y >> 3) & 1][(x >> 3) & 1][y & 7][x & 7], block_cb[y >> 1][x >> 1], block_cr[y >> 1][x >> 1], r, g, b);
if(OutBuffer.CanWrite())
OutBuffer.WriteUnit(pixel_or | ((r >> 3) << 0) | ((g >> 3) << 5) | ((b >> 3) << 10));
}
}
}
}
void MDEC_DMAWrite(uint32 V)
{
if(Command == 0x60000000)
{
for(unsigned i = 0; i < 2; i++)
{
IDCTMatrix[((IDCTMIndex & 0x7) << 3) | ((IDCTMIndex >> 3) & 0x7)] = (int16)(V & 0xFFFF);
IDCTMIndex = (IDCTMIndex + 1) & 0x3F;
V >>= 16;
}
}
else if(Command == 0x40000001)
{
for(int i = 0; i < 4; i++)
{
WriteQTab((uint8)V);
V >>= 8;
}
}
else if((Command & 0xF5FF0000) == 0x30000000)
{
if(InCounter > 0)
{
for(int vi = 0; vi < 2; vi++)
{
if(InputBuffer.CanWrite())
InputBuffer.WriteUnit(V);
V >>= 16;
}
InCounter--;
}
}
else
{
printf("MYSTERY1: %08x\n", V);
}
}
uint32 MDEC_DMARead(void)
{
uint32 V = 0;
if((Command & 0xF5FF0000) == 0x30000000 && OutBuffer.CanRead() >= 2)
{
V = OutBuffer.ReadUnit() | (OutBuffer.ReadUnit() << 16);
}
else
{
puts("BONUS GNOMES");
V = rand();
}
return(V);
}
bool MDEC_DMACanRead(void)
{
return(OutBuffer.CanRead() >= 2); //(OutBuffer.CanRead() >= 2) || ((Command & 0xF5FF0000) != 0x30000000);
}
void MDEC_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)
{
PSX_WARNING("[MDEC] Write: 0x%08x 0x%08x, %d", A, V, timestamp);
if(A & 4)
{
if(V & 0x80000000) // Reset?
{
block_ready = false;
run_time = 0;
QMIndex = 0;
IDCTMIndex = 0;
QScale = 0;
memset(Coeff, 0, sizeof(Coeff));
CoeffIndex = 0;
DecodeWB = 0;
InputBuffer.Flush();
OutBuffer.Flush();
InCounter = 0;
BlockEnd = false;
}
}
else
{
Command = V;
if((Command & 0xF5FF0000) == 0x30000000)
{
InputBuffer.Flush();
OutBuffer.Flush();
block_ready = false;
BlockEnd = false;
CoeffIndex = 0;
DecodeWB = 0;
InCounter = V & 0xFFFF;
}
else if(Command == 0x60000000)
{
IDCTMIndex = 0;
}
else if(Command == 0x40000001)
{
QMIndex = 0;
}
}
}
uint32 MDEC_Read(const pscpu_timestamp_t timestamp, uint32 A)
{
uint32 ret = 0;
if(A & 4)
{
ret = 0;
if(InputBuffer.CanRead())
ret |= 0x20000000;
}
else
{
ret = Command;
}
//PSX_WARNING("[MDEC] Read: 0x%08x 0x%08x -- %d %d", A, ret, InputBuffer.CanRead(), InCounter);
return(ret);
}
void MDEC_Run(int32 clocks)
{
run_time += clocks;
while(run_time > 0)
{
run_time--;
if(block_ready && !OutBuffer.CanRead())
EncodeImage();
if(block_ready && OutBuffer.CanRead())
break;
if(!InputBuffer.CanRead())
break;
WriteImageData(InputBuffer.ReadUnit());
}
if(run_time > 0)
run_time = 0;
}
}

23
mednafen/psx-0925/mdec.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef __MDFN_PSX_MDEC_H
#define __MDFN_PSX_MDEC_H
namespace MDFN_IEN_PSX
{
void MDEC_DMAWrite(uint32 V);
uint32 MDEC_DMARead(void);
void MDEC_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V);
uint32 MDEC_Read(const pscpu_timestamp_t timestamp, uint32 A);
void MDEC_Power(void);
bool MDEC_DMACanRead(void);
void MDEC_Run(int32 clocks);
int MDEC_StateAction(StateMem *sm, int load, int data_only);
}
#endif

1878
mednafen/psx-0925/psx.cpp Normal file

File diff suppressed because it is too large Load Diff

87
mednafen/psx-0925/psx.h Normal file
View File

@ -0,0 +1,87 @@
#ifndef __MDFN_PSX_PSX_H
#define __MDFN_PSX_PSX_H
#include <mednafen/mednafen.h>
#include <mednafen/masmem.h>
#include <trio/trio.h>
#include "../cdrom/cdromif.h"
#include "../general.h"
#include "../FileWrapper.h"
//#define PSX_WARNING(format, ...) { printf(format "\n", ## __VA_ARGS__); }
//#define PSX_DBGINFO(format, ...) { /*printf(format "\n", ## __VA_ARGS__);*/ }
#define PSX_WARNING(format, ...)
#define PSX_DBGINFO(format, ...)
namespace MDFN_IEN_PSX
{
typedef int32 pscpu_timestamp_t;
bool MDFN_FASTCALL PSX_EventHandler(const pscpu_timestamp_t timestamp);
void MDFN_FASTCALL PSX_MemWrite8(const pscpu_timestamp_t timestamp, uint32 A, uint32 V);
void MDFN_FASTCALL PSX_MemWrite16(const pscpu_timestamp_t timestamp, uint32 A, uint32 V);
void MDFN_FASTCALL PSX_MemWrite24(const pscpu_timestamp_t timestamp, uint32 A, uint32 V);
void MDFN_FASTCALL PSX_MemWrite32(const pscpu_timestamp_t timestamp, uint32 A, uint32 V);
uint8 MDFN_FASTCALL PSX_MemRead8(const pscpu_timestamp_t timestamp, uint32 A);
uint16 MDFN_FASTCALL PSX_MemRead16(const pscpu_timestamp_t timestamp, uint32 A);
uint32 MDFN_FASTCALL PSX_MemRead24(const pscpu_timestamp_t timestamp, uint32 A);
uint32 MDFN_FASTCALL PSX_MemRead32(const pscpu_timestamp_t timestamp, uint32 A);
uint8 PSX_MemPeek8(uint32 A);
uint16 PSX_MemPeek16(uint32 A);
uint32 PSX_MemPeek32(uint32 A);
// Should write to WO-locations if possible
#if 0
void PSX_MemPoke8(uint32 A, uint8 V);
void PSX_MemPoke16(uint32 A, uint16 V);
void PSX_MemPoke32(uint32 A, uint32 V);
#endif
void PSX_RequestMLExit(void);
enum
{
PSX_EVENT__SYNFIRST = 0,
PSX_EVENT_GPU,
PSX_EVENT_CDC,
//PSX_EVENT_SPU,
PSX_EVENT_TIMER,
PSX_EVENT_DMA,
PSX_EVENT_FIO,
PSX_EVENT__SYNLAST,
PSX_EVENT__COUNT,
};
#define PSX_EVENT_MAXTS 0x20000000
void PSX_SetEventNT(const int type, const pscpu_timestamp_t next_timestamp);
void PSX_GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock);
};
#include "dis.h"
#include "cpu.h"
#include "irq.h"
#include "gpu.h"
#include "dma.h"
//#include "sio.h"
#include "debug.h"
namespace MDFN_IEN_PSX
{
class PS_CDC;
class PS_SPU;
extern PS_CPU *CPU;
extern PS_GPU *GPU;
extern PS_CDC *CDC;
extern PS_SPU *SPU;
extern MultiAccessSizeMem<2048 * 1024, uint32, false> MainRAM;
};
#endif

106
mednafen/psx-0925/sio.cpp Normal file
View File

@ -0,0 +1,106 @@
/* 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 "psx.h"
#include "sio.h"
namespace MDFN_IEN_PSX
{
// Dummy implementation.
static uint16 Status;
static uint16 Mode;
static uint16 Control;
static uint16 BaudRate;
static uint32 DataBuffer;
void SIO_Power(void)
{
Status = 0;
Mode = 0;
Control = 0;
BaudRate = 0;
DataBuffer = 0;
}
uint32 SIO_Read(pscpu_timestamp_t timestamp, uint32 A)
{
uint32 ret = 0;
switch(A & 0xE)
{
default:
PSX_WARNING("[SIO] Unknown read: 0x%08x -- %d\n", A, timestamp);
break;
case 0x0:
//case 0x2:
ret = DataBuffer >> ((A & 2) * 8);
break;
case 0x4:
ret = Status;
break;
case 0x8:
ret = Mode;
break;
case 0xA:
ret = Control;
break;
case 0xE:
ret = BaudRate;
break;
}
return(ret >> ((A & 1) * 8));
}
void SIO_Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V)
{
V <<= (A & 1) * 8;
switch(A & 0xE)
{
default:
PSX_WARNING("[SIO] Unknown write: 0x%08x 0x%08x -- %d\n", A, V, timestamp);
break;
case 0x0:
//case 0x2:
V <<= (A & 2) * 8;
DataBuffer = V;
break;
case 0x8:
Mode = V;
break;
case 0xA:
Control = V;
break;
case 0xE:
BaudRate = V;
break;
}
}
}

13
mednafen/psx-0925/sio.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __MDFN_PSX_SIO_H
#define __MDFN_PSX_SIO_H
namespace MDFN_IEN_PSX
{
void SIO_Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V);
uint32 SIO_Read(pscpu_timestamp_t timestamp, uint32 A);
void SIO_Power(void);
}
#endif

1565
mednafen/psx-0925/spu.cpp Normal file

File diff suppressed because it is too large Load Diff

338
mednafen/psx-0925/spu.h Normal file
View File

@ -0,0 +1,338 @@
#ifndef __MDFN_PSX_SPU_H
#define __MDFN_PSX_SPU_H
namespace MDFN_IEN_PSX
{
enum
{
ADSR_ATTACK = 0,
ADSR_DECAY = 1,
ADSR_SUSTAIN = 2,
ADSR_RELEASE = 3
};
struct SPU_ADSR
{
uint16 EnvLevel; // We typecast it to (int16) in several places, but keep it here as (uint16) to prevent signed overflow/underflow, which compilers
// may not treat consistently.
uint32 Divider;
uint32 Phase;
bool AttackExp;
bool SustainExp;
bool SustainDec;
bool ReleaseExp;
int32 AttackRate; // Ar
int32 DecayRate; // Dr * 4
int32 SustainRate; // Sr
int32 ReleaseRate; // Rr * 4
int32 SustainLevel; // (Sl + 1) << 11
};
class PS_SPU;
class SPU_Sweep
{
friend class PS_SPU; // For save states - FIXME(remove in future?)
public:
SPU_Sweep() { }
~SPU_Sweep() { }
void Power(void);
void WriteControl(uint16 value);
int16 ReadVolume(void);
void WriteVolume(int16 value);
void Clock(void);
private:
uint16 Control;
int16 Current;
uint32 Divider;
};
struct SPU_Voice
{
int32 DecodeBuffer[32 + 4]; // + 4 so we don't have to do & 0x1F in our MAC
int32 DecodeWritePos;
uint8 DecodeFlags;
SPU_Sweep Sweep[2];
uint16 Pitch;
uint32 CurPhase;
int32 CurPhase_SD; // Offseted compared to CurPhase, used for triggering sample decode.
uint32 StartAddr;
uint32 CurAddr;
uint32 ADSRControl;
uint32 LoopAddr;
int32 PreLRSample; // After enveloping, but before L/R volume. Range of -32768 to 32767
SPU_ADSR ADSR;
};
class PS_SPU
{
public:
PS_SPU();
~PS_SPU();
int StateAction(StateMem *sm, int load, int data_only);
void Power(void);
void Write(pscpu_timestamp_t timestamp, uint32 A, uint16 V);
uint16 Read(pscpu_timestamp_t timestamp, uint32 A);
void WriteDMA(uint32 V);
uint32 ReadDMA(void);
void StartFrame(double rate, uint32 quality);
int32 EndFrame(int16 *SoundBuf);
int32 UpdateFromCDC(int32 clocks);
//pscpu_timestamp_t Update(pscpu_timestamp_t timestamp);
static void DecodeADPCM(const uint8 *input, int16 *output, const unsigned shift, const unsigned weight);
private:
void CheckIRQAddr(uint32 addr);
void WriteSPURAM(uint32 addr, uint16 value);
uint16 ReadSPURAM(uint32 addr);
void DecodeSamples(SPU_Voice *voice);
void CacheEnvelope(SPU_Voice *voice);
void ResetEnvelope(SPU_Voice *voice);
void ReleaseEnvelope(SPU_Voice *voice);
void RunEnvelope(SPU_Voice *voice);
void RunReverb(int32 in_l, int32 in_r, int32 &out_l, int32 &out_r);
bool GetCDAudio(int32 &l, int32 &r);
SPU_Voice Voices[24];
uint32 NoiseCounter;
uint16 LFSR;
uint32 FM_Mode;
uint32 Noise_Mode;
uint32 Reverb_Mode;
int32 ReverbWA;
SPU_Sweep GlobalSweep[2]; // Doesn't affect reverb volume!
int32 ReverbVol[2];
int32 CDVol[2];
int32 ExternVol[2];
uint32 IRQAddr;
uint32 RWAddr;
uint16 SPUControl;
uint32 VoiceOn;
uint32 VoiceOff;
uint32 BlockEnd;
uint32 CWA;
int32 CDXA_ResampBuffer[2][4];
int32 CDXA_CurPhase;
union
{
uint16 Regs[0x100];
struct
{
uint16 VoiceRegs[0xC0];
union
{
uint16 GlobalRegs[0x20];
struct
{
uint16 _Global0[0x17];
uint16 SPUStatus;
uint16 _Global1[0x08];
};
};
union
{
int16 ReverbRegs[0x20];
struct
{
int16 FB_SRC_A;
int16 FB_SRC_B;
int16 IIR_ALPHA;
int16 ACC_COEF_A;
int16 ACC_COEF_B;
int16 ACC_COEF_C;
int16 ACC_COEF_D;
int16 IIR_COEF;
int16 FB_ALPHA;
int16 FB_X;
int16 IIR_DEST_A0;
int16 IIR_DEST_A1;
int16 ACC_SRC_A0;
int16 ACC_SRC_A1;
int16 ACC_SRC_B0;
int16 ACC_SRC_B1;
int16 IIR_SRC_A0;
int16 IIR_SRC_A1;
int16 IIR_DEST_B0;
int16 IIR_DEST_B1;
int16 ACC_SRC_C0;
int16 ACC_SRC_C1;
int16 ACC_SRC_D0;
int16 ACC_SRC_D1;
int16 IIR_SRC_B1;
int16 IIR_SRC_B0;
int16 MIX_DEST_A0;
int16 MIX_DEST_A1;
int16 MIX_DEST_B0;
int16 MIX_DEST_B1;
int16 IN_COEF_L;
int16 IN_COEF_R;
};
};
};
};
uint16 AuxRegs[0x10];
int16 RDSB[2][128]; // [40]
int32 RDSB_WP;
int16 RUSB[2][128];
int32 RUSB_WP;
int32 ReverbCur;
int32 Get_Reverb_Offset(int32 offset);
int32 RD_RVB(int16 raw_offs);
void WR_RVB(int16 raw_offs, int32 sample, int32 extra_offs = 0);
bool IRQAsserted;
//pscpu_timestamp_t lastts;
int32 clock_divider;
uint16 SPURAM[524288 / sizeof(uint16)];
int last_rate;
uint32 last_quality;
// Buffers 44.1KHz samples, should have enough for one video frame(~735 frames NTSC, ~882 PAL) plus jitter plus enough for the resampler leftovers.
// We'll just go with 4096 because powers of 2 are AWESOME and such.
uint32 IntermediateBufferPos;
int16 IntermediateBuffer[4096][2];
public:
enum
{
GSREG_SPUCONTROL = 0,
GSREG_FM_ON,
GSREG_NOISE_ON,
GSREG_REVERB_ON,
GSREG_CDVOL_L,
GSREG_CDVOL_R,
GSREG_DRYVOL_CTRL_L,
GSREG_DRYVOL_CTRL_R,
GSREG_DRYVOL_L,
GSREG_DRYVOL_R,
GSREG_WETVOL_L,
GSREG_WETVOL_R,
GSREG_RWADDR,
GSREG_IRQADDR,
GSREG_REVERBWA,
GSREG_VOICEON,
GSREG_VOICEOFF,
GSREG_BLOCKEND,
// Note: the order of these should match the reverb reg array
GSREG_FB_SRC_A,
GSREG_FB_SRC_B,
GSREG_IIR_ALPHA,
GSREG_ACC_COEF_A,
GSREG_ACC_COEF_B,
GSREG_ACC_COEF_C,
GSREG_ACC_COEF_D,
GSREG_IIR_COEF,
GSREG_FB_ALPHA,
GSREG_FB_X,
GSREG_IIR_DEST_A0,
GSREG_IIR_DEST_A1,
GSREG_ACC_SRC_A0,
GSREG_ACC_SRC_A1,
GSREG_ACC_SRC_B0,
GSREG_ACC_SRC_B1,
GSREG_IIR_SRC_A0,
GSREG_IIR_SRC_A1,
GSREG_IIR_DEST_B0,
GSREG_IIR_DEST_B1,
GSREG_ACC_SRC_C0,
GSREG_ACC_SRC_C1,
GSREG_ACC_SRC_D0,
GSREG_ACC_SRC_D1,
GSREG_IIR_SRC_B1,
GSREG_IIR_SRC_B0,
GSREG_MIX_DEST_A0,
GSREG_MIX_DEST_A1,
GSREG_MIX_DEST_B0,
GSREG_MIX_DEST_B1,
GSREG_IN_COEF_L,
GSREG_IN_COEF_R,
// Multiply v * 256 for each extra voice
GSREG_V0_VOL_CTRL_L = 0x8000,
GSREG_V0_VOL_CTRL_R,
GSREG_V0_VOL_L,
GSREG_V0_VOL_R,
GSREG_V0_PITCH,
GSREG_V0_STARTADDR,
GSREG_V0_ADSR_CTRL,
GSREG_V0_ADSR_LEVEL,
GSREG_V0_LOOP_ADDR,
GSREG_V0_READ_ADDR
};
uint32 GetRegister(unsigned int which, char *special, const uint32 special_len);
void SetRegister(unsigned int which, uint32 value);
uint16 PeekSPURAM(uint32 address);
void PokeSPURAM(uint32 address, uint16 value);
};
}
#endif

View File

@ -0,0 +1,256 @@
{ (int16)0x12c7, (int16)0x59b3, (int16)0x1307, (int16)0xffff },
{ (int16)0x1288, (int16)0x59b2, (int16)0x1347, (int16)0xffff },
{ (int16)0x1249, (int16)0x59b0, (int16)0x1388, (int16)0xffff },
{ (int16)0x120b, (int16)0x59ad, (int16)0x13c9, (int16)0xffff },
{ (int16)0x11cd, (int16)0x59a9, (int16)0x140b, (int16)0xffff },
{ (int16)0x118f, (int16)0x59a4, (int16)0x144d, (int16)0xffff },
{ (int16)0x1153, (int16)0x599e, (int16)0x1490, (int16)0xffff },
{ (int16)0x1116, (int16)0x5997, (int16)0x14d4, (int16)0xffff },
{ (int16)0x10db, (int16)0x598f, (int16)0x1517, (int16)0xffff },
{ (int16)0x109f, (int16)0x5986, (int16)0x155c, (int16)0xffff },
{ (int16)0x1065, (int16)0x597c, (int16)0x15a0, (int16)0xffff },
{ (int16)0x102a, (int16)0x5971, (int16)0x15e6, (int16)0xffff },
{ (int16)0x0ff1, (int16)0x5965, (int16)0x162c, (int16)0xffff },
{ (int16)0x0fb7, (int16)0x5958, (int16)0x1672, (int16)0xffff },
{ (int16)0x0f7f, (int16)0x5949, (int16)0x16b9, (int16)0xffff },
{ (int16)0x0f46, (int16)0x593a, (int16)0x1700, (int16)0xffff },
{ (int16)0x0f0f, (int16)0x592a, (int16)0x1747, (int16)0x0000 },
{ (int16)0x0ed7, (int16)0x5919, (int16)0x1790, (int16)0x0000 },
{ (int16)0x0ea1, (int16)0x5907, (int16)0x17d8, (int16)0x0000 },
{ (int16)0x0e6b, (int16)0x58f4, (int16)0x1821, (int16)0x0000 },
{ (int16)0x0e35, (int16)0x58e0, (int16)0x186b, (int16)0x0000 },
{ (int16)0x0e00, (int16)0x58cb, (int16)0x18b5, (int16)0x0000 },
{ (int16)0x0dcb, (int16)0x58b5, (int16)0x1900, (int16)0x0000 },
{ (int16)0x0d97, (int16)0x589e, (int16)0x194b, (int16)0x0001 },
{ (int16)0x0d63, (int16)0x5886, (int16)0x1996, (int16)0x0001 },
{ (int16)0x0d30, (int16)0x586d, (int16)0x19e2, (int16)0x0001 },
{ (int16)0x0cfd, (int16)0x5853, (int16)0x1a2e, (int16)0x0001 },
{ (int16)0x0ccb, (int16)0x5838, (int16)0x1a7b, (int16)0x0002 },
{ (int16)0x0c99, (int16)0x581c, (int16)0x1ac8, (int16)0x0002 },
{ (int16)0x0c68, (int16)0x57ff, (int16)0x1b16, (int16)0x0002 },
{ (int16)0x0c38, (int16)0x57e2, (int16)0x1b64, (int16)0x0003 },
{ (int16)0x0c07, (int16)0x57c3, (int16)0x1bb3, (int16)0x0003 },
{ (int16)0x0bd8, (int16)0x57a3, (int16)0x1c02, (int16)0x0003 },
{ (int16)0x0ba9, (int16)0x5782, (int16)0x1c51, (int16)0x0004 },
{ (int16)0x0b7a, (int16)0x5761, (int16)0x1ca1, (int16)0x0004 },
{ (int16)0x0b4c, (int16)0x573e, (int16)0x1cf1, (int16)0x0005 },
{ (int16)0x0b1e, (int16)0x571b, (int16)0x1d42, (int16)0x0005 },
{ (int16)0x0af1, (int16)0x56f6, (int16)0x1d93, (int16)0x0006 },
{ (int16)0x0ac4, (int16)0x56d1, (int16)0x1de5, (int16)0x0007 },
{ (int16)0x0a98, (int16)0x56ab, (int16)0x1e37, (int16)0x0007 },
{ (int16)0x0a6c, (int16)0x5684, (int16)0x1e89, (int16)0x0008 },
{ (int16)0x0a40, (int16)0x565b, (int16)0x1edc, (int16)0x0009 },
{ (int16)0x0a16, (int16)0x5632, (int16)0x1f2f, (int16)0x0009 },
{ (int16)0x09eb, (int16)0x5609, (int16)0x1f82, (int16)0x000a },
{ (int16)0x09c1, (int16)0x55de, (int16)0x1fd6, (int16)0x000b },
{ (int16)0x0998, (int16)0x55b2, (int16)0x202a, (int16)0x000c },
{ (int16)0x096f, (int16)0x5585, (int16)0x207f, (int16)0x000d },
{ (int16)0x0946, (int16)0x5558, (int16)0x20d4, (int16)0x000e },
{ (int16)0x091e, (int16)0x5529, (int16)0x2129, (int16)0x000f },
{ (int16)0x08f7, (int16)0x54fa, (int16)0x217f, (int16)0x0010 },
{ (int16)0x08d0, (int16)0x54ca, (int16)0x21d5, (int16)0x0011 },
{ (int16)0x08a9, (int16)0x5499, (int16)0x222c, (int16)0x0012 },
{ (int16)0x0883, (int16)0x5467, (int16)0x2282, (int16)0x0013 },
{ (int16)0x085d, (int16)0x5434, (int16)0x22da, (int16)0x0015 },
{ (int16)0x0838, (int16)0x5401, (int16)0x2331, (int16)0x0016 },
{ (int16)0x0813, (int16)0x53cc, (int16)0x2389, (int16)0x0018 },
{ (int16)0x07ef, (int16)0x5397, (int16)0x23e1, (int16)0x0019 },
{ (int16)0x07cb, (int16)0x5361, (int16)0x2439, (int16)0x001b },
{ (int16)0x07a7, (int16)0x532a, (int16)0x2492, (int16)0x001c },
{ (int16)0x0784, (int16)0x52f3, (int16)0x24eb, (int16)0x001e },
{ (int16)0x0762, (int16)0x52ba, (int16)0x2545, (int16)0x0020 },
{ (int16)0x0740, (int16)0x5281, (int16)0x259e, (int16)0x0021 },
{ (int16)0x071e, (int16)0x5247, (int16)0x25f8, (int16)0x0023 },
{ (int16)0x06fd, (int16)0x520c, (int16)0x2653, (int16)0x0025 },
{ (int16)0x06dc, (int16)0x51d0, (int16)0x26ad, (int16)0x0027 },
{ (int16)0x06bb, (int16)0x5194, (int16)0x2708, (int16)0x0029 },
{ (int16)0x069b, (int16)0x5156, (int16)0x2763, (int16)0x002c },
{ (int16)0x067c, (int16)0x5118, (int16)0x27be, (int16)0x002e },
{ (int16)0x065c, (int16)0x50da, (int16)0x281a, (int16)0x0030 },
{ (int16)0x063e, (int16)0x509a, (int16)0x2876, (int16)0x0033 },
{ (int16)0x061f, (int16)0x505a, (int16)0x28d2, (int16)0x0035 },
{ (int16)0x0601, (int16)0x5019, (int16)0x292e, (int16)0x0038 },
{ (int16)0x05e4, (int16)0x4fd7, (int16)0x298b, (int16)0x003a },
{ (int16)0x05c7, (int16)0x4f95, (int16)0x29e7, (int16)0x003d },
{ (int16)0x05aa, (int16)0x4f52, (int16)0x2a44, (int16)0x0040 },
{ (int16)0x058e, (int16)0x4f0e, (int16)0x2aa1, (int16)0x0043 },
{ (int16)0x0572, (int16)0x4ec9, (int16)0x2aff, (int16)0x0046 },
{ (int16)0x0556, (int16)0x4e84, (int16)0x2b5c, (int16)0x0049 },
{ (int16)0x053b, (int16)0x4e3e, (int16)0x2bba, (int16)0x004d },
{ (int16)0x0520, (int16)0x4df7, (int16)0x2c18, (int16)0x0050 },
{ (int16)0x0506, (int16)0x4db0, (int16)0x2c76, (int16)0x0054 },
{ (int16)0x04ec, (int16)0x4d68, (int16)0x2cd4, (int16)0x0057 },
{ (int16)0x04d2, (int16)0x4d20, (int16)0x2d33, (int16)0x005b },
{ (int16)0x04b9, (int16)0x4cd7, (int16)0x2d91, (int16)0x005f },
{ (int16)0x04a0, (int16)0x4c8d, (int16)0x2df0, (int16)0x0063 },
{ (int16)0x0488, (int16)0x4c42, (int16)0x2e4f, (int16)0x0067 },
{ (int16)0x0470, (int16)0x4bf7, (int16)0x2eae, (int16)0x006b },
{ (int16)0x0458, (int16)0x4bac, (int16)0x2f0d, (int16)0x006f },
{ (int16)0x0441, (int16)0x4b5f, (int16)0x2f6c, (int16)0x0074 },
{ (int16)0x042a, (int16)0x4b13, (int16)0x2fcc, (int16)0x0078 },
{ (int16)0x0413, (int16)0x4ac5, (int16)0x302b, (int16)0x007d },
{ (int16)0x03fc, (int16)0x4a77, (int16)0x308b, (int16)0x0082 },
{ (int16)0x03e7, (int16)0x4a29, (int16)0x30ea, (int16)0x0087 },
{ (int16)0x03d1, (int16)0x49d9, (int16)0x314a, (int16)0x008c },
{ (int16)0x03bc, (int16)0x498a, (int16)0x31aa, (int16)0x0091 },
{ (int16)0x03a7, (int16)0x493a, (int16)0x3209, (int16)0x0096 },
{ (int16)0x0392, (int16)0x48e9, (int16)0x3269, (int16)0x009c },
{ (int16)0x037e, (int16)0x4898, (int16)0x32c9, (int16)0x00a1 },
{ (int16)0x036a, (int16)0x4846, (int16)0x3329, (int16)0x00a7 },
{ (int16)0x0356, (int16)0x47f4, (int16)0x3389, (int16)0x00ad },
{ (int16)0x0343, (int16)0x47a1, (int16)0x33e9, (int16)0x00b3 },
{ (int16)0x0330, (int16)0x474e, (int16)0x3449, (int16)0x00ba },
{ (int16)0x031d, (int16)0x46fa, (int16)0x34a9, (int16)0x00c0 },
{ (int16)0x030b, (int16)0x46a6, (int16)0x3509, (int16)0x00c7 },
{ (int16)0x02f9, (int16)0x4651, (int16)0x3569, (int16)0x00cd },
{ (int16)0x02e7, (int16)0x45fc, (int16)0x35c9, (int16)0x00d4 },
{ (int16)0x02d6, (int16)0x45a6, (int16)0x3629, (int16)0x00db },
{ (int16)0x02c4, (int16)0x4550, (int16)0x3689, (int16)0x00e3 },
{ (int16)0x02b4, (int16)0x44fa, (int16)0x36e8, (int16)0x00ea },
{ (int16)0x02a3, (int16)0x44a3, (int16)0x3748, (int16)0x00f2 },
{ (int16)0x0293, (int16)0x444c, (int16)0x37a8, (int16)0x00fa },
{ (int16)0x0283, (int16)0x43f4, (int16)0x3807, (int16)0x0101 },
{ (int16)0x0273, (int16)0x439c, (int16)0x3867, (int16)0x010a },
{ (int16)0x0264, (int16)0x4344, (int16)0x38c6, (int16)0x0112 },
{ (int16)0x0255, (int16)0x42eb, (int16)0x3926, (int16)0x011b },
{ (int16)0x0246, (int16)0x4292, (int16)0x3985, (int16)0x0123 },
{ (int16)0x0237, (int16)0x4239, (int16)0x39e4, (int16)0x012c },
{ (int16)0x0229, (int16)0x41df, (int16)0x3a43, (int16)0x0135 },
{ (int16)0x021b, (int16)0x4185, (int16)0x3aa2, (int16)0x013f },
{ (int16)0x020d, (int16)0x412a, (int16)0x3b00, (int16)0x0148 },
{ (int16)0x0200, (int16)0x40d0, (int16)0x3b5f, (int16)0x0152 },
{ (int16)0x01f2, (int16)0x4074, (int16)0x3bbd, (int16)0x015c },
{ (int16)0x01e5, (int16)0x4019, (int16)0x3c1b, (int16)0x0166 },
{ (int16)0x01d9, (int16)0x3fbd, (int16)0x3c79, (int16)0x0171 },
{ (int16)0x01cc, (int16)0x3f62, (int16)0x3cd7, (int16)0x017b },
{ (int16)0x01c0, (int16)0x3f05, (int16)0x3d35, (int16)0x0186 },
{ (int16)0x01b4, (int16)0x3ea9, (int16)0x3d92, (int16)0x0191 },
{ (int16)0x01a8, (int16)0x3e4c, (int16)0x3def, (int16)0x019c },
{ (int16)0x019c, (int16)0x3def, (int16)0x3e4c, (int16)0x01a8 },
{ (int16)0x0191, (int16)0x3d92, (int16)0x3ea9, (int16)0x01b4 },
{ (int16)0x0186, (int16)0x3d35, (int16)0x3f05, (int16)0x01c0 },
{ (int16)0x017b, (int16)0x3cd7, (int16)0x3f62, (int16)0x01cc },
{ (int16)0x0171, (int16)0x3c79, (int16)0x3fbd, (int16)0x01d9 },
{ (int16)0x0166, (int16)0x3c1b, (int16)0x4019, (int16)0x01e5 },
{ (int16)0x015c, (int16)0x3bbd, (int16)0x4074, (int16)0x01f2 },
{ (int16)0x0152, (int16)0x3b5f, (int16)0x40d0, (int16)0x0200 },
{ (int16)0x0148, (int16)0x3b00, (int16)0x412a, (int16)0x020d },
{ (int16)0x013f, (int16)0x3aa2, (int16)0x4185, (int16)0x021b },
{ (int16)0x0135, (int16)0x3a43, (int16)0x41df, (int16)0x0229 },
{ (int16)0x012c, (int16)0x39e4, (int16)0x4239, (int16)0x0237 },
{ (int16)0x0123, (int16)0x3985, (int16)0x4292, (int16)0x0246 },
{ (int16)0x011b, (int16)0x3926, (int16)0x42eb, (int16)0x0255 },
{ (int16)0x0112, (int16)0x38c6, (int16)0x4344, (int16)0x0264 },
{ (int16)0x010a, (int16)0x3867, (int16)0x439c, (int16)0x0273 },
{ (int16)0x0101, (int16)0x3807, (int16)0x43f4, (int16)0x0283 },
{ (int16)0x00fa, (int16)0x37a8, (int16)0x444c, (int16)0x0293 },
{ (int16)0x00f2, (int16)0x3748, (int16)0x44a3, (int16)0x02a3 },
{ (int16)0x00ea, (int16)0x36e8, (int16)0x44fa, (int16)0x02b4 },
{ (int16)0x00e3, (int16)0x3689, (int16)0x4550, (int16)0x02c4 },
{ (int16)0x00db, (int16)0x3629, (int16)0x45a6, (int16)0x02d6 },
{ (int16)0x00d4, (int16)0x35c9, (int16)0x45fc, (int16)0x02e7 },
{ (int16)0x00cd, (int16)0x3569, (int16)0x4651, (int16)0x02f9 },
{ (int16)0x00c7, (int16)0x3509, (int16)0x46a6, (int16)0x030b },
{ (int16)0x00c0, (int16)0x34a9, (int16)0x46fa, (int16)0x031d },
{ (int16)0x00ba, (int16)0x3449, (int16)0x474e, (int16)0x0330 },
{ (int16)0x00b3, (int16)0x33e9, (int16)0x47a1, (int16)0x0343 },
{ (int16)0x00ad, (int16)0x3389, (int16)0x47f4, (int16)0x0356 },
{ (int16)0x00a7, (int16)0x3329, (int16)0x4846, (int16)0x036a },
{ (int16)0x00a1, (int16)0x32c9, (int16)0x4898, (int16)0x037e },
{ (int16)0x009c, (int16)0x3269, (int16)0x48e9, (int16)0x0392 },
{ (int16)0x0096, (int16)0x3209, (int16)0x493a, (int16)0x03a7 },
{ (int16)0x0091, (int16)0x31aa, (int16)0x498a, (int16)0x03bc },
{ (int16)0x008c, (int16)0x314a, (int16)0x49d9, (int16)0x03d1 },
{ (int16)0x0087, (int16)0x30ea, (int16)0x4a29, (int16)0x03e7 },
{ (int16)0x0082, (int16)0x308b, (int16)0x4a77, (int16)0x03fc },
{ (int16)0x007d, (int16)0x302b, (int16)0x4ac5, (int16)0x0413 },
{ (int16)0x0078, (int16)0x2fcc, (int16)0x4b13, (int16)0x042a },
{ (int16)0x0074, (int16)0x2f6c, (int16)0x4b5f, (int16)0x0441 },
{ (int16)0x006f, (int16)0x2f0d, (int16)0x4bac, (int16)0x0458 },
{ (int16)0x006b, (int16)0x2eae, (int16)0x4bf7, (int16)0x0470 },
{ (int16)0x0067, (int16)0x2e4f, (int16)0x4c42, (int16)0x0488 },
{ (int16)0x0063, (int16)0x2df0, (int16)0x4c8d, (int16)0x04a0 },
{ (int16)0x005f, (int16)0x2d91, (int16)0x4cd7, (int16)0x04b9 },
{ (int16)0x005b, (int16)0x2d33, (int16)0x4d20, (int16)0x04d2 },
{ (int16)0x0057, (int16)0x2cd4, (int16)0x4d68, (int16)0x04ec },
{ (int16)0x0054, (int16)0x2c76, (int16)0x4db0, (int16)0x0506 },
{ (int16)0x0050, (int16)0x2c18, (int16)0x4df7, (int16)0x0520 },
{ (int16)0x004d, (int16)0x2bba, (int16)0x4e3e, (int16)0x053b },
{ (int16)0x0049, (int16)0x2b5c, (int16)0x4e84, (int16)0x0556 },
{ (int16)0x0046, (int16)0x2aff, (int16)0x4ec9, (int16)0x0572 },
{ (int16)0x0043, (int16)0x2aa1, (int16)0x4f0e, (int16)0x058e },
{ (int16)0x0040, (int16)0x2a44, (int16)0x4f52, (int16)0x05aa },
{ (int16)0x003d, (int16)0x29e7, (int16)0x4f95, (int16)0x05c7 },
{ (int16)0x003a, (int16)0x298b, (int16)0x4fd7, (int16)0x05e4 },
{ (int16)0x0038, (int16)0x292e, (int16)0x5019, (int16)0x0601 },
{ (int16)0x0035, (int16)0x28d2, (int16)0x505a, (int16)0x061f },
{ (int16)0x0033, (int16)0x2876, (int16)0x509a, (int16)0x063e },
{ (int16)0x0030, (int16)0x281a, (int16)0x50da, (int16)0x065c },
{ (int16)0x002e, (int16)0x27be, (int16)0x5118, (int16)0x067c },
{ (int16)0x002c, (int16)0x2763, (int16)0x5156, (int16)0x069b },
{ (int16)0x0029, (int16)0x2708, (int16)0x5194, (int16)0x06bb },
{ (int16)0x0027, (int16)0x26ad, (int16)0x51d0, (int16)0x06dc },
{ (int16)0x0025, (int16)0x2653, (int16)0x520c, (int16)0x06fd },
{ (int16)0x0023, (int16)0x25f8, (int16)0x5247, (int16)0x071e },
{ (int16)0x0021, (int16)0x259e, (int16)0x5281, (int16)0x0740 },
{ (int16)0x0020, (int16)0x2545, (int16)0x52ba, (int16)0x0762 },
{ (int16)0x001e, (int16)0x24eb, (int16)0x52f3, (int16)0x0784 },
{ (int16)0x001c, (int16)0x2492, (int16)0x532a, (int16)0x07a7 },
{ (int16)0x001b, (int16)0x2439, (int16)0x5361, (int16)0x07cb },
{ (int16)0x0019, (int16)0x23e1, (int16)0x5397, (int16)0x07ef },
{ (int16)0x0018, (int16)0x2389, (int16)0x53cc, (int16)0x0813 },
{ (int16)0x0016, (int16)0x2331, (int16)0x5401, (int16)0x0838 },
{ (int16)0x0015, (int16)0x22da, (int16)0x5434, (int16)0x085d },
{ (int16)0x0013, (int16)0x2282, (int16)0x5467, (int16)0x0883 },
{ (int16)0x0012, (int16)0x222c, (int16)0x5499, (int16)0x08a9 },
{ (int16)0x0011, (int16)0x21d5, (int16)0x54ca, (int16)0x08d0 },
{ (int16)0x0010, (int16)0x217f, (int16)0x54fa, (int16)0x08f7 },
{ (int16)0x000f, (int16)0x2129, (int16)0x5529, (int16)0x091e },
{ (int16)0x000e, (int16)0x20d4, (int16)0x5558, (int16)0x0946 },
{ (int16)0x000d, (int16)0x207f, (int16)0x5585, (int16)0x096f },
{ (int16)0x000c, (int16)0x202a, (int16)0x55b2, (int16)0x0998 },
{ (int16)0x000b, (int16)0x1fd6, (int16)0x55de, (int16)0x09c1 },
{ (int16)0x000a, (int16)0x1f82, (int16)0x5609, (int16)0x09eb },
{ (int16)0x0009, (int16)0x1f2f, (int16)0x5632, (int16)0x0a16 },
{ (int16)0x0009, (int16)0x1edc, (int16)0x565b, (int16)0x0a40 },
{ (int16)0x0008, (int16)0x1e89, (int16)0x5684, (int16)0x0a6c },
{ (int16)0x0007, (int16)0x1e37, (int16)0x56ab, (int16)0x0a98 },
{ (int16)0x0007, (int16)0x1de5, (int16)0x56d1, (int16)0x0ac4 },
{ (int16)0x0006, (int16)0x1d93, (int16)0x56f6, (int16)0x0af1 },
{ (int16)0x0005, (int16)0x1d42, (int16)0x571b, (int16)0x0b1e },
{ (int16)0x0005, (int16)0x1cf1, (int16)0x573e, (int16)0x0b4c },
{ (int16)0x0004, (int16)0x1ca1, (int16)0x5761, (int16)0x0b7a },
{ (int16)0x0004, (int16)0x1c51, (int16)0x5782, (int16)0x0ba9 },
{ (int16)0x0003, (int16)0x1c02, (int16)0x57a3, (int16)0x0bd8 },
{ (int16)0x0003, (int16)0x1bb3, (int16)0x57c3, (int16)0x0c07 },
{ (int16)0x0003, (int16)0x1b64, (int16)0x57e2, (int16)0x0c38 },
{ (int16)0x0002, (int16)0x1b16, (int16)0x57ff, (int16)0x0c68 },
{ (int16)0x0002, (int16)0x1ac8, (int16)0x581c, (int16)0x0c99 },
{ (int16)0x0002, (int16)0x1a7b, (int16)0x5838, (int16)0x0ccb },
{ (int16)0x0001, (int16)0x1a2e, (int16)0x5853, (int16)0x0cfd },
{ (int16)0x0001, (int16)0x19e2, (int16)0x586d, (int16)0x0d30 },
{ (int16)0x0001, (int16)0x1996, (int16)0x5886, (int16)0x0d63 },
{ (int16)0x0001, (int16)0x194b, (int16)0x589e, (int16)0x0d97 },
{ (int16)0x0000, (int16)0x1900, (int16)0x58b5, (int16)0x0dcb },
{ (int16)0x0000, (int16)0x18b5, (int16)0x58cb, (int16)0x0e00 },
{ (int16)0x0000, (int16)0x186b, (int16)0x58e0, (int16)0x0e35 },
{ (int16)0x0000, (int16)0x1821, (int16)0x58f4, (int16)0x0e6b },
{ (int16)0x0000, (int16)0x17d8, (int16)0x5907, (int16)0x0ea1 },
{ (int16)0x0000, (int16)0x1790, (int16)0x5919, (int16)0x0ed7 },
{ (int16)0x0000, (int16)0x1747, (int16)0x592a, (int16)0x0f0f },
{ (int16)0xffff, (int16)0x1700, (int16)0x593a, (int16)0x0f46 },
{ (int16)0xffff, (int16)0x16b9, (int16)0x5949, (int16)0x0f7f },
{ (int16)0xffff, (int16)0x1672, (int16)0x5958, (int16)0x0fb7 },
{ (int16)0xffff, (int16)0x162c, (int16)0x5965, (int16)0x0ff1 },
{ (int16)0xffff, (int16)0x15e6, (int16)0x5971, (int16)0x102a },
{ (int16)0xffff, (int16)0x15a0, (int16)0x597c, (int16)0x1065 },
{ (int16)0xffff, (int16)0x155c, (int16)0x5986, (int16)0x109f },
{ (int16)0xffff, (int16)0x1517, (int16)0x598f, (int16)0x10db },
{ (int16)0xffff, (int16)0x14d4, (int16)0x5997, (int16)0x1116 },
{ (int16)0xffff, (int16)0x1490, (int16)0x599e, (int16)0x1153 },
{ (int16)0xffff, (int16)0x144d, (int16)0x59a4, (int16)0x118f },
{ (int16)0xffff, (int16)0x140b, (int16)0x59a9, (int16)0x11cd },
{ (int16)0xffff, (int16)0x13c9, (int16)0x59ad, (int16)0x120b },
{ (int16)0xffff, (int16)0x1388, (int16)0x59b0, (int16)0x1249 },
{ (int16)0xffff, (int16)0x1347, (int16)0x59b2, (int16)0x1288 },
{ (int16)0xffff, (int16)0x1307, (int16)0x59b3, (int16)0x12c7 },

View File

@ -0,0 +1,64 @@
0x00000001,
0x00000001,
0x00000001,
0x00000001,
0x00000002,
0x00000002,
0x00000002,
0x00000002,
0x00000004,
0x00000005,
0x00000006,
0x00000007,
0x00000008,
0x0000000a,
0x0000000c,
0x0000000e,
0x00000010,
0x00000014,
0x00000018,
0x0000001c,
0x00000020,
0x00000028,
0x00000030,
0x00000038,
0x00000040,
0x00000050,
0x00000060,
0x00000070,
0x00000080,
0x000000a0,
0x000000c0,
0x000000e0,
0x00000100,
0x00000140,
0x00000180,
0x000001c0,
0x00000200,
0x00000280,
0x00000300,
0x00000380,
0x00000400,
0x00000500,
0x00000600,
0x00000700,
0x00000800,
0x00000a00,
0x00000c00,
0x00000e00,
0x00001000,
0x00001400,
0x00001800,
0x00001c00,
0x00002000,
0x00002800,
0x00003000,
0x00003800,
0x00004000,
0x00005000,
0x00006000,
0x00007000,
0x00008000,
0x00008000,
0x00008000,
0x00008000,

View File

@ -0,0 +1,237 @@
static int16 ReverbSat(int32 samp) MDFN_WARN_UNUSED_RESULT;
static INLINE int16 ReverbSat(int32 samp)
{
if(samp > 32767)
samp = 32767;
if(samp < -32768)
samp = -32768;
return(samp);
}
INLINE int32 PS_SPU::Get_Reverb_Offset(int32 in_offset)
{
int32 offset = in_offset & 0x3FFFF;
int32 wa_size = 0x40000 - ReverbWA;
if(offset & 0x20000)
{
offset -= ReverbWA;
if(offset < 0)
{
offset = 0;
//PSX_WARNING("[SPU] A reverb offset is broken(-).");
}
}
else
{
if(offset >= wa_size)
{
offset = wa_size - 1;
//PSX_WARNING("[SPU] A reverb offset is broken(+): WASize=0x%04x, 0x%04x.", wa_size >> 2, in_offset >> 2);
}
}
offset += ReverbCur;
if(offset >= 0x40000)
offset = (offset & 0x3FFFF) + ReverbWA;
assert(offset >= ReverbWA && offset < 0x40000);
return(offset);
}
int32 PS_SPU::RD_RVB(int16 raw_offs)
{
//raw_offs = rand() & 0xFFFF;
return((int16)SPURAM[Get_Reverb_Offset(raw_offs << 2)]);
}
void PS_SPU::WR_RVB(int16 raw_offs, int32 sample, int32 extra_offs)
{
//raw_offs = rand() & 0xFFFF;
SPURAM[Get_Reverb_Offset((raw_offs << 2) + extra_offs)] = ReverbSat(sample);
}
static INLINE int32 Reverb4422(const int16 *src)
{
static const int16 ResampTable[40] =
{
(int16)0xffff,
(int16)0x0000,
(int16)0x0002,
(int16)0x0000,
(int16)0xfff6,
(int16)0x0000,
(int16)0x0023,
(int16)0x0000,
(int16)0xff99,
(int16)0x0000,
(int16)0x010a,
(int16)0x0000,
(int16)0xfd98,
(int16)0x0000,
(int16)0x0534,
(int16)0x0000,
(int16)0xf470,
(int16)0x0000,
(int16)0x2806,
(int16)0x4000,
(int16)0x2806,
(int16)0x0000,
(int16)0xf470,
(int16)0x0000,
(int16)0x0534,
(int16)0x0000,
(int16)0xfd98,
(int16)0x0000,
(int16)0x010a,
(int16)0x0000,
(int16)0xff99,
(int16)0x0000,
(int16)0x0023,
(int16)0x0000,
(int16)0xfff6,
(int16)0x0000,
(int16)0x0002,
(int16)0x0000,
(int16)0xffff,
(int16)0x0000,
};
int32 out = 0; // 32-bits is adequate(it won't overflow)
for(int i = 0; i < 40; i += 2)
out += ResampTable[i] * src[i];
// Middle non-zero
out += 0x4000 * src[19];
out >>= 15;
if(out < -32768)
out = -32768;
if(out > 32767)
out = 32767;
return(out);
}
void PS_SPU::RunReverb(int32 in_l, int32 in_r, int32 &out_l, int32 &out_r)
{
int32 upsampled[2] = { 0, 0 };
RDSB[0][RDSB_WP] = in_l;
RDSB[1][RDSB_WP] = in_r;
RDSB[0][RDSB_WP | 0x40] = in_l; // So we don't have to &/bounds check in our MAC loop
RDSB[1][RDSB_WP | 0x40] = in_r;
RDSB_WP = (RDSB_WP + 1) & 0x3F;
if(!(RDSB_WP & 1))
{
int32 downsampled[2];
for(int lr = 0; lr < 2; lr++)
downsampled[lr] = Reverb4422(&RDSB[lr][(RDSB_WP - 40) & 0x3F]);
//
// Run algorithm
///
if(SPUControl & 0x80)
{
int32 IIR_INPUT_A0;
int32 IIR_INPUT_A1;
int32 IIR_INPUT_B0;
int32 IIR_INPUT_B1;
int32 IIR_A0, IIR_A1, IIR_B0, IIR_B1;
int32 ACC0, ACC1;
int32 FB_A0, FB_A1, FB_B0, FB_B1;
IIR_INPUT_A0 = ((RD_RVB(IIR_SRC_A0) * IIR_COEF) >> 15) + ((downsampled[0] * IN_COEF_L) >> 15);
IIR_INPUT_A1 = ((RD_RVB(IIR_SRC_A1) * IIR_COEF) >> 15) + ((downsampled[1] * IN_COEF_R) >> 15);
IIR_INPUT_B0 = ((RD_RVB(IIR_SRC_B0) * IIR_COEF) >> 15) + ((downsampled[0] * IN_COEF_L) >> 15);
IIR_INPUT_B1 = ((RD_RVB(IIR_SRC_B1) * IIR_COEF) >> 15) + ((downsampled[1] * IN_COEF_R) >> 15);
IIR_A0 = (((int64)IIR_INPUT_A0 * IIR_ALPHA) >> 15) + ((RD_RVB(IIR_DEST_A0) * (32768 - IIR_ALPHA)) >> 15);
IIR_A1 = (((int64)IIR_INPUT_A1 * IIR_ALPHA) >> 15) + ((RD_RVB(IIR_DEST_A1) * (32768 - IIR_ALPHA)) >> 15);
IIR_B0 = (((int64)IIR_INPUT_B0 * IIR_ALPHA) >> 15) + ((RD_RVB(IIR_DEST_B0) * (32768 - IIR_ALPHA)) >> 15);
IIR_B1 = (((int64)IIR_INPUT_B1 * IIR_ALPHA) >> 15) + ((RD_RVB(IIR_DEST_B1) * (32768 - IIR_ALPHA)) >> 15);
WR_RVB(IIR_DEST_A0, IIR_A0, 1);
WR_RVB(IIR_DEST_A1, IIR_A1, 1);
WR_RVB(IIR_DEST_B0, IIR_B0, 1);
WR_RVB(IIR_DEST_B1, IIR_B1, 1);
#if 0
ACC0 = ((RD_RVB(ACC_SRC_A0) * ACC_COEF_A) >> 15) +
((RD_RVB(ACC_SRC_B0) * ACC_COEF_B) >> 15) +
((RD_RVB(ACC_SRC_C0) * ACC_COEF_C) >> 15) +
((RD_RVB(ACC_SRC_D0) * ACC_COEF_D) >> 15);
ACC1 = ((RD_RVB(ACC_SRC_A1) * ACC_COEF_A) >> 15) +
((RD_RVB(ACC_SRC_B1) * ACC_COEF_B) >> 15) +
((RD_RVB(ACC_SRC_C1) * ACC_COEF_C) >> 15) +
((RD_RVB(ACC_SRC_D1) * ACC_COEF_D) >> 15);
#endif
ACC0 = ((int64)(RD_RVB(ACC_SRC_A0) * ACC_COEF_A) +
(RD_RVB(ACC_SRC_B0) * ACC_COEF_B) +
(RD_RVB(ACC_SRC_C0) * ACC_COEF_C) +
(RD_RVB(ACC_SRC_D0) * ACC_COEF_D)) >> 15;
ACC1 = ((int64)(RD_RVB(ACC_SRC_A1) * ACC_COEF_A) +
(RD_RVB(ACC_SRC_B1) * ACC_COEF_B) +
(RD_RVB(ACC_SRC_C1) * ACC_COEF_C) +
(RD_RVB(ACC_SRC_D1) * ACC_COEF_D)) >> 15;
FB_A0 = RD_RVB(MIX_DEST_A0 - FB_SRC_A);
FB_A1 = RD_RVB(MIX_DEST_A1 - FB_SRC_A);
FB_B0 = RD_RVB(MIX_DEST_B0 - FB_SRC_B);
FB_B1 = RD_RVB(MIX_DEST_B1 - FB_SRC_B);
WR_RVB(MIX_DEST_A0, ACC0 - ((FB_A0 * FB_ALPHA) >> 15));
WR_RVB(MIX_DEST_A1, ACC1 - ((FB_A1 * FB_ALPHA) >> 15));
WR_RVB(MIX_DEST_B0, (((int64)FB_ALPHA * ACC0) >> 15) - ((FB_A0 * (int16)(0x8000 ^ FB_ALPHA)) >> 15) - ((FB_B0 * FB_X) >> 15));
WR_RVB(MIX_DEST_B1, (((int64)FB_ALPHA * ACC1) >> 15) - ((FB_A1 * (int16)(0x8000 ^ FB_ALPHA)) >> 15) - ((FB_B1 * FB_X) >> 15));
}
//
// Get output samples
//
// RUSB[0][RUSB_WP | 0x40] = RUSB[0][RUSB_WP] = (short)rand();
// RUSB[1][RUSB_WP | 0x40] = RUSB[1][RUSB_WP] = (short)rand();
RUSB[0][RUSB_WP | 0x40] = RUSB[0][RUSB_WP] = (RD_RVB(MIX_DEST_A0) + RD_RVB(MIX_DEST_B0)) >> 1;
RUSB[1][RUSB_WP | 0x40] = RUSB[1][RUSB_WP] = (RD_RVB(MIX_DEST_A1) + RD_RVB(MIX_DEST_B1)) >> 1;
RUSB_WP = (RUSB_WP + 1) & 0x3F;
ReverbCur = (ReverbCur + 1) & 0x3FFFF;
if(!ReverbCur)
ReverbCur = ReverbWA;
}
else
{
RUSB[0][RUSB_WP | 0x40] = RUSB[0][RUSB_WP] = 0;
RUSB[1][RUSB_WP | 0x40] = RUSB[1][RUSB_WP] = 0;
RUSB_WP = (RUSB_WP + 1) & 0x3F;
}
for(int lr = 0; lr < 2; lr++)
upsampled[lr] = Reverb4422(&RUSB[lr][(RUSB_WP - 40) & 0x3F]);
out_l = upsampled[0];
out_r = upsampled[1];
}

512
mednafen/psx-0925/timer.cpp Normal file
View File

@ -0,0 +1,512 @@
/* 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 "psx.h"
#include "timer.h"
/*
Notes(some of it may be incomplete or wrong in subtle ways)
Control bits:
Lower 3 bits of mode, for timer1:
0x1 = don't count during vblank
0x3 = vblank going inactive triggers timer reset
0x5 = vblank going inactive triggers timer reset, and only count within vblank.
0x7 = Wait until vblank goes active then inactive, then start counting?
For timer2:
0x1 = timer stopped(TODO: confirm on real system)
Target mode enabled 0x008
IRQ enable 0x010
--?Affects 0x400 status flag?-- 0x020
IRQ evaluation auto-reset 0x040
--unknown-- 0x080
Clock selection 0x100
Divide by 8(timer 2 only?) 0x200
Counter:
Reset to 0 on writes to the mode/status register.
Status flags:
Unknown flag 0x0400
Compare flag 0x0800
Cleared on mode/status read.
Set when: //ever Counter == 0(proooobably, need to investigate lower 3 bits in relation to this).
Overflow/Carry flag 0x1000
Cleared on mode/status read.
Set when counter overflows from 0xFFFF->0.
Hidden flags:
IRQ done
Cleared on writes to the mode/status register, on writes to the count register, and apparently automatically when the counter
increments if (Mode & 0x40) [Note: If target mode is enabled, and target is 0, IRQ done flag won't be automatically reset]
There seems to be a brief period(edge condition?) where, if count to target is enabled, you can (sometimes?) read the target value in the count
register before it's reset to 0. I doubt any games rely on this, but who knows. Maybe a PSX equivalent of the PC Engine "Battle Royale"? ;)
When the counter == 0, the compare flag is set. An IRQ will be generated if (Mode & 0x10), and the hidden IRQ done flag will be set.
*/
/*
Dec. 26, 2011 Note
Due to problems I've had with my GPU timing test program, timer2 appears to be unreliable(clocks are skipped?) when target mode is enabled and the full
33MHz clock is used(rather than 33MHz / 8). TODO: Investigate further and confirm(or not).
*/
/*
FIXME: Clock appropriately(and update events) when using SetRegister() via the debugger.
*/
namespace MDFN_IEN_PSX
{
extern PS_GPU *GPU;
struct Timer
{
uint32 Mode;
int32 Counter; // Only 16-bit, but 32-bit here for detecting counting past target.
int32 Target;
int32 Div8Counter;
bool IRQDone;
int32 DoZeCounting;
};
static bool vblank;
static bool hretrace;
static Timer Timers[3];
static pscpu_timestamp_t lastts;
static int32 CalcNextEvent(int32 next_event)
{
for(int i = 0; i < 3; i++)
{
int32 target;
int32 count_delta;
if((i == 0 || i == 1) && (Timers[i].Mode & 0x100)) // If clocked by GPU, abort for this timer(will result in poor granularity for pixel-clock-derived timer IRQs, but whatever).
continue;
if(!(Timers[i].Mode & 0x10)) // If IRQ is disabled, abort for this timer.
continue;
if((Timers[i].Mode & 0x8) && (Timers[i].Counter == 0) && (Timers[i].Target == 0) && !Timers[i].IRQDone)
{
next_event = 1;
continue;
}
target = ((Timers[i].Mode & 0x8) && (Timers[i].Counter < Timers[i].Target)) ? Timers[i].Target : 0x10000;
count_delta = target - Timers[i].Counter;
if(count_delta <= 0)
{
fprintf(stderr, "timer %d count_delta <= 0!!! %d %d\n", i, target, Timers[i].Counter);
continue;
}
{
int32 tmp_clocks;
if(Timers[i].DoZeCounting <= 0)
continue;
if((i == 0x2) && (Timers[i].Mode & 0x1))
continue;
if((i == 0x2) && (Timers[i].Mode & 0x200))
{
assert(Timers[i].Div8Counter >= 0 && Timers[i].Div8Counter < 8);
tmp_clocks = ((count_delta - 1) * 8) + (8 - Timers[i].Div8Counter);
}
else
tmp_clocks = count_delta;
assert(tmp_clocks > 0);
if(next_event > tmp_clocks)
next_event = tmp_clocks;
}
}
return(next_event);
}
static void ClockTimer(int i, uint32 clocks)
{
int32 before = Timers[i].Counter;
int32 target = 0x10000;
bool zero_tm = false;
if(Timers[i].DoZeCounting <= 0)
clocks = 0;
if(i == 0x2)
{
uint32 d8_clocks;
Timers[i].Div8Counter += clocks;
d8_clocks = Timers[i].Div8Counter >> 3;
Timers[i].Div8Counter -= d8_clocks << 3;
if(Timers[i].Mode & 0x200) // Divide by 8, at least for timer 0x2
clocks = d8_clocks;
if(Timers[i].Mode & 1)
clocks = 0;
}
if(Timers[i].Mode & 0x008)
target = Timers[i].Target;
if(target == 0 && Timers[i].Counter == 0)
zero_tm = true;
else
Timers[i].Counter += clocks;
if(clocks && (Timers[i].Mode & 0x40))
Timers[i].IRQDone = false;
if((before < target && Timers[i].Counter >= target) || zero_tm || Timers[i].Counter > 0xFFFF)
{
#if 1
if(Timers[i].Mode & 0x10)
{
if((Timers[i].Counter - target) > 3)
printf("Timer %d IRQ trigger error: %d\n", i, Timers[i].Counter - target);
}
#endif
Timers[i].Mode |= 0x0800;
if(Timers[i].Counter > 0xFFFF)
{
Timers[i].Counter -= 0x10000;
if(target == 0x10000)
Timers[i].Mode |= 0x1000;
if(!target)
Timers[i].Counter = 0;
}
if(target)
Timers[i].Counter -= (Timers[i].Counter / target) * target;
if((Timers[i].Mode & 0x10) && !Timers[i].IRQDone)
{
Timers[i].IRQDone = true;
IRQ_Assert(IRQ_TIMER_0 + i, true);
IRQ_Assert(IRQ_TIMER_0 + i, false);
}
if(Timers[i].Counter && (Timers[i].Mode & 0x40))
Timers[i].IRQDone = false;
}
}
void TIMER_SetVBlank(bool status)
{
switch(Timers[1].Mode & 0x7)
{
case 0x1:
Timers[1].DoZeCounting = !status;
break;
case 0x3:
if(vblank && !status)
Timers[1].Counter = 0;
break;
case 0x5:
Timers[1].DoZeCounting = status;
if(vblank && !status)
Timers[1].Counter = 0;
break;
case 0x7:
if(Timers[1].DoZeCounting == -1)
{
if(!vblank && status)
Timers[1].DoZeCounting = 0;
}
else if(Timers[1].DoZeCounting == 0)
{
if(vblank && !status)
Timers[1].DoZeCounting = 1;
}
break;
}
vblank = status;
}
void TIMER_SetHRetrace(bool status)
{
if(hretrace && !status)
{
if((Timers[0].Mode & 0x7) == 0x3)
Timers[0].Counter = 0;
}
hretrace = status;
}
void TIMER_AddDotClocks(uint32 count)
{
if(Timers[0].Mode & 0x100)
ClockTimer(0, count);
}
void TIMER_ClockHRetrace(void)
{
if(Timers[1].Mode & 0x100)
ClockTimer(1, 1);
}
pscpu_timestamp_t TIMER_Update(const pscpu_timestamp_t timestamp)
{
int32 cpu_clocks = timestamp - lastts;
for(int i = 0; i < 3; i++)
{
uint32 timer_clocks = cpu_clocks;
if(Timers[i].Mode & 0x100)
continue;
ClockTimer(i, timer_clocks);
}
lastts = timestamp;
return(timestamp + CalcNextEvent(1024));
}
static void CalcCountingStart(unsigned which)
{
Timers[which].DoZeCounting = true;
switch(which)
{
case 1:
switch(Timers[which].Mode & 0x07)
{
case 0x1:
Timers[which].DoZeCounting = !vblank;
break;
case 0x5:
Timers[which].DoZeCounting = vblank;
break;
case 0x7:
Timers[which].DoZeCounting = -1;
break;
}
break;
}
}
void TIMER_Write(const pscpu_timestamp_t timestamp, uint32 A, uint16 V)
{
TIMER_Update(timestamp);
int which = (A >> 4) & 0x3;
assert(!(A & 3));
PSX_DBGINFO("[TIMER] Write: %08x %04x\n", A, V);
if(which >= 3)
return;
// TODO: See if the "Timers[which].Counter" part of the IRQ if() statements below is what a real PSX does.
switch(A & 0xC)
{
case 0x0: Timers[which].IRQDone = false;
#if 1
if(Timers[which].Counter && (V & 0xFFFF) == 0)
{
Timers[which].Mode |= 0x0800;
if((Timers[which].Mode & 0x10) && !Timers[which].IRQDone)
{
Timers[which].IRQDone = true;
IRQ_Assert(IRQ_TIMER_0 + which, true);
IRQ_Assert(IRQ_TIMER_0 + which, false);
}
}
#endif
Timers[which].Counter = V & 0xFFFF;
break;
case 0x4: Timers[which].Mode = (V & 0x3FF) | (Timers[which].Mode & 0x1C00);
Timers[which].IRQDone = false;
#if 1
if(Timers[which].Counter)
{
Timers[which].Mode |= 0x0800;
if((Timers[which].Mode & 0x10) && !Timers[which].IRQDone)
{
Timers[which].IRQDone = true;
IRQ_Assert(IRQ_TIMER_0 + which, true);
IRQ_Assert(IRQ_TIMER_0 + which, false);
}
}
Timers[which].Counter = 0;
#endif
CalcCountingStart(which); // Call after setting .Mode
break;
case 0x8: Timers[which].Target = V & 0xFFFF;
break;
default: assert(0);
}
// TIMER_Update(timestamp);
PSX_SetEventNT(PSX_EVENT_TIMER, timestamp + CalcNextEvent(1024));
}
uint16 TIMER_Read(const pscpu_timestamp_t timestamp, uint32 A)
{
uint16 ret = 0;
int which = (A >> 4) & 0x3;
assert(!(A & 3));
if(which >= 3)
assert(0);
TIMER_Update(timestamp);
switch(A & 0xC)
{
case 0x0: ret = Timers[which].Counter;
break;
case 0x4: ret = Timers[which].Mode;
Timers[which].Mode &= ~0x1800;
break;
case 0x8: ret = Timers[which].Target;
break;
default: assert(0);
}
return(ret);
}
void TIMER_ResetTS(void)
{
lastts = 0;
}
void TIMER_Power(void)
{
lastts = 0;
hretrace = false;
vblank = false;
memset(Timers, 0, sizeof(Timers));
}
int TIMER_StateAction(StateMem *sm, int load, int data_only)
{
SFORMAT StateRegs[] =
{
#define SFTIMER(n) SFVARN(Timers[n].Mode, #n "Mode"), \
SFVARN(Timers[n].Counter, #n "Counter"), \
SFVARN(Timers[n].Target, #n "Target"), \
SFVARN(Timers[n].Div8Counter, #n "Div8Counter"), \
SFVARN(Timers[n].IRQDone, #n "IRQDone")
SFTIMER(0),
SFTIMER(1),
SFTIMER(2),
#undef SFTIMER
SFVAR(lastts),
SFEND
};
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "TIMER");
if(load)
{
}
return(ret);
}
uint32 TIMER_GetRegister(unsigned int which, char *special, const uint32 special_len)
{
int tw = (which >> 4) & 0x3;
uint32 ret = 0;
switch(which & 0xF)
{
case TIMER_GSREG_COUNTER0:
ret = Timers[tw].Counter;
break;
case TIMER_GSREG_MODE0:
ret = Timers[tw].Mode;
break;
case TIMER_GSREG_TARGET0:
ret = Timers[tw].Target;
break;
}
return(ret);
}
void TIMER_SetRegister(unsigned int which, uint32 value)
{
int tw = (which >> 4) & 0x3;
switch(which & 0xF)
{
case TIMER_GSREG_COUNTER0:
Timers[tw].Counter = value & 0xFFFF;
break;
case TIMER_GSREG_MODE0:
Timers[tw].Mode = value & 0xFFFF;
break;
case TIMER_GSREG_TARGET0:
Timers[tw].Target = value & 0xFFFF;
break;
}
}
}

42
mednafen/psx-0925/timer.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef __MDFN_PSX_TIMER_H
#define __MDFN_PSX_TIMER_H
namespace MDFN_IEN_PSX
{
enum
{
TIMER_GSREG_COUNTER0 = 0x00,
TIMER_GSREG_MODE0,
TIMER_GSREG_TARGET0,
TIMER_GSREG_COUNTER1 = 0x10,
TIMER_GSREG_MODE1,
TIMER_GSREG_TARGET1,
TIMER_GSREG_COUNTER2 = 0x20,
TIMER_GSREG_MODE2,
TIMER_GSREG_TARGET2,
};
uint32 TIMER_GetRegister(unsigned int which, char *special, const uint32 special_len);
void TIMER_SetRegister(unsigned int which, uint32 value);
void TIMER_Write(const pscpu_timestamp_t timestamp, uint32 A, uint16 V);
uint16 TIMER_Read(const pscpu_timestamp_t timestamp, uint32 A);
void TIMER_AddDotClocks(uint32 count);
void TIMER_ClockHRetrace(void);
void TIMER_SetHRetrace(bool status);
void TIMER_SetVBlank(bool status);
pscpu_timestamp_t TIMER_Update(const pscpu_timestamp_t);
void TIMER_ResetTS(void);
void TIMER_Power(void);
int TIMER_StateAction(StateMem *sm, int load, int data_only);
}
#endif

View File

@ -5,22 +5,17 @@ Battle Arena Toshinden, Final Fantasy 7 have some kind of GPU timing issues.
Zero Divide runs too fast(related to CPU emulation speed?).
Chrono Cross has several-second freezes during some large special attack/magic sequences.
-----------------------------------------------------------------------------------------------
Tiny Toon Adventures - Plucky's Big Adventure is failing and BREAK'ing for some reason, maybe memcard related.
Shadow Master has broken startup images.
Shadow Master might have broken startup images.
Crusaders of Might and Magic - The CD-XA buffering increase for ToD II is apparently exacerbating the early voice cutoff problem in this game.
Crash Team Racing - Noticed a game lockup once in the arcade mode stage select screen, having trouble reproducing it.
Misadventures of Trone Bonne - Voice problems, lockup, possibly due to excessively long seek delays?
Dance Dance Revolution - The music is...totally wonky.
Medal of Honor - Sound issues.
Fuuraiki - Hangs at black screen when trying to start a new game.
-----------------------------------------------------------------------------------------------
Test time delta between GPU LL DMA end and GPU non-busy status for various primitive types in sequence on a PS1.

View File

@ -554,8 +554,8 @@ void PS_CDC::XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab)
uint8 ibuffer[28];
int16 obuffer[2 + 28];
//if(param != param_copy)
// printf("%d %02x %02x\n", unit, param, param_copy);
if(param != param_copy)
printf("%d %02x %02x\n", unit, param, param_copy);
for(unsigned i = 0; i < 28; i++)
{
@ -775,8 +775,8 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
{
if(XA_Test(buf))
{
//if(AudioBuffer_ReadPos & 0xFFF)
//printf("readpos=%04x(rabl=%04x) writepos=%04x\n", AudioBuffer_ReadPos, AudioBuffer[AudioBuffer_ReadPos >> 12].Size, AudioBuffer_WritePos);
if(AudioBuffer_ReadPos & 0xFFF)
printf("readpos=%04x(rabl=%04x) writepos=%04x\n", AudioBuffer_ReadPos, AudioBuffer[AudioBuffer_ReadPos >> 12].Size, AudioBuffer_WritePos);
//if(AudioBuffer_UsedCount == 0)
// AudioBuffer_InPrebuffer = true;
@ -986,7 +986,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
const CDC_CTEntry *command = &Commands[PendingCommand];
//PSX_WARNING("[CDC] Command: %s --- %d", command->name, Results.CanRead());
#if 0
#if 1
printf("[CDC] Command: %s --- ", command->name);
for(unsigned int i = 0; i < ArgsIn; i++)
printf(" 0x%02x", ArgsBuf[i]);
@ -1327,7 +1327,7 @@ int32 PS_CDC::CalcSeekTime(int32 initial, int32 target, bool motor_on, bool paus
}
}
//printf("%d\n", ret);
printf("%d\n", ret);
return(ret);
}

View File

@ -54,7 +54,7 @@ void PS_CPU::SetFastMap(void *region_mem, uint32 region_address, uint32 region_s
// FAST_MAP_SHIFT
// FAST_MAP_PSIZE
for(uint64 A = region_address; A < region_address + region_size; A += FAST_MAP_PSIZE)
for(uint64 A = region_address; A < (uint64)region_address + region_size; A += FAST_MAP_PSIZE)
{
FastMap[A >> FAST_MAP_SHIFT] = ((uint8 *)region_mem - region_address);
}

View File

@ -546,10 +546,15 @@ static RegType Regs_SPU_Voices[] =
VOICE_HELPER(2),
VOICE_HELPER(3),
#else
VOICE_HELPER(20),
VOICE_HELPER(21),
VOICE_HELPER(9),
VOICE_HELPER(12),
VOICE_HELPER(17),
VOICE_HELPER(22),
VOICE_HELPER(23),
//VOICE_HELPER(20),
//VOICE_HELPER(21),
//VOICE_HELPER(22),
//VOICE_HELPER(23),
#endif
{ 0, "", "", 0 },
};

View File

@ -28,24 +28,24 @@ struct OpEntry
const char *format;
};
#define MASK_OP (0x3F << 26)
#define MASK_FUNC (0x3F)
#define MASK_RS (0x1F << 21)
#define MASK_RT (0x1F << 16)
#define MASK_RD (0x1F << 11)
#define MASK_SA (0x1F << 6)
#define MASK_OP (0x3FU << 26)
#define MASK_FUNC (0x3FU)
#define MASK_RS (0x1FU << 21)
#define MASK_RT (0x1FU << 16)
#define MASK_RD (0x1FU << 11)
#define MASK_SA (0x1FU << 6)
#define MK_OP(mnemonic, format, op, func, extra_mask) { MASK_OP | (op ? 0 : MASK_FUNC) | extra_mask, (op << 26) | func, mnemonic, format }
#define MK_OP(mnemonic, format, op, func, extra_mask) { MASK_OP | (op ? 0 : MASK_FUNC) | extra_mask, ((unsigned)op << 26) | func, mnemonic, format }
#define MK_OP_REGIMM(mnemonic, regop) { MASK_OP | MASK_RT, (0x01 << 26) | (regop << 16), mnemonic, "s, p" }
#define MK_OP_REGIMM(mnemonic, regop) { MASK_OP | MASK_RT, (0x01U << 26) | (regop << 16), mnemonic, "s, p" }
#define MK_COPZ(z) { MASK_OP | (0x1 << 25), (0x1 << 25) | ((0x10 | z) << 26), "cop" #z, "F" }
#define MK_COP0_FUNC(mnemonic, func) { MASK_OP | (0x1 << 25) | MASK_FUNC, (0x10 << 26) | (0x1 << 25) | func, mnemonic, "" }
#define MK_COPZ(z) { MASK_OP | (0x1U << 25), (0x1U << 25) | ((0x10U | z) << 26), "cop" #z, "F" }
#define MK_COP0_FUNC(mnemonic, func) { MASK_OP | (0x1U << 25) | MASK_FUNC, (0x10U << 26) | (0x1U << 25) | func, mnemonic, "" }
#define MK_COPZ_XFER(z, mnemonic, format, xf) { MASK_OP | (0x1F << 21), ((0x10 | z) << 26) | (xf << 21), mnemonic, format }
#define MK_COPZ_XFER(z, mnemonic, format, xf) { MASK_OP | (0x1FU << 21), ((0x10U | z) << 26) | (xf << 21), mnemonic, format }
#define MK_GTE(mnemonic, format, func) { MASK_OP | (0x1 << 25) | MASK_FUNC, (0x1 << 25) | (0x12 << 26) | func, mnemonic, format }
#define MK_GTE(mnemonic, format, func) { MASK_OP | (0x1U << 25) | MASK_FUNC, (0x1U << 25) | (0x12U << 26) | func, mnemonic, format }
static OpEntry ops[] =
{

View File

@ -434,6 +434,7 @@ void DMA_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)
{
int ch = (A & 0x7F) >> 4;
//if(ch == 2 || ch == 7)
//PSX_WARNING("[DMA] Write: %08x %08x, DMAIntStatus=%08x", A, V, DMAIntStatus);
// FIXME if we ever have "accurate" bus emulation
@ -548,11 +549,6 @@ uint32 DMA_Read(const pscpu_timestamp_t timestamp, uint32 A)
{
int ch = (A & 0x7F) >> 4;
uint32 ret = 0;
//assert(!(A & 3));
//if(ch == 2)
// printf("DMA Read: %08x --- %d\n", A, GPU->GetScanlineNum());
if(ch == 7)
{

View File

@ -674,7 +674,7 @@ void FrontIO::SetInput(unsigned int port, const char *type, void *ptr)
if(port < 2)
irq10_pulse_ts[port] = PSX_EVENT_MAXTS;
if(!strcmp(type, "gamepad"))
if(!strcmp(type, "gamepad") || !strcmp(type, "dancepad"))
Devices[port] = Device_Gamepad_Create();
else if(!strcmp(type, "dualanalog"))
Devices[port] = Device_DualAnalog_Create(false);
@ -882,6 +882,15 @@ static InputDeviceInfoStruct InputDeviceInfoPSXPort[] =
Device_Justifier_IDII,
},
{
"dancepad",
"Dance Pad",
"Dingo Dingo Rodeo!",
NULL,
sizeof(Device_Dancepad_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_Dancepad_IDII,
},
};
static const InputPortInfoStruct PortInfo[] =

View File

@ -787,6 +787,8 @@ INLINE void PS_GPU::WriteCB(uint32 InData)
void PS_GPU::Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)
{
V <<= (A & 3) * 8;
if(A & 4) // GP1 ("Control")
{
uint32 command = V >> 24;
@ -965,7 +967,7 @@ uint32 PS_GPU::Read(const pscpu_timestamp_t timestamp, uint32 A)
//PSX_WARNING("[GPU READ WHEN (DMACONTROL&2)] 0x%08x - ret=0x%08x, scanline=%d", A, ret, scanline);
}
return(ret);
return(ret >> ((A & 3) * 8));
}
INLINE void PS_GPU::ReorderRGB_Var(uint32 out_Rshift, uint32 out_Gshift, uint32 out_Bshift, bool bpp24, const uint16 *src, uint32 *dest, const int32 dx_start, const int32 dx_end, int32 fb_x)
@ -1155,11 +1157,7 @@ pscpu_timestamp_t PS_GPU::Update(const pscpu_timestamp_t sys_timestamp)
}
char buffer[256];
trio_snprintf(buffer, sizeof(buffer), _("VIDEO STANDARD MISMATCH"));
#ifndef __LIBRETRO__
DrawTextTrans(surface->pixels + ((DisplayRect->h / 2) - (13 / 2)) * surface->pitch32, surface->pitch32 << 2, DisplayRect->w, (UTF8*)buffer,
surface->MakeColor(0x00, 0xFF, 0x00), true, MDFN_FONT_6x13_12x13);
#endif
/* trio_snprintf(buffer, sizeof(buffer), _("VIDEO STANDARD MISMATCH")); */
}
else
{

View File

@ -211,6 +211,28 @@ InputDeviceInputInfoStruct Device_Gamepad_IDII[16] =
{ "square", "□ (left)", 8, IDIT_BUTTON_CAN_RAPID, NULL },
};
InputDeviceInputInfoStruct Device_Dancepad_IDII[16] =
{
{ "select", "SELECT", 0, IDIT_BUTTON, NULL },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ "start", "START", 1, IDIT_BUTTON, NULL },
{ "up", "UP ↑", 3, IDIT_BUTTON, NULL },
{ "right", "RIGHT →", 6, IDIT_BUTTON, NULL },
{ "down", "DOWN ↓", 8, IDIT_BUTTON, NULL },
{ "left", "LEFT ←", 5, IDIT_BUTTON, NULL },
{ NULL, "empty", 0, IDIT_BUTTON, NULL },
{ NULL, "empty", 0, IDIT_BUTTON, NULL },
{ NULL, "empty", 0, IDIT_BUTTON, NULL },
{ NULL, "empty", 0, IDIT_BUTTON, NULL },
{ "triangle", "△ (lower left)", 7, IDIT_BUTTON, NULL },
{ "circle", "○ (upper right)", 4, IDIT_BUTTON, NULL },
{ "cross", "x (upper left)", 2, IDIT_BUTTON, NULL },
{ "square", "□ (lower right)", 9, IDIT_BUTTON, NULL },
};
}

View File

@ -6,6 +6,7 @@ namespace MDFN_IEN_PSX
InputDevice *Device_Gamepad_Create(void);
extern InputDeviceInputInfoStruct Device_Gamepad_IDII[16];
extern InputDeviceInputInfoStruct Device_Dancepad_IDII[16];
}
#endif

View File

@ -15,10 +15,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __LIBRETRO__
#define HAVE_PSF 1
#endif
#include "psx.h"
#include "mdec.h"
#include "frontio.h"
@ -26,13 +22,7 @@
#include "sio.h"
#include "cdc.h"
#include "spu.h"
#include "../mednafen-endian.h"
#include "../mempatcher.h"
#ifdef HAVE_PSF
#include "../PSFLoader.h"
#include "../player.h"
#endif
#include "../cputest/cputest.h"
extern MDFNGI EmulatedPSX;
@ -40,20 +30,6 @@ extern MDFNGI EmulatedPSX;
namespace MDFN_IEN_PSX
{
#ifdef HAVE_PSF
class PSF1Loader : public PSFLoader
{
public:
PSF1Loader(MDFNFILE *fp);
virtual ~PSF1Loader();
virtual void HandleEXE(const uint8 *data, uint32 len, bool ignore_pcsp = false);
PSFTags tags;
};
#endif
enum
{
REGION_JP = 0,
@ -67,10 +43,6 @@ static uint32 ReadCounter = 0;
static uint32 WriteCounter = 0;
#endif
#ifdef HAVE_PSF
static PSF1Loader *psf_loader = NULL;
#endif
static std::vector<CDIF*> *cdifs = NULL;
static std::vector<const char *> cdifs_scex_ids;
static bool CD_TrayOpen;
@ -587,7 +559,7 @@ template<typename T, bool IsWrite, bool Access24, bool Peek> static INLINE void
return;
}
if(A >= 0x1F801100 && A <= 0x1F80112F) // Root counters
if(A >= 0x1F801100 && A <= 0x1F80113F) // Root counters
{
if(IsWrite)
TIMER_Write(timestamp, A, V);
@ -777,15 +749,11 @@ static void Emulate(EmulateSpecStruct *espec)
{
pscpu_timestamp_t timestamp = 0;
#ifdef __LIBRETRO__
espec->skip = false;
#else
if(FIO->RequireNoFrameskip())
{
//puts("MEOW");
espec->skip = false; //TODO: Save here, and restore at end of Emulate() ?
}
#endif
MDFNGameInfo->mouse_sensitivity = MDFN_GetSettingF("psx.input.mouse_sensitivity");
@ -796,19 +764,11 @@ static void Emulate(EmulateSpecStruct *espec)
espec->SoundBufSize = 0;
FIO->UpdateInput();
#ifdef HAVE_PSF
GPU->StartFrame(psf_loader ? NULL : espec);
#else
GPU->StartFrame(espec);
#endif
SPU->StartFrame(espec->SoundRate, MDFN_GetSettingUI("psx.spu.resamp_quality"));
Running = -1;
#ifdef HAVE_PSF
timestamp = CPU->Run(timestamp, psf_loader != NULL);
#else
timestamp = CPU->Run(timestamp, false);
#endif
assert(timestamp);
@ -830,17 +790,6 @@ static void Emulate(EmulateSpecStruct *espec)
espec->MasterCycles = timestamp;
#ifdef HAVE_PSF
if(psf_loader)
{
if(!espec->skip)
{
espec->LineWidths[0].w = ~0;
Player_Draw(espec->surface, &espec->DisplayRect, 0, espec->SoundBuf, espec->SoundBufSize);
}
}
#endif
// Save memcards if dirty.
for(int i = 0; i < 8; i++)
{
@ -857,7 +806,7 @@ static void Emulate(EmulateSpecStruct *espec)
Memcard_SaveDelay[i] += timestamp;
if(Memcard_SaveDelay[i] >= (33868800 * 2)) // Wait until about 2 seconds of no new writes.
{
//fprintf(stderr, "Saving memcard %d...\n", i);
fprintf(stderr, "Saving memcard %d...\n", i);
try
{
char ext[64];
@ -893,11 +842,6 @@ static void Emulate(EmulateSpecStruct *espec)
static bool TestMagic(const char *name, MDFNFILE *fp)
{
#ifdef HAVE_PSF
if(PSFLoader::TestMagic(0x01, fp))
return(true);
#endif
if(fp->size < 0x800)
return(false);
@ -1461,31 +1405,10 @@ static void LoadEXE(const uint8 *data, const uint32 size, bool ignore_pcsp = fal
}
#ifdef HAVE_PSF
PSF1Loader::PSF1Loader(MDFNFILE *fp)
{
tags = Load(0x01, 2033664, fp);
}
PSF1Loader::~PSF1Loader()
{
}
void PSF1Loader::HandleEXE(const uint8 *data, uint32 size, bool ignore_pcsp)
{
LoadEXE(data, size, ignore_pcsp);
}
#endif
static void Cleanup(void);
static int Load(const char *name, MDFNFILE *fp)
{
#ifdef HAVE_PSF
const bool IsPSF = PSFLoader::TestMagic(0x01, fp);
#else
const bool IsPSF = false;
#endif
const bool IsPSF = false;
if(!TestMagic(name, fp))
{
@ -1514,19 +1437,6 @@ static int Load(const char *name, MDFNFILE *fp)
try
{
#ifdef HAVE_PSF
if(IsPSF)
{
psf_loader = new PSF1Loader(fp);
std::vector<std::string> SongNames;
SongNames.push_back(psf_loader->tags.GetTag("title"));
Player_Init(1, psf_loader->tags.GetTag("game"), psf_loader->tags.GetTag("artist"), psf_loader->tags.GetTag("copyright"), SongNames);
}
else
#endif
LoadEXE(fp->data, fp->size);
}
catch(std::exception &e)
@ -1544,8 +1454,8 @@ static int LoadCD(std::vector<CDIF *> *CDInterfaces)
int ret = InitCommon(CDInterfaces);
// TODO: fastboot setting
if(MDFN_GetSettingB("psx.fastboot"))
BIOSROM->WriteU32(0x6990, 0);
//if(MDFN_GetSettingB("psx.fastboot"))
// BIOSROM->WriteU32(0x6990, 0);
MDFNGameInfo->GameType = GMT_CDROM;
@ -1556,14 +1466,6 @@ static void Cleanup(void)
{
TextMem.resize(0);
#ifdef HAVE_PSF
if(psf_loader)
{
delete psf_loader;
psf_loader = NULL;
}
#endif
if(CDC)
{
delete CDC;
@ -1613,9 +1515,6 @@ static void Cleanup(void)
static void CloseGame(void)
{
#ifdef HAVE_PSF
if(!psf_loader)
#endif
{
for(int i = 0; i < 8; i++)
{
@ -1641,11 +1540,6 @@ static void CloseGame(void)
static void SetInput(int port, const char *type, void *ptr)
{
#ifdef HAVE_PSF
if(psf_loader)
FIO->SetInput(port, "none", NULL);
else
#endif
FIO->SetInput(port, type, ptr);
}
@ -1761,10 +1655,8 @@ static void DoSimpleCommand(int cmd)
static const FileExtensionSpecStruct KnownExtensions[] =
{
#ifdef HAVE_PSF
{ ".psf", gettext_noop("PSF1 Rip") },
{ ".minipsf", gettext_noop("MiniPSF1 Rip") },
#endif
{ ".psx", gettext_noop("PS-X Executable") },
{ ".exe", gettext_noop("PS-X Executable") },
{ NULL, NULL }
@ -1806,7 +1698,7 @@ static MDFNSetting PSXSettings[] =
{ "psx.input.port7.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on port 2C."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x0080FF", "0x000000", "0x1000000" },
{ "psx.input.port8.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on port 2D."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x8000FF", "0x000000", "0x1000000" },
{ "psx.fastboot", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Skip BIOS intro sequence."), gettext_noop("MAY BREAK GAMES."), MDFNST_BOOL, "0" },
//{ "psx.fastboot", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Skip BIOS intro sequence."), gettext_noop("MAY BREAK GAMES."), MDFNST_BOOL, "0" },
{ "psx.region_autodetect", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Attempt to auto-detect region of game."), NULL, MDFNST_BOOL, "1" },
{ "psx.region_default", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Default region to use."), gettext_noop("Used if region autodetection fails or is disabled."), MDFNST_ENUM, "jp", NULL, NULL, NULL, NULL, Region_List },

View File

@ -9,10 +9,8 @@
#include "../general.h"
#include "../FileWrapper.h"
//#define PSX_WARNING(format, ...) { printf(format "\n", ## __VA_ARGS__); }
//#define PSX_DBGINFO(format, ...) { /*printf(format "\n", ## __VA_ARGS__);*/ }
#define PSX_WARNING(format, ...)
#define PSX_DBGINFO(format, ...)
#define PSX_WARNING(format, ...) { printf(format "\n", ## __VA_ARGS__); }
#define PSX_DBGINFO(format, ...) { /*printf(format "\n", ## __VA_ARGS__);*/ }
namespace MDFN_IEN_PSX
{

View File

@ -770,7 +770,7 @@ int32 PS_SPU::UpdateFromCDC(int32 clocks)
voice->CurPhase_SD += phase_inc;
}
if(!(SPUControl & 0x8000) || (VoiceOff & (1 << voice_num)))
if(VoiceOff & (1 << voice_num))
{
if(voice->ADSR.Phase != ADSR_RELEASE)
{
@ -778,7 +778,7 @@ int32 PS_SPU::UpdateFromCDC(int32 clocks)
}
}
if((SPUControl & 0x8000) && (VoiceOn & (1 << voice_num)))
if(VoiceOn & (1 << voice_num))
{
ResetEnvelope(voice);
@ -796,6 +796,12 @@ int32 PS_SPU::UpdateFromCDC(int32 clocks)
voice->CurAddr = voice->StartAddr & ~0x7;
}
if(!(SPUControl & 0x8000))
{
voice->ADSR.Phase = ADSR_RELEASE;
voice->ADSR.EnvLevel = 0;
}
}
VoiceOff = 0;
@ -1173,6 +1179,7 @@ void PS_SPU::StartFrame(double rate, uint32 quality)
{
if((int)rate != last_rate || quality != last_quality)
{
//double ratio = (double)44100 / (rate ? rate : 44100);
int err = 0;
last_rate = (int)rate;

View File

@ -71,13 +71,13 @@
/*
FIXME: Clock appropriately(and update events) when using SetRegister() via the debugger.
TODO: If we ever return randomish values to "simulate" open bus, remember to change the return type and such of the TIMER_Read() function to full 32-bit too.
*/
namespace MDFN_IEN_PSX
{
extern PS_GPU *GPU;
struct Timer
{
uint32 Mode;
@ -337,7 +337,7 @@ void TIMER_Write(const pscpu_timestamp_t timestamp, uint32 A, uint16 V)
int which = (A >> 4) & 0x3;
assert(!(A & 3));
V <<= (A & 3) * 8;
PSX_DBGINFO("[TIMER] Write: %08x %04x\n", A, V);
@ -384,7 +384,8 @@ void TIMER_Write(const pscpu_timestamp_t timestamp, uint32 A, uint16 V)
case 0x8: Timers[which].Target = V & 0xFFFF;
break;
default: assert(0);
case 0xC: // Open bus
break;
}
// TIMER_Update(timestamp);
@ -397,10 +398,12 @@ uint16 TIMER_Read(const pscpu_timestamp_t timestamp, uint32 A)
uint16 ret = 0;
int which = (A >> 4) & 0x3;
assert(!(A & 3));
if(which >= 3)
assert(0);
{
PSX_WARNING("[TIMER] Open Bus Read: 0x%08x", A);
return(ret >> ((A & 3) * 8));
}
TIMER_Update(timestamp);
@ -416,10 +419,11 @@ uint16 TIMER_Read(const pscpu_timestamp_t timestamp, uint32 A)
case 0x8: ret = Timers[which].Target;
break;
default: assert(0);
case 0xC: PSX_WARNING("[TIMER] Open Bus Read: 0x%08x", A);
break;
}
return(ret);
return(ret >> ((A & 3) * 8));
}

View File

@ -1,15 +0,0 @@
DEFS = @DEFS@ @CFLAG_VISIBILITY@
INCLUDES = -I./
noinst_LIBRARIES = libvorbisidec.a
libvorbisidec_a_SOURCES = mdct.c block.c window.c \
synthesis.c info.c \
floor1.c floor0.c vorbisfile.c \
res012.c mapping0.c registry.c codebook.c \
sharedbook.c framing.c bitwise.c \
codebook.h misc.h mdct_lookup.h\
os.h mdct.h block.h ivorbisfile.h lsp_lookup.h\
registry.h window.h window_lookup.h\
codec_internal.h backends.h ogg.h \
asm_arm.h ivorbiscodec.h

View File

@ -1,623 +0,0 @@
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@
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/tremor
DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
COPYING
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_$(V))
am__v_AR_ = $(am__v_AR_$(AM_DEFAULT_VERBOSITY))
am__v_AR_0 = @echo " AR " $@;
AM_V_at = $(am__v_at_$(V))
am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
am__v_at_0 = @
libvorbisidec_a_AR = $(AR) $(ARFLAGS)
libvorbisidec_a_LIBADD =
am_libvorbisidec_a_OBJECTS = mdct.$(OBJEXT) block.$(OBJEXT) \
window.$(OBJEXT) synthesis.$(OBJEXT) info.$(OBJEXT) \
floor1.$(OBJEXT) floor0.$(OBJEXT) vorbisfile.$(OBJEXT) \
res012.$(OBJEXT) mapping0.$(OBJEXT) registry.$(OBJEXT) \
codebook.$(OBJEXT) sharedbook.$(OBJEXT) framing.$(OBJEXT) \
bitwise.$(OBJEXT)
libvorbisidec_a_OBJECTS = $(am_libvorbisidec_a_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
AM_V_lt = $(am__v_lt_$(V))
am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
am__v_lt_0 = --silent
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_$(V))
am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
am__v_CC_0 = @echo " CC " $@;
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_$(V))
am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
am__v_CCLD_0 = @echo " CCLD " $@;
AM_V_GEN = $(am__v_GEN_$(V))
am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
am__v_GEN_0 = @echo " GEN " $@;
SOURCES = $(libvorbisidec_a_SOURCES)
DIST_SOURCES = $(libvorbisidec_a_SOURCES)
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 = @DEFS@ @CFLAG_VISIBILITY@
DEPDIR = @DEPDIR@
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@
MATH_OPTIMIZER_FLAGS = @MATH_OPTIMIZER_FLAGS@
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@
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@
XMKMF = @XMKMF@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
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@
lt_ECHO = @lt_ECHO@
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@
INCLUDES = -I./
noinst_LIBRARIES = libvorbisidec.a
libvorbisidec_a_SOURCES = mdct.c block.c window.c \
synthesis.c info.c \
floor1.c floor0.c vorbisfile.c \
res012.c mapping0.c registry.c codebook.c \
sharedbook.c framing.c bitwise.c \
codebook.h misc.h mdct_lookup.h\
os.h mdct.h block.h ivorbisfile.h lsp_lookup.h\
registry.h window.h window_lookup.h\
codec_internal.h backends.h ogg.h \
asm_arm.h ivorbiscodec.h
all: all-am
.SUFFIXES:
.SUFFIXES: .c .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/tremor/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/tremor/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)
libvorbisidec.a: $(libvorbisidec_a_OBJECTS) $(libvorbisidec_a_DEPENDENCIES)
$(AM_V_at)-rm -f libvorbisidec.a
$(AM_V_AR)$(libvorbisidec_a_AR) libvorbisidec.a $(libvorbisidec_a_OBJECTS) $(libvorbisidec_a_LIBADD)
$(AM_V_at)$(RANLIB) libvorbisidec.a
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitwise.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/block.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/codebook.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/floor0.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/floor1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/framing.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mapping0.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mdct.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/registry.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/res012.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sharedbook.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/synthesis.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vorbisfile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/window.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LTCOMPILE) -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:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
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

@ -1,785 +0,0 @@
CHANGES -- trio
The changes listed without a name attributed to them were most likely done by
Bjorn Reese and/or Daniel Stenberg.
Version 1.14 - 2010/01/26
-------------------------
* David Byron
Added trio_xstring_append_max.
* Fixed compilation problem on Cygwin due to lack of long double math
(reported by Matthias Andree).
* David Boyce
Added #undef of standard stdio function names before assigning trio functions
to them.
* Matthias Andree
Upgraded configure.in to use new macros instead of obsoleted macros.
* Matthias Andree
Added VPATH to Makefile.in
* Tom Honermann
Fixed problem with subnormal numbers which caused an infinite loop outputting
leading spaces.
* Adam McLaurin
Improved parsing performance by avoiding memset() and memcpy() on character
arrays.
* Gideon Smeding
Fixed %u scanning of signed numbers.
* Gideon Smeding
Fixed group scanning for non-matching input.
* Fixed missing undo of look-ahead reading for scanf functions. This does only
work for the scanf* and fscanf* functions, not dscanf* and cscanf* functions
(reported by Gideon Smeding).
* If the format string is empty, scanf does not attempt to read any input.
* Ralf Junker
Fixed Borland compilation for user-defined specifiers.
Version 1.13 - 2008/11/09
-------------------------
* Ives Aerts
Added the $<format|skip> format for user-defined specifiers, which is
compatible with compiler warnings about mismatches between specifiers and
arguments.
* Added TRIO_DEPRECATED flag (reported by David Boyce)
* Fixed rounding adjustment for long double (reported as bug item #2136686).
* Added Makefile dependency for test target (reported as bug item #2136636).
* David Boyce
Fixed long long support for MSVC.
* Fixed potential problem with read after buffer end for non-zero terminated
strings (reported as bug item #1828465).
* Andreas Stricker
Added WinCE support.
* Fixed number of significant digits for %g.
Version 1.12 - 2006/10/22
-------------------------
* Fixed scanning of floats (reported by Bernd Ahlers).
* Fixed configure.in for GCC on Tru64 and MIPSpro on IRIX (reported by Andreas
Maus).
* Olli Savia
Added support for LynxOS.
Version 1.11 - 2006/04/08
-------------------------
* Mark Pickelmann
Fixed trio_unregister. If the first element was removed, the remaining
list would be removed as well.
* Fixed unintended formatting of %e that would result in non-zero numbers
starting with zero (reported by Mark Pickelmann and Gisli Ottarsson).
* Fixed compilation with Sun Workshop 6 (reported by Matthias Andree).
* Fixed accuracy for denormalized numbers (bug item #758327).
* Glen Davidson
Fixed scanning of floating-point numbers without a decimal-point (bug item
#1370427).
* David Byron
Fixed more compiler warnings.
* Fixed compilation of trio_to_long_double and TRIO_FEATURE_FLOAT (reported by
David Byron).
* Fixed precision of large floating-point numbers (bug item #1314524).
* Karl Bochert
Fixed trio_fpclassify_and_signbit to only restore the floating-point
precision.
* Fixed detection of need for ieee option on FreeBSD/Alpha.
* Added TRIO_SNPRINTF_ONLY compilation.
* Fixed trio_to_double by not using strtod() on Tru64/DECC because it does not
support hex-floats.
* Fixed crash on 64 bits machines related to a previous workaround in version
1.9 for uninitialized va_list (reported by Nicolai Tufar, suggestion by
Douglas Gwyn).
* Patrick Jessee
Fixed width calculation for %g.
* Added macros for internal features.
* Jon Foster
Added macros for conditional compilation of many features. Documented all
the features.
* Karl Bochert
Fixed problem with Borland C++, which changes the floating-point precision
for certain math functions (log10() and _fpclass()).
* Karl Bochert
Fixed compilation warnings on Borland C++.
* Removed any occurrence of #elif because Borland C++ reports wrong line
numbers when they are present (reported by Karl Bochert).
* David Byron
Added trio_asprintfv.
* Brian Chapman
Fixed Mac OS X compilation.
* David Byron
Fixed several compiler warnings.
* Fixed printing of out-of-range arguments for %hhd and %hd. These arguments
can be out of range because of default integer promotion.
* Bob Friesenhahn
Fixed installation of header files.
* Joe Orton
Added SHELL to Makefile.in to avoid problems with CShells.
* Shaun Tancheff
Fixed regresion tests for MSVC.
* Craig Berry
Fixed the VMS C99 workaround.
Version 1.10 - 2003/03/06
-------------------------
* Rearranged some include files to accommodate large file support (reported by
Albert Chin-A-Young).
* Added support for SunOS 4.1.x lack of strerror, tolower, and toupper
(reported by Peter McCluskey).
* Fixed pedantic compilation with TRIO_MINIMAL.
* Jose Kahan
Moved <limits.h> to avoid redefinition problems.
* Fixed hex-float exponents (reported by Matthias Clasen).
* Fixed handling of negative width and precision via paramters (reported by
Jacob Navia).
* Nigel Hall
Fixed TRIO_VA_START for VMS.
* Rune Enggaard Lausen
Fixed compilation for Borland C++ Builder.
* Fixed precision of hex-float numbers (reported by James Antill).
* Fixed plus sign only to be added for signed numbers.
* Fixed printing of integers with value and precision of zero (reported by
James Antill).
* Fixed %#.o to only print one zero if the value is zero (reported by James
Antill).
* Rewrote check for IEEE compilation option to remove dependency on additional
scripts.
* Mehdi Lavasani
Makefile install target fixed to work with older install programs.
* Collapsed the DECC, MSVC, HP-UX, and AIX code for trio_fpclassify_and_sign()
with further preprocessing.
Version 1.9 - 2002/10/13
------------------------
* Fixed trio_fpclassify_and_signbit on AIX 3.2
* Added configure check for -ieee/-mieee compilation option for Alpha machines.
* Craig Berry
Fixed compilation on VMS.
* Albert Chin-A-Young
Fixed incorrect conditional expression in trio_isinf.
* Fixed the warnings about uninitialized va_list in the printfv and scanfv
family without the use of compiler specific pragmas (suggested by Ian
Pilcher).
* Fixed space flag for floating-point numbers (reported by Ian Main).
Version 1.8 - 2002/07/10
------------------------
* Fixed infinite loop in multibyte handling (reported by Gisli Ottarsson).
* Added the customizable cprintf/cscanf family which enables to user to specify
input and output stream functions (suggested by Florian Schulze).
* Fixed trio_isinf by removing the HP-UX workaround, and instead making sure
that the C99 macro will adhere to the trio return values (reported by Luke
Dunstan).
* Alexander Lukyanov
Fixed boundary case for scanning and EOF.
* Jacob Navia
Enabled the L modifier for formatting.
* Added TRIO_MINIMAL to build trio without the string functions.
* Added the R modifier to print rounded floating-point numbers.
* Added trio_to_long_double and long double scanning (the L modifier).
* Added trio_locale_decimal_point, trio_locale_thousand_separator,
trio_locale_grouping to overwrite locale settings.
* Rewrote TrioWriteDouble to avoid temporary buffers and thus the danger of
buffer overflows (for instance %.5000f).
* Improved floating-point formatting accuracy.
* Fixed formatting of non-decimal exponents.
* Fixed thousand separator checking.
* Fixed %f scanning to get a float and %lf to get a double.
* Fixed WIN32 compilation (reported by Emmanuel Mogenet)
* Fixed regression test cases to exclude disabled features.
Version 1.7 - 2002/05/07
------------------------
* Fixed trio_to_double to handle hex-floats properly.
* Fixed printing of %a-format to be like %e, not like %g.
* Fixed floating-point printing of values beyond the machine accuracy.
* Fixed %f for printing with large precision.
* Fixed the usage of C99 nan(), which caused a crash on OSF/1 (reported by
Georg Bolz)
* Joe Orton
Fixed %p on 64-bit platforms.
* Made trio compile with K&R compilers.
* Emmanuel Mogenet
Fixed bug in trio_asprintf.
* Emmanuel Mogenet
Various WIN32 fixes.
* Joe Orton
Fixed trio_isinf() on HP-UX, and added test cases.
* Joe Orton
Fixed non-portable use of $^ in Makefile.
* Joe Orton
Added autoconf.
* Alexander Lukyanov
Fixed a number of bugs in the scanning of EOF and the count specifier.
* Richard Jinks
Added trio_nzero
* Fixed incorrect handling of return code from TrioReadChar (reported by
Henrik Löf)
* Fixed parsing of character class expressions.
* Fixed trio_to_double which did not work with long fractions.
* Fixed %f for printing of large numbers.
* Fixed %#s to handle whitespaces as non-printable characters.
* Added trio_isfinite, trio_signbit, and trio_fpclassify.
* Added new test cases.
Version 1.6 - 2002/01/13
------------------------
* Added dynamic string functions.
* Rewrote and extended documentation in JavaDoc (using Doxygen).
* Moved and renamed strio functions to triostr.
* Robert Collins
Added definition for Cygwin.
* Markus Henke
Added long double workaround for the HP C/iX compiler.
* Marc Verwerft
Improved error handling for dynamically allocated strings.
* John Fotheringham
Made trionan compile on OpenVMS.
* Added 'd' and 'D' as exponent letters when using TRIO_MICROSOFT.
* Fixed uninitial memory read for the parameter modifiers.
Version 1.5 - 2001/09/08
------------------------
* Merged with libxml changes.
* Moved NaN and Inf handling to separate file to enable reuse in other
projects.
* Igor Zlatkovic
Fixed TrioGenerateNan for MSVC.
* Fixed lots of preprocessor macros and internal data structure names.
Version 1.4 - 2001/06/03
------------------------
* Added hex-float (%a and %A) for scanning.
* Added wide character arguments (%ls, %ws, %S, %lc, %wc, and %C) for both
printf and scanf.
* Added mutex callbacks for user-specified specifiers to enable applications to
add thread-safety. These are registered with trio_register, where the
namespace is set to either ":enter" to lock a mutex, or ":leave" to unlock a
mutex.
* Added equivalence class expressions for scanning. For example, %[[=a=]] scans
for all letters in the same equivalence class as the letter 'a' as defined
by the locale.
* Changed character class expressions for scanning. The expressions must now
be embedded withing an extra set of brackets, e.g. %[[:alpha:]]. This was
done to adhere to the syntax of UNIX98 regular expressions.
* Added the possibility to specify standard support (TRIO_C99 etc.) as compiler
options.
* Fixed conversion of hex-float in StrToDouble.
* Fixed formatting of hex-float numbers.
* Stan Boehm
Fixed crash on QNX, which happend because some buffers on the stack were too
big.
* Fixed default precision for %f and %g (reported by Jose Ortiz)
* Howard Kapustein
Added the I8, I16, I32, and I64 modifiers.
* Jose Ortiz
Fixed rounding problem for %e.
* Jose Ortiz
Fixed various problems with the xlC and Sun C++ compilers.
Version 1.3 - 2001/05/16
------------------------
* trio's treatment of the field width when the %e code was used was not
correct (reported by Gisli Ottarsson). It turns out the fraction part should
be zero-padded by default and the exponent part should be zero-prefixed if
it is only one digit. At least that's how the GNU and Sun libc's work. The
trio floating point output looks identical to them now.
* Fixed group scanning with modifiers.
* Fixed compilation for 64-bit Digital Unix.
* Igor Zlatkovic
Fixed compilation of dprintf, which uses read/write, for MSVC.
* Fixed various compilation problems on Digital Unix (mainly associated with
va_list).
Version 1.2 - 2001/04/11
------------------------
* Added autoconf integration. If compiled with HAVE_CONFIG_H the following
happens. Firstly, <config.h> is included. Secondly, trio will only be
compiled if WITH_TRIO is defined herein. Thirdly, if TRIO_REPLACE_STDIO is
defined, only stdio functions that have not been detected by autoconf, i.e.
those not defined by HAVE_PRINTF or similar, will be replaced by trio
functions (suggested by Daniel Veillard).
* Fixed '%m.nf' output. Previously trio did not treat the width properly
in all cases (reported by Gisli Ottarsson).
* Added explicit promotion for the scanfv family.
* Fixed more C++ compilation warnings.
Version 1.1 - 2001/02/25
------------------------
* Added explicit promotion for the printfv familiy. A float must be specified
by %hf.
* Fixed positionals for printfv (reported by Gisli Ottarsson).
* Fixed an integer to pointer conversion problem on the SGI MIPS C compiler
(reported by Gisli Ottarsson).
* Fixed ANSI C++ warnings (type casting, and namespace is a reserved keyword).
* Added \n to all examples in the documentation to prevent confusion.
* Fixed StrSubstringMax
Version 1.0 - 2000/12/10
------------------------
* Bumped Version number.
Version 0.25 - 2000/12/09
-------------------------
* Wrote more documentation.
* Improved NaN support and added NaN to regression test.
* Fixed C99 support.
* Added missing getter/setter functions.
Version 0.24 - 2000/12/02
-------------------------
* Added callback functionality for the user-defined specifier (<>). All
the necessary functions are defined in triop.h header file. See the
documentation for trio_register for further detail.
* Wrote initial documentation on the callback functionality.
* Added the printfv and scanfv family of functions, which takes a pointer
array rather than variadic arguments. Each pointer in the array must point
to the associated data (requested by Bruce Korb).
* As indicated in version 0.21 the extension modifiers (<>) have now been
completely removed.
* Added skipping of thousand-separators in floating-point number scanning.
Version 0.23 - 2000/10/21
-------------------------
* Added width to scanning of floating-point numbers.
* Wrote more documentation on trio_printf.
* Fixed problem with trailing zeroes after decimal-point.
Version 0.22 - 2000/08/06
-------------------------
* Added LC_CTYPE locale dependent character class expressions to scan lists.
Included are [:alnum:], [:alpha:], [:cntrl:], [:digit:], [:graph:],
[:lower:], [:print:], [:punct:], [:space:], [:upper:], [:xdigit:]
* Added C escapes to alternative string formatting and scanning.
* Added StrSubstringMax.
* Wrote a little more documentation.
* Fixed scanf return values.
* Fixed a sign error for non-ascii characters.
Version 0.21 - 2000/07/19
-------------------------
* Converted the documentation to TeX. With latex2man the documentation can
automatically be converted into man pages.
* Added trio_scanf, trio_vscanf, trio_fscanf, and trio_vfscanf.
* Added trio_dprintf, trio_vdprintf, trio_dscanf, and trio_vdscanf. These
functions can be used to write and read directly to pipes and sockets (the
assume blocking sockets). Stdio buffering is surpassed, so the functions are
async-safe. However, reading from stdin (STDIN_FILENO) or writing to stdout
(STDOUT_FILENO) reintroduces the buffering.
* Paul Janzen
Added trio_asprintf and trio_vasprintf, which are compatible with the GNU
and BSD interfaces.
* Added scanlist ranges for group scanning (%[]).
* Added width for scanning (missing for floating-point numbers though).
* Added variable size modifier (&) to handle system defined types of unknown
size. This modifier makes certain assumptions about the integer sizes, which
may not be valid on any machine. Consequently, the modifier will remain
undocumented, as it may be removed later.
* Added \777 and \xFF to alternative string scanning (%#s)
* Added the TRIO_REPLACE_STDIO check in the header.
* Improved performance of the multibyte character parsing.
* Fixed positionals (%n$) which had stopped working.
* Fixed hh and ll modifiers to allow exactly two letters and no more.
* Fixed ANSI C++ warnings. Also fixed the compiler warning about casting
between integer and pointer (this has been annoying me for ages).
* Fixed snprintf and vsnprintf with zero buffer size.
* Fixed NAN problems (reported by Keith Briggs).
* Fixed parsing of multibyte characters. The format string was not correctly
advanced in case of a multibyte character.
* Renamed many of the internal functions to have more consistant names.
* Removed the <quote=c> and <fill=c> modifiers. They are not really worth
including. The other <> modifiers may disappear as well.
Version 0.20 - 2000/06/05
-------------------------
* Added intmax_t and ptrdiff_t support.
* Added support for LC_NUMERIC grouping.
* Added double-dot notation for the conversion base. The style is now
%width.precision.base, where any argument can be a number, an asterix
indicating a parameter, or be omitted entirely. For example, %*..2i is
to specify binary numbers without precision, and with width as a parameter
on the va_list.
* Added sticky modifier (!), which makes subsequent specifiers of the same
type reuse the current modifiers. Inspired by a suggestion from Gary Porter.
* Added group scanning (%[]). Scanlist ranges and multibyte sequences are not
supported yet.
* Added count scanning (%n).
* Changed the number scanning to accept thousand separators and any base.
* Fixed positional for parameters. It is possible to write something like
%3$*1$.*2$d (which happens to be the same as %*.*d).
* Fixed precision of integers.
* Fixed parameter flags. Before trio could only handle one parameter flag per
specifier, although two (three with double-dot base) were possible.
* Fixed isinf() for those platforms where it is unimplemented.
Version 0.18 - 2000/05/27
-------------------------
* Rewrote the entire floating-point formatting function (Danny Dulai had
reported several errors and even supplied some patches, which unfortunately
were lost due to the refactoring).
* Removed the use of strlen() in the declaration of a stack array. This
caused problems on some compilers (besides it isn't really ANSI C compliant
anyways). Using some arbitrarily chosen maximum value; should examine if
some standard defines an upper limit on the length of decimal-point and
thousands-separator (sizeof(wchar_t) perhaps?)
* Changed the parsing of the format string to be multibyte aware.
Version 0.17 - 2000/05/19
-------------------------
* Added INF, -INF, and NAN for floating-point numbers.
* Fixed %#.9g -- alternative with precision.
* Ken Gibson
Fixed printing of negative hex numbers
* Joerg (last name unknown)
Fixed convertion of non-ASCII characters
Version 0.16 - 1999/08/06
-------------------------
* Changed the constness of the second argument of StrFloat and StrDouble. The
lack of parameter overloading in C is the reason for the strange use of
constness in strtof and strtod.
* Cleaned up constness.
Version 0.15 - 1999/07/23
-------------------------
* Fixed the internal representation of numbers from signed to unsigned. Signed
numbers posed a problem for large unsigned numbers (reported by Tero)
* Fixed a tiny bug in trio_vsprintfcat
* Changed the meaning of the max argument of StrAppendMax to be consistant
with StrFormatAppendMax. Now it is the maximal size of the entire target
buffer, not just the appended size. This makes it easier to avoid buffer
overflows (requested by Tero)
Version 0.14 - 1999/05/16
-------------------------
* Added size_t support (just waiting for a C99 compliant compiler to add
ptrdiff_t and intmax_t)
* Rewrote TrioOutStreamDouble so it does not use the libc sprintf to emulate
floating-point anylonger.
* Fixed width, precision, and adjustment for numbers and doubles.
Version 0.13 - 1999/05/06
-------------------------
* Fixed zero padding for %d. Now %d will only zero pad if explicitly requested
to do so with the 0 flag (reported by Tero).
* Fixed an incorrect while() condition in TrioGetString (reported by Tero).
Version 0.12 - 1999/04/19
-------------------------
* Fixed incorrect zero padding of pointers
* Added StrHash with STRIO_HASH_PLAIN
* Added StrFormatDateMax
Version 0.11 - 1999/03/25
-------------------------
* Made it compile under cygwin
* Fixed a bug were TrioPreprocess would return an error if no formatting chars
were found (reported by Tero).
Version - 1999/03/19
--------------------
* Added trio_strerror and TRIO_ERROR_NAME.
* Changed the error codes to be positive (as errno)
* Fixed two reads of uninitialized memory reported by Purify
* Added binary specifiers 'b' and 'B' (like SCO.) ThousandSeparator can be
used to separate nibbles (4 bit)
* Renamed all Internal* functions to Trio*, which seems like a better
namespace (even though it is of no practical interest because these
functions are not visible beyond the scope of this file.)
Version - 1999/03/12
--------------------
* Added hex-float format for StrToDouble
* Double references and gaps in the arguments are not allowed (for the %n$
format) and in both cases an error code is returned.
* Added StrToDouble (and StrToFloat)
Version - 1999/03/08
--------------------
* Added InStream and OutStream to the trio_T structure.
* Started work on TrioScan.
* Return values for errors changed. Two macros to unpack the error code has
been added to the header.
* Shortshort (hh) flag added.
* %#s also quotes the quote-char now.
* Removed the 'errorInFormat' boolean, which isn't used anymore after the
functions bail out with an error instead.
Version - 1999/03/04
--------------------
* More than MAX_PARAMETERS parametes will now cause the TrioPreprocess()
function to return error.
* Unknown flags and/or specifiers cause errors too.
* Added trio_snprintfcat and trio_vsnprintfcat and the defined name
StrFormatAppendMax. They append a formatted string to the end of a string.
* Define MAX_PARAMETERS to 128 at all times instead of using NL_ARGMAX when
that exists.
* Added platform fixes for Amiga as suggested by Tero Jänkä <tesaja@utu.fi>
Version - 1999/01/31
--------------------
* vaprintf did add a zero byte even when it had failed.
* Cleaned up the code for locale handling and thousand separator
* Added trio_aprintf() and trio_vaprintf(). They return an allocated string.
* Added thousands separator for numbers
* Added floating point support for *printf
Version - 1998/10/20
--------------------
* StrMatchCase() called StrMatch() instead of itself recursively
* Rewrote the implementation of *printf and *scanf and put all the code in
this file. Extended qualifiers and qualifiers from other standards were
added.
* Added StrSpanFunction, StrToLong, and StrToUnsignedLong
Version - 1998/05/23
--------------------
* Made the StrEqual* functions resistant to NULL pointers
* Turns out strdup() is no standard at all, and some platforms (I seem to
recall HP-UX) has problems with it. Made our own StrDuplicate() instead.
* Added StrFormat() and StrFormatMax() to serve as sprintf() and snprintf()
respectively.

View File

@ -1,6 +0,0 @@
AUTOMAKE_OPTIONS = subdir-objects
DEFS = -DLOCALEDIR=\"$(datadir)/locale\" @DEFS@ @TRIO_CFLAGS@
DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/intl
noinst_LIBRARIES = libtrio.a
libtrio_a_SOURCES = trio.c trionan.c triostr.c

View File

@ -1,599 +0,0 @@
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@
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/trio
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_$(V))
am__v_AR_ = $(am__v_AR_$(AM_DEFAULT_VERBOSITY))
am__v_AR_0 = @echo " AR " $@;
AM_V_at = $(am__v_at_$(V))
am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
am__v_at_0 = @
libtrio_a_AR = $(AR) $(ARFLAGS)
libtrio_a_LIBADD =
am_libtrio_a_OBJECTS = trio.$(OBJEXT) trionan.$(OBJEXT) \
triostr.$(OBJEXT)
libtrio_a_OBJECTS = $(am_libtrio_a_OBJECTS)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
AM_V_lt = $(am__v_lt_$(V))
am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
am__v_lt_0 = --silent
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_$(V))
am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
am__v_CC_0 = @echo " CC " $@;
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_$(V))
am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
am__v_CCLD_0 = @echo " CCLD " $@;
AM_V_GEN = $(am__v_GEN_$(V))
am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
am__v_GEN_0 = @echo " GEN " $@;
SOURCES = $(libtrio_a_SOURCES)
DIST_SOURCES = $(libtrio_a_SOURCES)
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@ @TRIO_CFLAGS@
DEPDIR = @DEPDIR@
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@
MATH_OPTIMIZER_FLAGS = @MATH_OPTIMIZER_FLAGS@
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@
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@
XMKMF = @XMKMF@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
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@
lt_ECHO = @lt_ECHO@
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
noinst_LIBRARIES = libtrio.a
libtrio_a_SOURCES = trio.c trionan.c triostr.c
all: all-am
.SUFFIXES:
.SUFFIXES: .c .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/trio/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/trio/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)
libtrio.a: $(libtrio_a_OBJECTS) $(libtrio_a_DEPENDENCIES)
$(AM_V_at)-rm -f libtrio.a
$(AM_V_AR)$(libtrio_a_AR) libtrio.a $(libtrio_a_OBJECTS) $(libtrio_a_LIBADD)
$(AM_V_at)$(RANLIB) libtrio.a
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trio.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trionan.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/triostr.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LTCOMPILE) -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:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
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

@ -4,6 +4,5 @@
#include "video.h"
void MDFND_DispMessage(UTF8 *text);
void MDFNI_SaveSnapshot(const MDFN_Surface *src, const MDFN_Rect *rect, const MDFN_Rect *LineWidths);
#endif

View File

@ -160,14 +160,6 @@ class MDFN_PixelFormat
}; // MDFN_PixelFormat;
struct MDFN_PaletteEntry
{
uint8 r, g, b;
};
#include <vector>
typedef std::vector<MDFN_PaletteEntry> MDFN_Palette;
// Supports 32-bit RGBA
// 16-bit is WIP
class MDFN_Surface //typedef struct