(Mednafen PSX) Update to version 0.9.33.3

This commit is contained in:
twinaphex 2014-04-21 00:24:36 +02:00
parent 33d93a7229
commit c4267b048b
71 changed files with 58048 additions and 3 deletions

View File

@ -38,12 +38,13 @@ endif
NEED_CD = 1
NEED_TREMOR = 1
NEED_BPP = 32
WANT_NEW_API = 1
NEED_BLIP = 1
NEED_DEINTERLACER = 1
NEED_THREADING = 1
NEED_STEREO_SOUND = 1
CORE_DEFINE := -DWANT_PSX_EMU
CORE_DIR := $(MEDNAFEN_DIR)/psx-0932
CORE_DIR := $(MEDNAFEN_DIR)/psx-09333
CORE_SOURCES := $(CORE_DIR)/psx.cpp \
$(CORE_DIR)/irq.cpp \
$(CORE_DIR)/timer.cpp \

View File

@ -61,7 +61,7 @@ static Deinterlacer deint;
#if defined(WANT_PSX_EMU)
#define MEDNAFEN_CORE_NAME_MODULE "psx"
#define MEDNAFEN_CORE_NAME "Mednafen PSX"
#define MEDNAFEN_CORE_VERSION "v0.9.32"
#define MEDNAFEN_CORE_VERSION "v0.9.33.3"
#define MEDNAFEN_CORE_EXTENSIONS "cue|toc|m3u|ccd"
static double mednafen_psx_fps = 59.82704; // Hardcoded for NTSC atm.
#define MEDNAFEN_CORE_GEOMETRY_BASE_W 320
@ -93,7 +93,7 @@ static bool is_pal = false;
#define MEDNAFEN_CORE_NAME_MODULE "pce_fast"
#define MEDNAFEN_CORE_NAME "Mednafen PCE Fast"
#define MEDNAFEN_CORE_VERSION "v0.9.33.3"
#define MEDNAFEN_CORE_EXTENSIONS "pce|sgx|cue"
#define MEDNAFEN_CORE_EXTENSIONS "pce|sgx|cue|ccd"
#define MEDNAFEN_CORE_TIMING_FPS 59.82
#define MEDNAFEN_CORE_GEOMETRY_BASE_W (game->nominal_width)
#define MEDNAFEN_CORE_GEOMETRY_BASE_H (game->nominal_height)

701
mednafen/psx-09333/Makefile Normal file
View File

@ -0,0 +1,701 @@
# Makefile.in generated by automake 1.11.6 from Makefile.am.
# src/psx/Makefile. Generated from Makefile.in by configure.
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
am__make_dryrun = \
{ \
am__dry=no; \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
*) \
for am__flg in $$MAKEFLAGS; do \
case $$am__flg in \
*=*|--*) ;; \
*n*) am__dry=yes; break;; \
esac; \
done;; \
esac; \
test $$am__dry = yes; \
}
pkgdatadir = $(datadir)/mednafen
pkgincludedir = $(includedir)/mednafen
pkglibdir = $(libdir)/mednafen
pkglibexecdir = $(libexecdir)/mednafen
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 = x86_64-unknown-linux-gnu
host_triplet = x86_64-unknown-linux-gnu
target_triplet = x86_64-unknown-linux-gnu
am__append_1 = debug.cpp
subdir = src/psx
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 = @
libpsx_a_AR = $(AR) $(ARFLAGS)
libpsx_a_LIBADD =
am__libpsx_a_SOURCES_DIST = psx.cpp irq.cpp timer.cpp dma.cpp \
frontio.cpp sio.cpp cpu.cpp gte.cpp dis.cpp cdc.cpp spu.cpp \
gpu.cpp mdec.cpp input/gamepad.cpp input/dualanalog.cpp \
input/dualshock.cpp input/memcard.cpp input/multitap.cpp \
input/mouse.cpp input/negcon.cpp input/guncon.cpp \
input/justifier.cpp debug.cpp
am__dirstamp = $(am__leading_dot)dirstamp
am__objects_1 = debug.$(OBJEXT)
am_libpsx_a_OBJECTS = psx.$(OBJEXT) irq.$(OBJEXT) timer.$(OBJEXT) \
dma.$(OBJEXT) frontio.$(OBJEXT) sio.$(OBJEXT) cpu.$(OBJEXT) \
gte.$(OBJEXT) dis.$(OBJEXT) cdc.$(OBJEXT) spu.$(OBJEXT) \
gpu.$(OBJEXT) mdec.$(OBJEXT) input/gamepad.$(OBJEXT) \
input/dualanalog.$(OBJEXT) input/dualshock.$(OBJEXT) \
input/memcard.$(OBJEXT) input/multitap.$(OBJEXT) \
input/mouse.$(OBJEXT) input/negcon.$(OBJEXT) \
input/guncon.$(OBJEXT) input/justifier.$(OBJEXT) \
$(am__objects_1)
libpsx_a_OBJECTS = $(am_libpsx_a_OBJECTS)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_lt = $(am__v_lt_$(V))
am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
am__v_lt_0 = --silent
LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_CXX = $(am__v_CXX_$(V))
am__v_CXX_ = $(am__v_CXX_$(AM_DEFAULT_VERBOSITY))
am__v_CXX_0 = @echo " CXX " $@;
CXXLD = $(CXX)
CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CXXLD = $(am__v_CXXLD_$(V))
am__v_CXXLD_ = $(am__v_CXXLD_$(AM_DEFAULT_VERBOSITY))
am__v_CXXLD_0 = @echo " CXXLD " $@;
AM_V_GEN = $(am__v_GEN_$(V))
am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
am__v_GEN_0 = @echo " GEN " $@;
SOURCES = $(libpsx_a_SOURCES)
DIST_SOURCES = $(am__libpsx_a_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = ${SHELL} /home/squarepusher/Downloads/mednafen/missing --run aclocal-1.11
ALLOCA =
ALSA_CFLAGS =
ALSA_LIBS = -lasound -lm -ldl -lpthread
AMTAR = $${TAR-tar}
AM_CFLAGS = -fsigned-char -Wall -Winline -Wshadow -Wempty-body -Wignored-qualifiers -fno-fast-math -fno-unsafe-math-optimizations -fno-aggressive-loop-optimizations -fomit-frame-pointer -finline-limit=6000 --param large-function-growth=800 --param inline-unit-growth=175 --param max-inline-insns-single=10000 -fno-strict-overflow
AM_CXXFLAGS = -fsigned-char -Wall -Winline -Wshadow -Wempty-body -Wignored-qualifiers -fno-fast-math -fno-unsafe-math-optimizations -fno-aggressive-loop-optimizations -fomit-frame-pointer -finline-limit=6000 --param large-function-growth=800 --param inline-unit-growth=175 --param max-inline-insns-single=10000 -fno-strict-overflow
AM_DEFAULT_VERBOSITY = 1
AR = ar
AUTOCONF = ${SHELL} /home/squarepusher/Downloads/mednafen/missing --run autoconf
AUTOHEADER = ${SHELL} /home/squarepusher/Downloads/mednafen/missing --run autoheader
AUTOMAKE = ${SHELL} /home/squarepusher/Downloads/mednafen/missing --run automake-1.11
AWK = gawk
BUILD_INCLUDED_LIBINTL = no
CATOBJEXT = .gmo
CC = gcc
CCAS = gcc
CCASDEPMODE = depmode=gcc3
CCASFLAGS = -g -O2
CCDEPMODE = depmode=gcc3
CFLAGS = -g -O2
CFLAG_VISIBILITY = -fvisibility=hidden
CPP = gcc -E
CPPFLAGS =
CXX = g++
CXXCPP = g++ -E
CXXDEPMODE = depmode=gcc3
CXXFLAGS = -g -O2
CYGPATH_W = echo
DATADIRNAME = share
DEFS = -DLOCALEDIR=\"$(datadir)/locale\" -DHAVE_CONFIG_H -mmmx -msse -msse2 -funroll-loops
DEPDIR = .deps
DLLTOOL = false
DSYMUTIL =
DUMPBIN =
ECHO_C =
ECHO_N = -n
ECHO_T =
EGREP = /usr/bin/grep -E
EXEEXT =
FGREP = /usr/bin/grep -F
GBA_EXTRA_FLAGS = -fno-unit-at-a-time
GENCAT = gencat
GETTEXT_MACRO_VERSION = 0.18
GLIBC2 = yes
GLIBC21 = yes
GMSGFMT = /usr/bin/msgfmt
GMSGFMT_015 = /usr/bin/msgfmt
GREP = /usr/bin/grep
HAVE_ASPRINTF = 1
HAVE_NEWLOCALE = 1
HAVE_POSIX_PRINTF = 1
HAVE_SNPRINTF = 1
HAVE_VISIBILITY = 1
HAVE_WPRINTF = 0
INSTALL = /usr/bin/install -c
INSTALL_DATA = ${INSTALL} -m 644
INSTALL_PROGRAM = ${INSTALL}
INSTALL_SCRIPT = ${INSTALL}
INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
INSTOBJEXT = .mo
INTLBISON = bison
INTLLIBS =
INTLOBJS =
INTL_DEFAULT_VERBOSITY = 1
INTL_LIBTOOL_SUFFIX_PREFIX =
INTL_MACOSX_LIBS =
JACK_CFLAGS =
JACK_LIBS = -ljack -lpthread
LD = /usr/bin/ld -m elf_x86_64
LDFLAGS =
LIBCDIO_CFLAGS =
LIBCDIO_LIBS = -lcdio -lm
LIBICONV =
LIBINTL =
LIBMULTITHREAD = -lpthread
LIBOBJS =
LIBPTH =
LIBPTH_PREFIX =
LIBS = -lsndfile -lcdio -lm -lz -lz -lasound -lm -ldl -lpthread -ljack -lpthread
LIBTHREAD =
LIBTOOL = $(SHELL) $(top_builddir)/libtool
LIPO =
LN_S = ln -s
LTLIBC = -lc
LTLIBICONV =
LTLIBINTL =
LTLIBMULTITHREAD = -lpthread
LTLIBOBJS =
LTLIBPTH =
LTLIBTHREAD =
MAKEINFO = ${SHELL} /home/squarepusher/Downloads/mednafen/missing --run makeinfo
MANIFEST_TOOL = :
MKDIR_P = /usr/bin/mkdir -p
MMX_CFLAGS = -mmmx
MSGFMT = /usr/bin/msgfmt
MSGFMT_015 = /usr/bin/msgfmt
MSGMERGE = /usr/bin/msgmerge
NM = /usr/bin/nm -B
NMEDIT =
OBJDUMP = objdump
OBJEXT = o
OTOOL =
OTOOL64 =
PACKAGE = mednafen
PACKAGE_BUGREPORT =
PACKAGE_NAME =
PACKAGE_STRING =
PACKAGE_TARNAME =
PACKAGE_URL =
PACKAGE_VERSION =
PATH_SEPARATOR = :
PKG_CONFIG = /usr/bin/pkg-config
PKG_CONFIG_LIBDIR =
PKG_CONFIG_PATH =
POSUB = po
PRI_MACROS_BROKEN = 0
RANLIB = ranlib
SDL_CFLAGS = -I/usr/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
SDL_CONFIG = /usr/bin/sdl-config
SDL_LIBS = -L/usr/lib -lSDL -lpthread
SED = /usr/bin/sed
SET_MAKE =
SHELL = /bin/sh
SNDFILE_CFLAGS =
SNDFILE_LIBS = -lsndfile
SNES_EXTRA_CXXFLAGS =
SNES_EXTRA_FLAGS = -Wno-unused -Wno-inline -Wno-shadow -Wno-sign-compare -Wno-ignored-qualifiers -Wno-uninitialized -Wno-parentheses -Wno-switch
SNES_PERF_EXTRA_CXXFLAGS = -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-vectorize -fipa-cp-clone -fno-stack-protector
SNES_PERF_EXTRA_FLAGS = -Wno-unused -Wno-inline -Wno-shadow -Wno-sign-compare -Wno-ignored-qualifiers -Wno-uninitialized -Wno-parentheses -Wno-switch
SSE2_CFLAGS = -msse2
SSE3_CFLAGS = -msse3
SSE_CFLAGS = -msse
STRIP = strip
TRIO_CFLAGS =
USE_INCLUDED_LIBINTL = no
USE_NLS = yes
VERSION = 0.9.33.3
WARNING_FLAGS = -Wall -Winline -Wshadow -Wempty-body -Wignored-qualifiers
WINDRES =
WOE32 = no
WOE32DLL = no
XGETTEXT = /usr/bin/xgettext
XGETTEXT_015 = /usr/bin/xgettext
XGETTEXT_EXTRA_OPTIONS =
abs_builddir = /home/squarepusher/Downloads/mednafen/src/psx
abs_srcdir = /home/squarepusher/Downloads/mednafen/src/psx
abs_top_builddir = /home/squarepusher/Downloads/mednafen
abs_top_srcdir = /home/squarepusher/Downloads/mednafen
ac_ct_AR = ar
ac_ct_CC = gcc
ac_ct_CXX = g++
ac_ct_DUMPBIN =
am__include = include
am__leading_dot = .
am__quote =
am__tar = $${TAR-tar} chof - "$$tardir"
am__untar = $${TAR-tar} xf -
bindir = ${exec_prefix}/bin
build = x86_64-unknown-linux-gnu
build_alias =
build_cpu = x86_64
build_os = linux-gnu
build_vendor = unknown
builddir = .
datadir = ${datarootdir}
datarootdir = ${prefix}/share
docdir = ${datarootdir}/doc/${PACKAGE}
dvidir = ${docdir}
exec_prefix = ${prefix}
host = x86_64-unknown-linux-gnu
host_alias =
host_cpu = x86_64
host_os = linux-gnu
host_vendor = unknown
htmldir = ${docdir}
includedir = ${prefix}/include
infodir = ${datarootdir}/info
install_sh = ${SHELL} /home/squarepusher/Downloads/mednafen/install-sh
libdir = ${exec_prefix}/lib
libexecdir = ${exec_prefix}/libexec
localedir = ${datarootdir}/locale
localstatedir = ${prefix}/var
mandir = ${datarootdir}/man
mkdir_p = /usr/bin/mkdir -p
oldincludedir = /usr/include
pdfdir = ${docdir}
prefix = /usr/local
program_transform_name = s,x,x,
psdir = ${docdir}
sbindir = ${exec_prefix}/sbin
sharedstatedir = ${prefix}/com
srcdir = .
sysconfdir = ${prefix}/etc
target = x86_64-unknown-linux-gnu
target_alias =
target_cpu = x86_64
target_os = linux-gnu
target_vendor = unknown
top_build_prefix = ../../
top_builddir = ../..
top_srcdir = ../..
AUTOMAKE_OPTIONS = subdir-objects
DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/intl -I$(top_srcdir)
noinst_LIBRARIES = libpsx.a
libpsx_a_SOURCES = psx.cpp irq.cpp timer.cpp dma.cpp frontio.cpp \
sio.cpp cpu.cpp gte.cpp dis.cpp cdc.cpp spu.cpp gpu.cpp \
mdec.cpp input/gamepad.cpp input/dualanalog.cpp \
input/dualshock.cpp input/memcard.cpp input/multitap.cpp \
input/mouse.cpp input/negcon.cpp input/guncon.cpp \
input/justifier.cpp $(am__append_1)
all: all-am
.SUFFIXES:
.SUFFIXES: .cpp .lo .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/psx/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/psx/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)
input/$(am__dirstamp):
@$(MKDIR_P) input
@: > input/$(am__dirstamp)
input/$(DEPDIR)/$(am__dirstamp):
@$(MKDIR_P) input/$(DEPDIR)
@: > input/$(DEPDIR)/$(am__dirstamp)
input/gamepad.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/dualanalog.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/dualshock.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/memcard.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/multitap.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/mouse.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/negcon.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/guncon.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/justifier.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
libpsx.a: $(libpsx_a_OBJECTS) $(libpsx_a_DEPENDENCIES) $(EXTRA_libpsx_a_DEPENDENCIES)
$(AM_V_at)-rm -f libpsx.a
$(AM_V_AR)$(libpsx_a_AR) libpsx.a $(libpsx_a_OBJECTS) $(libpsx_a_LIBADD)
$(AM_V_at)$(RANLIB) libpsx.a
mostlyclean-compile:
-rm -f *.$(OBJEXT)
-rm -f input/dualanalog.$(OBJEXT)
-rm -f input/dualshock.$(OBJEXT)
-rm -f input/gamepad.$(OBJEXT)
-rm -f input/guncon.$(OBJEXT)
-rm -f input/justifier.$(OBJEXT)
-rm -f input/memcard.$(OBJEXT)
-rm -f input/mouse.$(OBJEXT)
-rm -f input/multitap.$(OBJEXT)
-rm -f input/negcon.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
include ./$(DEPDIR)/cdc.Po
include ./$(DEPDIR)/cpu.Po
include ./$(DEPDIR)/debug.Po
include ./$(DEPDIR)/dis.Po
include ./$(DEPDIR)/dma.Po
include ./$(DEPDIR)/frontio.Po
include ./$(DEPDIR)/gpu.Po
include ./$(DEPDIR)/gte.Po
include ./$(DEPDIR)/irq.Po
include ./$(DEPDIR)/mdec.Po
include ./$(DEPDIR)/psx.Po
include ./$(DEPDIR)/sio.Po
include ./$(DEPDIR)/spu.Po
include ./$(DEPDIR)/timer.Po
include input/$(DEPDIR)/dualanalog.Po
include input/$(DEPDIR)/dualshock.Po
include input/$(DEPDIR)/gamepad.Po
include input/$(DEPDIR)/guncon.Po
include input/$(DEPDIR)/justifier.Po
include input/$(DEPDIR)/memcard.Po
include input/$(DEPDIR)/mouse.Po
include input/$(DEPDIR)/multitap.Po
include input/$(DEPDIR)/negcon.Po
.cpp.o:
$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
$(am__mv) $$depbase.Tpo $$depbase.Po
# $(AM_V_CXX)source='$<' object='$@' libtool=no \
# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
# $(AM_V_CXX_no)$(CXXCOMPILE) -c -o $@ $<
.cpp.obj:
$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
$(am__mv) $$depbase.Tpo $$depbase.Po
# $(AM_V_CXX)source='$<' object='$@' libtool=no \
# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
# $(AM_V_CXX_no)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.cpp.lo:
$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
$(am__mv) $$depbase.Tpo $$depbase.Plo
# $(AM_V_CXX)source='$<' object='$@' libtool=yes \
# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
# $(AM_V_CXX_no)$(LTCXXCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
set x; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(LIBRARIES)
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-rm -f input/$(DEPDIR)/$(am__dirstamp)
-rm -f input/$(am__dirstamp)
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) input/$(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) input/$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am:
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
clean-libtool clean-noinstLIBRARIES ctags distclean \
distclean-compile distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
install-html-am install-info install-info-am install-man \
install-pdf install-pdf-am install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags uninstall uninstall-am
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View File

@ -0,0 +1,12 @@
AUTOMAKE_OPTIONS = subdir-objects
DEFS = -DLOCALEDIR=\"$(datadir)/locale\" @DEFS@ @MMX_CFLAGS@ @SSE_CFLAGS@ @SSE2_CFLAGS@ -funroll-loops
DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/intl -I$(top_srcdir)
noinst_LIBRARIES = libpsx.a
libpsx_a_SOURCES = psx.cpp irq.cpp timer.cpp dma.cpp frontio.cpp sio.cpp cpu.cpp gte.cpp dis.cpp cdc.cpp spu.cpp gpu.cpp mdec.cpp
libpsx_a_SOURCES += input/gamepad.cpp input/dualanalog.cpp input/dualshock.cpp input/memcard.cpp input/multitap.cpp input/mouse.cpp input/negcon.cpp input/guncon.cpp input/justifier.cpp
if WANT_DEBUGGER
libpsx_a_SOURCES += debug.cpp
endif

View File

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

173
mednafen/psx-09333/PSX-TODO Normal file
View File

@ -0,0 +1,173 @@
***Major issues***
Tomb Raider(PAL)
(reported, and confirmed) "was fighting Tomb Raider PAL this night, when you get out of pool in Lara's home the game
bugs out: issues GetlocP, waits for it to complete and expects seek to be NOT complete (i.e. older location)"
Thoughts on emulating:
CalcSpinupTime()
DS_SPINUP
StatusAfterSpinup ORRR we could scrap that StatusAfter* idea and have some kind of fancy function callback system...
Monkey Hero
Locks up shortly after title screen. It's straddling a framebuffer write command's parameters across two linked-list
blocks(2 words at the end of the first block, and 1 word at the beginning of the next block). AFAIK, this construct will only
work on the real thing under *very* strict timing constraints. Probably explains why it reportedly doesn't work on the PS2.
It's as easy to fix as changing a certain 2 to a 3 in the GPU command table, and probably won't break anything,
but I'm still reluctant to do it...
Tales of Destiny (Japanese version 1.0)
Frequently locks up after random battles in the cave after Mary joins. US version is reported to not suffer from this problem.
Looks like the game is stuck waiting for an SPU IRQ that never happens. The problem seems to be related to usage of Mary's "Moushuuken" skill.
Simple 1500 Series Vol. 057 - The Maze
Locks up during startup; looks to be poorly programmed and extremely sensitive to seek timing.
----------------------------------------------------------------------------------------------
***Medium issues***
Championship Motocross 2001
Invisible driver. GHOSTRIDER~ The palette data in RAM is apparently being selectively zero'd out between
the DMA from CDC and the DMA to GPU for some reason. Timing issue related maybe? (Probably CPU instruction timing issue)
Nicktoons Racing
Totally fubared sound effects. Likely CPU instruction timing-related(decreasing the IPC fixes this problem), or perhaps timing
related to SPU RAM writes?
Resident Evil - Director's Cut(non-Dual Shock-version)
Controller configuration screen pops up on some screen transitions; probably one of those stupid seek timing-related issues.
-----------------------------------------------------------------------------------------------
***Lesser issues***
Thousand Arms
Many dialogue voices cut off a half second or so early; related to SPU IRQs and playback SPU RAM read timing I think.
Final Fantasy 8
Reported 3D model(character) flicker at some points in the game - look into it.
Tactics Ogre
Menu/Overlay elements on the map screen periodically flicker; seems to be a timing thing probably related to the sound engine
in the game. Although upon further inspection, it may be a GPU command timing issue in that we're emulating the GPU primitive
drawing faster than occurs on an actual PS1. Might require texture cache simulation to some degree.
Castrol Honda Superbike Racing
Graphical glitches on startup, menus(fixed now probably), and loading screens. (What is with all
these racing games having weird timing-related problems, it's like some sort of curse)
Vigilante 8
Has weird red and green(and a few blue) garbage pixels in patches sometimes during gameplay; "garbage" pixel placement
is somewhat sparse, so it might not even be noticeable if it were to occur on a PS1 with composite or S-video output, due to limited
chroma bandwidth.
Final Fantasy 7
"Sony Computer blah blah" game startup image is a bit glitchy; interlacing-related glitch. That part is really sensitive to CPU, GPU, DMA,
and RAM timing...
Adventures of Lomax, The
"QSOUND" loading screen during startup is a flickery mess; interlacing-related glitch from the looks of it.
Maybe it's like that on an actual PS1 too?
Nightmare Creatures
BIOS reverb sound excessively contaminates beginning of game.
Shadow Master
Might have broken startup images.
WipeOut 3
Music stops playing after a long while; maybe it's supposed to do that?
-----------------------------------------------------------------------------------------------
***Chaotic timing issues(listed here for reference and testing after any future timing tweaks or improvements)***
Battle Arena Toshinden
NBA Jam Extreme
Zero Divide
Run too fast if CPU and(/or?) GPU operations execute too fast. Probably not an issue anymore, but still
listed here for reference.
iS: Internal Section
Arcade Party Pak (Toobin)
Next Tetris, The
Extremely sensitive about interlacing semantics, especially in regards to the high bit of the GPU status register when entering
interlaced 480-height mode.
Ballblazer Champions
Excessively sensitive to timing issues; might lock up during startup sometimes.
FIFA - Road to Worldcup 98 (USA)
Used to lock up during startup; probably CPU instruction timing-related, or MDEC timing related,
or CDC timing related, or DMA timing related, or maybe the moon phase is to blame!
[CDC] WARNING: Interrupting command 0x02, phase=0, timeleft=1195 with command=0x02
[CDC] Bad number(5) of args(first check) for command 0x02
0x39 0x23 0x22 0x41 0x67
Freestyle Motocross: McGrath vs. Pastrana
Used to suffer from random fairly long(but finite) freezes during gameplay. Possibly CPU instruction-timing
related. Possibly CDC-timing related.
[CDC] Command: ReadN ---
[CDC] Command: Standby ---
[CDC] Command: Nop ---
[CDC] Command: Setmode --- 0xa0
[CDC] Command: Setloc --- 0x08 0x13 0x53
[CDC] Command: ReadN ---
20076
[CDC] Command: Standby ---
[CDC] Command: Nop ---
[CDC] Command: Setmode --- 0xa0
[CDC] Command: Setloc --- 0x08 0x13 0x61
0x800668B8
Resident Evil 2
Lockup on second disc in a certain place; probably related to seek timing. Seems to be fixed now, but still listed
here for reference.
-----------------------------------------------------------------------------------------------
Star Wars Dark Forces notes(for working towards removing a kludge/hack in the DMA IRQ handling)
PC=0x8001B124: [DMA] Write: 1f8010f4 008a0000, DMAIntStatus=0000000c
if(V == 0x008a0000 && DMAIntStatus == 0x0000000c)
DBG_Break(); // V |= 8 << 24; //V |= 4 << 24;
Add a means of grabbing and passing CIRC data, when using a physical CD, from Mednafen core to the PSX module so that the correct
subheader fields can be chosen when there is a mismatch between the two instances of each field during XA ADPCM playback.
Ensure(long-term, IE a note to the FUTURE) that input device state is latched in independent variables at the start of the
input device's handling of a state read command, so that when games are reading device state across an MDFNI_Emulate() boundary, the
data won't change in the middle, which could hypothetically cause problems in some rare circumstances(and make entering
button combos in games more finicky).
Respect device(GPU, SPU, etc.) DMA mode/memory access mode bits(more for homebrew's sake than commercial games').
Test if Dual Analog vibration compatibility mode can be restored with DualShock after using DualShock extended features if the "Analog"
mode button on the gamepad is pressed after the extended features are used.
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.
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,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

2383
mednafen/psx-09333/cdc.cpp Normal file

File diff suppressed because it is too large Load Diff

275
mednafen/psx-09333/cdc.h Normal file
View File

@ -0,0 +1,275 @@
#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;
int32 ReadPos;
};
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);
void SoftReset(void);
void GetCDAudio(int32 samples[2]);
private:
CDIF *Cur_CDIF;
bool DiscChanged;
int32 DiscStartupDelay;
CD_Audio_Buffer AudioBuffer;
uint8 Pending_DecodeVolume[2][2], DecodeVolume[2][2]; // [data_source][output_port]
int16 ADPCM_ResampBuf[2][32 * 2];
uint8 ADPCM_ResampCurPos;
uint8 ADPCM_ResampCurPhase;
void ApplyVolume(int32 samples[2]);
void ReadAudioBuffer(int32 samples[2]);
void ClearAudioBuffers(void);
//
//
//
uint8 RegSelector;
uint8 ArgsBuf[16];
uint8 ArgsWP; // 5-bit(0 ... 31)
uint8 ArgsRP; // 5-bit(0 ... 31)
uint8 ArgsReceiveLatch;
uint8 ArgsReceiveBuf[32];
uint8 ArgsReceiveIn;
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;
enum { SectorPipe_Count = 2 };
uint8 SectorPipe[SectorPipe_Count][2352];
uint8 SectorPipe_Pos;
uint8 SectorPipe_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;
int 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);
void EnbufferizeCDDASector(const uint8 *buf);
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;
void HandlePlayRead(void);
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(bool logical, 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

2556
mednafen/psx-09333/cpu.cpp Normal file

File diff suppressed because it is too large Load Diff

254
mednafen/psx-09333/cpu.h Normal file
View File

@ -0,0 +1,254 @@
#ifndef __MDFN_PSX_CPU_H
#define __MDFN_PSX_CPU_H
/*
Load delay notes:
// Takes 1 less
".set noreorder\n\t"
".set nomacro\n\t"
"lw %0, 0(%2)\n\t"
"nop\n\t"
"nop\n\t"
"or %0, %1, %1\n\t"
// cycle than this:
".set noreorder\n\t"
".set nomacro\n\t"
"lw %0, 0(%2)\n\t"
"nop\n\t"
"or %0, %1, %1\n\t"
"nop\n\t"
// Both of these
".set noreorder\n\t"
".set nomacro\n\t"
"lw %0, 0(%2)\n\t"
"nop\n\t"
"nop\n\t"
"or %1, %0, %0\n\t"
// take same...(which is kind of odd).
".set noreorder\n\t"
".set nomacro\n\t"
"lw %0, 0(%2)\n\t"
"nop\n\t"
"or %1, %0, %0\n\t"
"nop\n\t"
*/
#include "gte.h"
namespace MDFN_IEN_PSX
{
#define PS_CPU_EMULATE_ICACHE 1
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);
// TODO eventually: factor BIU address decoding directly in the CPU core somehow without hurting speed.
void SetBIU(uint32 val);
uint32 GetBIU(void);
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;
uint32 LDAbsorb;
pscpu_timestamp_t next_event_ts;
pscpu_timestamp_t gte_ts_done;
pscpu_timestamp_t muldiv_ts_done;
uint32 BIU;
struct __ICache
{
uint32 TV;
uint32 Data;
} ICache[1024];
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;
#if 1
//uint32 WrAbsorb;
//uint8 WrAbsorbShift;
// On read:
//WrAbsorb = 0;
//WrAbsorbShift = 0;
// On write:
//WrAbsorb >>= (WrAbsorbShift >> 2) & 8;
//WrAbsorbShift -= (WrAbsorbShift >> 2) & 8;
//WrAbsorb |= (timestamp - pre_write_timestamp) << WrAbsorbShift;
//WrAbsorbShift += 8;
#endif
struct
{
uint8 ReadAbsorb[0x20];
uint8 ReadAbsorbDummy;
};
uint8 ReadAbsorbWhich;
uint8 ReadFudge;
//uint32 WriteAbsorb;
//uint8 WriteAbsorbCount;
//uint8 WriteAbsorbMonkey;
MultiAccessSizeMem<1024, uint32, false> ScratchRAM;
//PS_GTE GTE;
uint8 *FastMap[1 << (32 - FAST_MAP_SHIFT)];
uint8 DummyPage[FAST_MAP_PSIZE];
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 PeekMemory(uint32 address) MDFN_COLD;
template<typename T> T ReadMemory(pscpu_timestamp_t &timestamp, uint32 address, bool DS24 = false, bool LWC_timing = 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)(const pscpu_timestamp_t timestamp, 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);
bool PeekCheckICache(uint32 PC, uint32 *iw);
uint8 PeekMem8(uint32 A);
uint16 PeekMem16(uint32 A);
uint32 PeekMem32(uint32 A);
private:
void (*CPUHook)(const pscpu_timestamp_t timestamp, uint32 pc);
void (*ADDBT)(uint32 from, uint32 to, bool exception);
};
}
#endif

View File

@ -0,0 +1,687 @@
/* 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 RedoCPUHook(void);
static void (*CPUHook)(uint32, bool) = NULL;
static bool CPUHookContinuous = false;
struct PSX_BPOINT
{
uint32 A[2];
int type;
};
static std::vector<PSX_BPOINT> BreakPointsPC, BreakPointsRead, BreakPointsWrite;
static bool FoundBPoint;
static bool BTEnabled;
static int BTIndex;
struct BTEntry
{
uint32 from;
uint32 to;
uint32 branch_count;
bool exception;
bool valid;
};
#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->valid)
prevbt->branch_count++;
else
{
BTEntries[BTIndex].from = from;
BTEntries[BTIndex].to = to;
BTEntries[BTIndex].exception = exception;
BTEntries[BTIndex].branch_count = 1;
BTEntries[BTIndex].valid = true;
BTIndex = (BTIndex + 1) % NUMBT;
}
}
static void EnableBranchTrace(bool enable)
{
BTEnabled = enable;
if(!enable)
{
BTIndex = 0;
memset(BTEntries, 0, sizeof(BTEntries));
}
RedoCPUHook();
}
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(const pscpu_timestamp_t timestamp, 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]);
}
for(bpit = BreakPointsPC.begin(); bpit != BreakPointsPC.end(); bpit++)
{
if(PC >= bpit->A[0] && PC <= bpit->A[1])
{
FoundBPoint = true;
break;
}
}
CPU->CheckBreakpoints(CheckCPUBPCallB, CPU->PeekMem32(PC));
CPUHookContinuous |= FoundBPoint;
if(CPUHookContinuous && CPUHook)
{
ForceEventUpdates(timestamp);
CPUHook(PC, FoundBPoint);
}
FoundBPoint = false;
}
static void RedoCPUHook(void)
{
const bool HappyTest = CPUHook || BreakPointsPC.size() || BreakPointsRead.size() || BreakPointsWrite.size();
CPU->SetCPUHook(HappyTest ? CPUHandler : NULL, BTEnabled ? 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, bool bpoint), bool continuous)
{
CPUHook = callb;
CPUHookContinuous = continuous;
RedoCPUHook();
}
static void GetAddressSpaceBytes(const char *name, uint32 Address, uint32 Length, uint8 *Buffer)
{
if(!strcmp(name, "cpu"))
{
while(Length--)
{
Address &= 0xFFFFFFFF;
*Buffer = CPU->PeekMem8(Address);
Address++;
Buffer++;
}
}
else if(!strcmp(name, "ram"))
{
while(Length--)
{
Address &= 0x1FFFFF;
*Buffer = CPU->PeekMem8(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--)
{
pscpu_timestamp_t dummy = 0;
Address &= 0xFFFFFFFF;
// TODO
PSX_MemWrite8(dummy, 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 |= CPU->PeekMem8(A + i) << (i * 8);
return(ret);
}
static void Disassemble(uint32 &A, uint32 SpecialA, char *TextBuf)
{
assert(!(A & 0x3));
uint32 instr = CPU->PeekMem32(A);
CPU->PeekCheckICache(A, &instr);
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,
EnableBranchTrace,
GetBranchTrace,
SetGraphicsDecode,
NULL, //PCFXDBG_SetLogFunc,
};
static RegType Regs_Misc[] =
{
{ TIMER_GSREG_COUNTER0, "COUNT0", "Counter 0", 2 },
{ TIMER_GSREG_MODE0, "MODE0", "Mode 0", 2 },
{ TIMER_GSREG_TARGET0, "TARGET0", "Target 0", 2 },
{ 0, "------", "", 0xFFFF },
{ TIMER_GSREG_COUNTER1, "COUNT1", "Counter 1", 2 },
{ TIMER_GSREG_MODE1, "MODE1", "Mode 1", 2 },
{ TIMER_GSREG_TARGET1, "TARGET1", "Target 1", 2 },
{ 0, "------", "", 0xFFFF },
{ TIMER_GSREG_COUNTER2, "COUNT2", "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, "ASSERTD", "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_DST_A0", "", 2 },
{ PS_SPU::GSREG_IIR_DEST_A1, "IIR_DST_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_DST_B0", "", 2 },
{ PS_SPU::GSREG_IIR_DEST_B1, "IIR_DST_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_DST_A0", "", 2 },
{ PS_SPU::GSREG_MIX_DEST_A1, "MIX_DST_A1", "", 2 },
{ PS_SPU::GSREG_MIX_DEST_B0, "MIX_DST_B0", "", 2 },
{ PS_SPU::GSREG_MIX_DEST_B1, "MIX_DST_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(9),
VOICE_HELPER(12),
VOICE_HELPER(17),
VOICE_HELPER(22),
//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;
CPUHookContinuous = false;
FoundBPoint = false;
BTEnabled = false;
BTIndex = false;
memset(BTEntries, 0, sizeof(BTEntries));
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);
}
}

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-09333/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 (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, ((unsigned)op << 26) | func, mnemonic, format }
#define MK_OP_REGIMM(mnemonic, regop) { MASK_OP | MASK_RT, (0x01U << 26) | (regop << 16), mnemonic, "s, p" }
#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 | (0x1FU << 21), ((0x10U | z) << 26) | (xf << 21), mnemonic, format }
#define MK_GTE(mnemonic, format, func) { MASK_OP | (0x1U << 25) | MASK_FUNC, (0x1U << 25) | (0x12U << 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];
trio_snprintf(s_a, sizeof(s_a), "%d", shamt);
if(immediate < 0)
trio_snprintf(s_i, sizeof(s_i), "%d", immediate);
else
trio_snprintf(s_i, sizeof(s_i), "0x%04x", (uint32)immediate);
trio_snprintf(s_z, sizeof(s_z), "0x%04x", immediate_ze);
trio_snprintf(s_p, sizeof(s_p), "0x%08x", PC + 4 + (immediate << 2));
trio_snprintf(s_P, sizeof(s_P), "0x%08x", ((PC + 4) & 0xF0000000) | (jt << 2));
trio_snprintf(s_c, sizeof(s_c), "CPR%d", rd);
trio_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;
trio_snprintf(as, 16, "sf=%d", (int)(bool)(instr & (1 << 19)));
}
else if(!strncmp(&op->format[i], "#mx#", 4))
{
i += 3;
trio_snprintf(as, 16, "mx=%d", (instr >> 17) & 0x3);
}
else if(!strncmp(&op->format[i], "#v#", 3))
{
i += 2;
trio_snprintf(as, 16, "v=%d", (instr >> 15) & 0x3);
}
else if(!strncmp(&op->format[i], "#cv#", 4))
{
i += 3;
trio_snprintf(as, 16, "cv=%d", (instr >> 13) & 0x3);
}
else if(!strncmp(&op->format[i], "#lm#", 4))
{
i += 3;
trio_snprintf(as, 16, "lm=%d", (int)(bool)(instr & (1 << 10)));
}
ret.append(as);
}
break;
case 'F':
{
char s_F[16];
trio_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-09333/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

821
mednafen/psx-09333/dma.cpp Normal file
View File

@ -0,0 +1,821 @@
/* 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"
//#include <map>
// Notes: DMA tested to abort when
/* 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_FIVE = 5,
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;
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();
}
void PSX_SetDMASuckSuck(unsigned);
static INLINE bool ChCan(const unsigned ch, const uint32 CRModeCache)
{
switch(ch)
{
default:
abort();
case CH_MDEC_IN:
return(MDEC_DMACanWrite());
case CH_MDEC_OUT:
return(MDEC_DMACanRead());
case CH_GPU:
if(CRModeCache & 0x1)
return(GPU->DMACanWrite());
else
return(true);
case CH_CDC:
return(true);
case CH_SPU:
return(true);
case CH_FIVE:
return(false);
case CH_OT:
return((bool)(DMACH[ch].ChanControl & (1U << 28)));
}
}
static void RecalcHalt(void)
{
bool Halt = false;
unsigned ch = 0;
for(ch = 0; ch < 7; ch++)
{
if(DMACH[ch].ChanControl & (1U << 24))
{
if(!(DMACH[ch].ChanControl & (7U << 8)))
{
if(DMACH[ch].WordCounter > 0)
{
Halt = true;
break;
}
}
#if 0
if(DMACH[ch].ChanControl & 0x100) // DMA doesn't hog the bus when this bit is set, though the DMA takes longer.
continue;
if(ch == 4 || ch == 5) // Not sure if these channels will typically hog the bus or not...investigate.
continue;
if(!(DMACH[ch].ChanControl & (1U << 10))) // Not sure about HOGGERYNESS with linked-list mode, and it likely wouldn't work well either in regards
// to GPU commands due to the rather large DMA update granularity.
{
if((DMACH[ch].WordCounter > 0) || ChCan(ch, DMACH[ch].ChanControl & 0x1))
{
Halt = true;
break;
}
}
#endif
}
}
#if 0
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;
#endif
//printf("Halt: %d\n", Halt);
if(!Halt && (DMACH[2].ChanControl & (1U << 24)) && ((DMACH[2].ChanControl & 0x700) == 0x200) && ChCan(2, DMACH[2].ChanControl))
{
unsigned tmp = DMACH[2].BlockControl & 0xFFFF;
if(tmp > 0)
tmp--;
if(tmp > 200) // Due to 8-bit limitations in the CPU core.
tmp = 200;
PSX_SetDMASuckSuck(tmp);
}
else
PSX_SetDMASuckSuck(0);
CPU->SetHalt(Halt);
}
static INLINE void ChRW(const unsigned ch, const uint32 CRModeCache, uint32 *V)
{
unsigned extra_cyc_overhead = 0;
switch(ch)
{
default:
abort();
break;
case CH_MDEC_IN:
if(CRModeCache & 0x1)
MDEC_DMAWrite(*V);
else
*V = 0;
break;
case CH_MDEC_OUT:
if(CRModeCache & 0x1)
{
}
else
*V = MDEC_DMARead();
break;
case CH_GPU:
if(CRModeCache & 0x1)
GPU->WriteDMA(*V);
else
*V = GPU->ReadDMA();
break;
case CH_CDC:
// 0x1f801018 affects CDC DMA timing.
#if 0
if(CRModeCache & 0x100) // For CDC DMA(at least): When this bit is set, DMA controller doesn't appear to hog the (RAM?) bus.
{
if(CRModeCache & 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
if(CRModeCache & 0x1)
{
}
else
{
extra_cyc_overhead = 8; // FIXME: Test.
*V = CDC->DMARead(); // Note: Legend of Mana's opening movie is sensitive to DMA timing, including CDC.
}
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.
extra_cyc_overhead = 47; // Should be closer to 69, average, but actual timing is...complicated.
if(CRModeCache & 0x1)
SPU->WriteDMA(*V);
else
*V = SPU->ReadDMA();
break;
case CH_FIVE:
if(CRModeCache & 0x1)
{
}
else
{
*V = 0;
}
break;
case CH_OT:
if(DMACH[ch].WordCounter == 1)
*V = 0xFFFFFF;
else
*V = (DMACH[ch].CurAddr - 4) & 0x1FFFFF;
break;
}
// GROSS APPROXIMATION, shoehorning multiple effects together, TODO separate(especially SPU and CDC)
DMACH[ch].ClockCounter -= std::max<int>(extra_cyc_overhead, (CRModeCache & 0x100) ? 7 : 0);
}
//
// Remember to handle an end condition on the same iteration of the while(DMACH[ch].ClockCounter > 0) loop that caused it,
// otherwise RecalcHalt() might take the CPU out of a halted state before the end-of-DMA is signaled(especially a problem considering our largeish
// DMA update timing granularity).
//
static INLINE void RunChannelI(const unsigned ch, const uint32 CRModeCache, int32 clocks)
{
//const uint32 dc = (DMAControl >> (ch * 4)) & 0xF;
DMACH[ch].ClockCounter += clocks;
while(MDFN_LIKELY(DMACH[ch].ClockCounter > 0))
{
if(DMACH[ch].WordCounter == 0) // Begin WordCounter reload.
{
if(!(DMACH[ch].ChanControl & (1 << 24))) // Needed for the forced-DMA-stop kludge(see DMA_Write()).
break;
if(!ChCan(ch, CRModeCache))
break;
DMACH[ch].CurAddr = DMACH[ch].BaseAddr;
if(CRModeCache & (1U << 10))
{
uint32 header;
if(MDFN_UNLIKELY(DMACH[ch].CurAddr & 0x800000))
{
DMACH[ch].ChanControl &= ~(0x11 << 24);
DMAIntControl |= 0x8000;
RecalcIRQOut();
break;
}
header = MainRAM.ReadU32(DMACH[ch].CurAddr & 0x1FFFFC);
DMACH[ch].CurAddr = (DMACH[ch].CurAddr + 4) & 0xFFFFFF;
DMACH[ch].WordCounter = header >> 24;
DMACH[ch].BaseAddr = header & 0xFFFFFF;
// printf to debug Soul Reaver ;)
//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;
goto SkipPayloadStuff; // 3 cheers for gluten-free spaghetticode(necessary because the newly-loaded WordCounter might be 0, and we actually
// want 0 to mean 0 and not 65536 in this context)!
}
else
{
DMACH[ch].WordCounter = DMACH[ch].BlockControl & 0xFFFF;
if(CRModeCache & (1U << 9))
{
if(ch == 2) // Technically should apply to all channels, but since we don't implement CPU read penalties for channels other than 2 yet, it's like this to avoid making DMA longer than what games can handle.
DMACH[ch].ClockCounter -= 7;
DMACH[ch].BlockControl = (DMACH[ch].BlockControl & 0xFFFF) | ((DMACH[ch].BlockControl - (1U << 16)) & 0xFFFF0000);
}
}
} // End WordCounter reload.
else if(CRModeCache & 0x100) // BLARGH BLARGH FISHWHALE
{
//printf("LoadWC: %u(oldWC=%u)\n", DMACH[ch].BlockControl & 0xFFFF, DMACH[ch].WordCounter);
//MDFN_DispMessage("SPOOOON\n");
DMACH[ch].CurAddr = DMACH[ch].BaseAddr;
DMACH[ch].WordCounter = DMACH[ch].BlockControl & 0xFFFF;
}
//
// Do the payload read/write
//
{
uint32 vtmp;
if(MDFN_UNLIKELY(DMACH[ch].CurAddr & 0x800000))
{
DMACH[ch].ChanControl &= ~(0x11 << 24);
DMAIntControl |= 0x8000;
RecalcIRQOut();
break;
}
if(CRModeCache & 0x1)
vtmp = MainRAM.ReadU32(DMACH[ch].CurAddr & 0x1FFFFC);
ChRW(ch, CRModeCache, &vtmp);
if(!(CRModeCache & 0x1))
MainRAM.WriteU32(DMACH[ch].CurAddr & 0x1FFFFC, vtmp);
}
if(CRModeCache & 0x2)
DMACH[ch].CurAddr = (DMACH[ch].CurAddr - 4) & 0xFFFFFF;
else
DMACH[ch].CurAddr = (DMACH[ch].CurAddr + 4) & 0xFFFFFF;
DMACH[ch].WordCounter--;
DMACH[ch].ClockCounter--;
SkipPayloadStuff: ;
if(CRModeCache & 0x100) // BLARGH BLARGH WHALEFISH
{
DMACH[ch].BaseAddr = DMACH[ch].CurAddr;
DMACH[ch].BlockControl = (DMACH[ch].BlockControl & 0xFFFF0000) | DMACH[ch].WordCounter;
//printf("SaveWC: %u\n", DMACH[ch].WordCounter);
}
//
// Handle channel end condition:
//
if(DMACH[ch].WordCounter == 0)
{
bool ChannelEndTC = false;
if(!(DMACH[ch].ChanControl & (1 << 24))) // Needed for the forced-DMA-stop kludge(see DMA_Write()).
break;
switch((CRModeCache >> 9) & 0x3)
{
case 0x0:
ChannelEndTC = true;
break;
case 0x1:
DMACH[ch].BaseAddr = DMACH[ch].CurAddr;
if((DMACH[ch].BlockControl >> 16) == 0)
ChannelEndTC = true;
break;
case 0x2:
case 0x3: // Not sure about 0x3.
if(DMACH[ch].BaseAddr == 0xFFFFFF)
ChannelEndTC = true;
break;
}
if(ChannelEndTC)
{
DMACH[ch].ChanControl &= ~(0x11 << 24);
if(DMAIntControl & (1U << (16 + ch)))
{
DMAIntStatus |= 1U << ch;
RecalcIRQOut();
}
break;
}
}
}
if(DMACH[ch].ClockCounter > 0)
DMACH[ch].ClockCounter = 0;
}
static INLINE void RunChannel(pscpu_timestamp_t timestamp, int32 clocks, int ch)
{
// Mask out the bits that the DMA controller will modify during the course of operation.
const uint32 CRModeCache = DMACH[ch].ChanControl &~(0x11 << 24);
switch(ch)
{
default: abort();
case 0:
if(MDFN_LIKELY(CRModeCache == 0x00000201))
RunChannelI(0, 0x00000201, clocks);
else
RunChannelI(0, CRModeCache, clocks);
break;
case 1:
if(MDFN_LIKELY(CRModeCache == 0x00000200))
RunChannelI(1, 0x00000200, clocks);
else
RunChannelI(1, CRModeCache, clocks);
break;
case 2:
if(MDFN_LIKELY(CRModeCache == 0x00000401))
RunChannelI(2, 0x00000401, clocks);
else if(MDFN_LIKELY(CRModeCache == 0x00000201))
RunChannelI(2, 0x00000201, clocks);
else if(MDFN_LIKELY(CRModeCache == 0x00000200))
RunChannelI(2, 0x00000200, clocks);
else
RunChannelI(2, CRModeCache, clocks);
break;
case 3:
if(MDFN_LIKELY(CRModeCache == 0x00000000))
RunChannelI(3, 0x00000000, clocks);
else if(MDFN_LIKELY(CRModeCache == 0x00000100))
RunChannelI(3, 0x00000100, clocks);
else
RunChannelI(3, CRModeCache, clocks);
break;
case 4:
if(MDFN_LIKELY(CRModeCache == 0x00000201))
RunChannelI(4, 0x00000201, clocks);
else if(MDFN_LIKELY(CRModeCache == 0x00000200))
RunChannelI(4, 0x00000200, clocks);
else
RunChannelI(4, CRModeCache, clocks);
break;
case 5:
RunChannelI(5, CRModeCache, clocks);
break;
case 6:
if(MDFN_LIKELY(CRModeCache == 0x00000002))
RunChannelI(6, 0x00000002, clocks);
else
RunChannelI(6, CRModeCache, 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));
}
#if 0
static void CheckLinkedList(uint32 addr)
{
std::map<uint32, bool> zoom;
do
{
if(zoom[addr])
{
printf("Bad linked list: 0x%08x\n", addr);
break;
}
zoom[addr] = 1;
uint32 header = MainRAM.ReadU32(addr & 0x1FFFFC);
addr = header & 0xFFFFFF;
} while(addr != 0xFFFFFF && !(addr & 0x800000));
}
#endif
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
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);
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;
//printf("CHCR: %u, %08x --- 0x%08x\n", ch, V, DMACH[ch].BlockControl);
//
// 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].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
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 & 0x51000000) | 0x2;
else
DMACH[ch].ChanControl = V & 0x71770703;
if(!(OldCC & (1 << 24)) && (V & (1 << 24)))
{
//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].WordCounter = 0;
DMACH[ch].ClockCounter = 0;
//
// 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? ;)
//
// Also, it's needed for RecalcHalt() to work with some semblance of workiness.
//
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;
if(ch == 7)
{
switch(A & 0xC)
{
default: PSX_WARNING("[DMA] Unknown read: %08x", A);
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].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-09333/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,946 @@
/* 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 "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 unsigned EP_to_MP(bool emulate_multitap[2], unsigned ep)
{
if(!emulate_multitap[0] && emulate_multitap[1])
{
if(ep == 0 || ep >= 5)
return(0);
else
return(1);
}
else
return(ep >= 4);
}
static INLINE unsigned EP_to_SP(bool emulate_multitap[2], unsigned ep)
{
if(!emulate_multitap[0] && emulate_multitap[1])
{
if(ep == 0)
return(0);
else if(ep < 5)
return(ep - 1);
else
return(ep - 4);
}
else
return(ep & 0x3);
}
void FrontIO::MapDevicesToPorts(void)
{
if(emulate_multitap[0] && emulate_multitap[1])
{
for(unsigned i = 0; i < 2; i++)
{
Ports[i] = DevicesTap[i];
MCPorts[i] = DummyDevice;
}
}
else if(!emulate_multitap[0] && emulate_multitap[1])
{
Ports[0] = Devices[0];
MCPorts[0] = emulate_memcards[0] ? DevicesMC[0] : DummyDevice;
Ports[1] = DevicesTap[1];
MCPorts[1] = DummyDevice;
}
else if(emulate_multitap[0] && !emulate_multitap[1])
{
Ports[0] = DevicesTap[0];
MCPorts[0] = DummyDevice;
Ports[1] = Devices[4];
MCPorts[1] = emulate_memcards[4] ? DevicesMC[4] : DummyDevice;
}
else
{
for(unsigned i = 0; i < 2; i++)
{
Ports[i] = Devices[i];
MCPorts[i] = emulate_memcards[i] ? DevicesMC[i] : DummyDevice;
}
}
//printf("\n");
for(unsigned i = 0; i < 8; i++)
{
unsigned mp = EP_to_MP(emulate_multitap, i);
if(emulate_multitap[mp])
DevicesTap[mp]->SetSubDevice(EP_to_SP(emulate_multitap, i), Devices[i], emulate_memcards[i] ? DevicesMC[i] : DummyDevice);
else
DevicesTap[mp]->SetSubDevice(EP_to_SP(emulate_multitap, i), DummyDevice, DummyDevice);
//printf("%d-> multitap: %d, sub-port: %d\n", i, mp, EP_to_SP(emulate_multitap, i));
}
}
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);
}
static const uint8 ScaleShift[4] = { 0, 0, 4, 6 };
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 = std::max<uint32>(0x20, (Baudrate << ScaleShift[Mode & 0x3]) & ~1); // Minimum of 0x20 is an emulation sanity check to prevent severe performance degradation.
//printf("CD: 0x%02x\n", ClockDivider);
}
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)) )
PSX_DBG(PSX_DBG_WARNING, "FIO device selection changed during comm %04x->%04x\n", 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;
//printf("%02x\n", 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:
//printf("FIO Read: 0x%02x\n", ReceiveBuffer);
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 += std::max<uint32>(0x20, (Baudrate << ScaleShift[Mode & 0x3]) & ~1); // Minimum of 0x20 is an emulation sanity check to prevent severe performance degradation.
}
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") || !strcmp(type, "dancepad"))
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())
{
FileStream mf(path, FileStream::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())
{
FileStream mf(path, FileStream::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. Rumble is emulated, but currently only supported on Linux, and MS Windows via the XInput API and XInput-compatible gamepads/joysticks. If you're having trouble getting rumble to work on Linux, see if Mednafen is printing out error messages during startup regarding /dev/input/event*, and resolve the issue(s) as necessary.",
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,
},
{
"dancepad",
"Dance Pad",
"Dingo Dingo Rodeo!",
NULL,
sizeof(Device_Dancepad_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_Dancepad_IDII,
},
};
static const InputPortInfoStruct PortInfo[] =
{
{ "port1", "Virtual Port 1", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port2", "Virtual Port 2", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port3", "Virtual Port 3", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port4", "Virtual Port 4", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port5", "Virtual Port 5", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port6", "Virtual Port 6", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port7", "Virtual Port 7", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port8", "Virtual Port 8", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
};
InputInfoStruct FIO_InputInfo =
{
sizeof(PortInfo) / sizeof(InputPortInfoStruct),
PortInfo
};
}

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

1468
mednafen/psx-09333/gpu.cpp Normal file

File diff suppressed because it is too large Load Diff

310
mednafen/psx-09333/gpu.h Normal file
View File

@ -0,0 +1,310 @@
// 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, int sls, int sle) MDFN_COLD;
~PS_GPU() MDFN_COLD;
void Power(void) MDFN_COLD;
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();
}
void WriteDMA(uint32 V);
uint32 ReadDMA(void);
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);
uint32 ReadData(void);
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 DisplayFB_CurYOffset;
uint32 DisplayFB_CurLineYReadout;
bool InVBlank;
//
//
//
uint32 LinesPerField;
uint32 scanline;
bool field;
bool field_ram_readout;
bool PhaseChange;
uint32 DotClockCounter;
uint64 GPUClockCounter;
uint32 GPUClockRatio;
int32 LineClockCounter;
int32 LinePhase;
int32 DrawTimeAvail;
pscpu_timestamp_t lastts;
//
//
//
bool sl_zero_reached;
//
//
EmulateSpecStruct *espec;
MDFN_Surface *surface;
MDFN_Rect *DisplayRect;
MDFN_Rect *LineWidths;
bool skip;
bool HardwarePALType;
int LineVisFirst, LineVisLast;
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,235 @@
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 || FlipY || (u & 1) || (v & 1) || ((TexMode_TA == 0) && ((u & 3) || (v & 3))))
// fprintf(stderr, "Flippy: %d %d 0x%02x 0x%02x\n", FlipX, FlipY, u, v);
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;
}
}

1736
mednafen/psx-09333/gte.cpp Normal file

File diff suppressed because it is too large Load Diff

21
mednafen/psx-09333/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 @@
# dummy

View File

@ -0,0 +1 @@
# dummy

View File

@ -0,0 +1 @@
# dummy

View File

@ -0,0 +1 @@
# dummy

View File

@ -0,0 +1 @@
# dummy

View File

@ -0,0 +1 @@
# dummy

View File

@ -0,0 +1 @@
# dummy

View File

@ -0,0 +1 @@
# dummy

View File

@ -0,0 +1 @@
# dummy

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,240 @@
#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)
{
//printf("PAD COmmand 0x42, sl=%u\n", GPU->GetScanlineNum());
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 },
};
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

@ -0,0 +1,12 @@
#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];
extern InputDeviceInputInfoStruct Device_Dancepad_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 = 16; // Not 16 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 = 16; // Not 16 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 - 177;
}
}
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,397 @@
/* 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 "multitap.h"
/*
TODO: PS1 multitap appears to have some internal knowledge of controller IDs, so it won't get "stuck" waiting for data from a controller that'll never
come. We currently sort of "cheat" due to how the dsr_pulse_delay stuff works, but in the future we should try to emulate this multitap functionality.
Also, full-mode read startup and subport controller ID read timing isn't quite right, so we should fix that too.
*/
/*
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, 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;
fm_dp = 0;
memset(fm_buffer, 0, sizeof(fm_buffer));
fm_deferred_error_temp = false;
fm_deferred_error = false;
fm_command_error = 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)
{
if(old_dtr)
{
//printf("Multitap stop.\n");
}
bit_counter = 0;
receive_buffer = 0;
selected_device = -1;
mc_mode = false;
full_mode = false;
}
if(!old_dtr && dtr)
{
full_mode = full_mode_setting;
byte_counter = 0;
//if(full_mode)
// printf("Multitap start: %d\n", full_mode);
}
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;
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)
{
if(byte_counter == 0)
{
bool mangled_txd = TxD;
if(bit_counter < 4)
mangled_txd = (0x01 >> bit_counter) & 1;
for(unsigned i = 0; i < 4; i++)
{
pad_devices[i]->Clock(mangled_txd, tmp_pulse_delay[0][i]);
mc_devices[i]->Clock(mangled_txd, tmp_pulse_delay[1][i]);
}
}
else
{
if(full_mode)
{
if(byte_counter == 1)
{
ret = (0x80 >> bit_counter) & 1;
for(unsigned i = 0; i < 4; i++)
{
fm_buffer[i][0] &= (pad_devices[i]->Clock(TxD, tmp_pulse_delay[0][i]) << bit_counter) | (~(1U << bit_counter));
}
}
else if(byte_counter == 2)
{
ret = (0x5A >> bit_counter) & 1;
}
// || byte_counter == (0x03 + 0x08 * 1) || byte_counter == (0x03 + 0x08 * 2) || byte_counter == (0x03 + 0x08 * 3))
else if(byte_counter >= 0x03 && byte_counter < 0x03 + 0x08 * 4)
{
if(!fm_command_error && byte_counter >= (0x03 + 1) && byte_counter < (0x03 + 0x08))
{
for(unsigned i = 0; i < 4; i++)
{
fm_buffer[i][byte_counter - 0x03] &= (pad_devices[i]->Clock(0, tmp_pulse_delay[0][i]) << bit_counter) | (~(1U << bit_counter));
}
}
ret &= ((&fm_buffer[0][0])[byte_counter - 0x03] >> bit_counter) & 1;
}
}
else // to if(full_mode)
{
if((unsigned)selected_device < 4)
{
ret &= pad_devices[selected_device]->Clock(TxD, tmp_pulse_delay[0][selected_device]);
ret &= mc_devices[selected_device]->Clock(TxD, tmp_pulse_delay[1][selected_device]);
}
}
} // end else to if(byte_counter == 0)
}
//
//
//
bit_counter = (bit_counter + 1) & 0x7;
if(bit_counter == 0)
{
//printf("Receive: 0x%02x\n", receive_buffer);
if(byte_counter == 0)
{
mc_mode = (bool)(receive_buffer & 0xF0);
if(mc_mode)
full_mode = false;
//printf("Zoomba: 0x%02x\n", receive_buffer);
//printf("Full mode: %d %d %d\n", full_mode, bit_counter, byte_counter);
if(full_mode)
{
memset(fm_buffer, 0xFF, sizeof(fm_buffer));
selected_device = 0;
}
else
{
//printf("Device select: %02x\n", receive_buffer);
fm_deferred_error = false;
selected_device = ((receive_buffer & 0xF) - 1) & 0xFF;
}
}
if(byte_counter == 1)
{
command = receive_buffer;
//printf("Multitap sub-command: %02x\n", command);
if(full_mode)
{
if(command != 0x42)
fm_command_error = true;
else
fm_command_error = fm_deferred_error;
}
else
{
fm_command_error = false;
}
fm_deferred_error = false;
}
if((!mc_mode || full_mode) && byte_counter == 2)
{
//printf("Full mode setting: %02x\n", receive_buffer);
full_mode_setting = receive_buffer & 0x01;
}
if(full_mode)
{
if(byte_counter == (3 + 8 * 0) || byte_counter == (3 + 8 * 1) || byte_counter == (3 + 8 * 2) || byte_counter == (3 + 8 * 3))
{
unsigned index = (byte_counter - 3) >> 3;
assert(index < 4);
if(index == 0)
fm_deferred_error_temp = false;
if((fm_dp & (1U << index)) && receive_buffer != 0x42)
{
//printf("Multitap command check failed: %u, 0x%02x\n", byte_counter, receive_buffer);
fm_deferred_error_temp = true;
}
}
if(byte_counter == 33)
fm_deferred_error = fm_deferred_error_temp;
}
// Handle DSR stuff
if(full_mode)
{
if(byte_counter == 0) // Next byte: 0x80
{
dsr_pulse_delay = 1000;
fm_dp = 0;
for(unsigned i = 0; i < 4; i++)
fm_dp |= (((bool)(tmp_pulse_delay[0][i])) << i);
}
else if(byte_counter == 1) // Next byte: 0x5A
dsr_pulse_delay = 0x40;
else if(byte_counter == 2) // Next byte(typically, controller-dependent): 0x41
{
if(fm_dp)
dsr_pulse_delay = 0x40;
else
dsr_pulse_delay = 0;
}
else if(byte_counter >= 3 && byte_counter < 34) // Next byte when byte_counter==3 (typically, controller-dependent): 0x5A
{
if(byte_counter < 10)
{
int d = 0x40;
for(unsigned i = 0; i < 4; i++)
if(tmp_pulse_delay[0][i] > d)
d = tmp_pulse_delay[0][i];
dsr_pulse_delay = d;
}
else
dsr_pulse_delay = 0x20;
if(byte_counter == 3 && fm_command_error)
dsr_pulse_delay = 0;
}
} // end if(full_mode)
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++;
}
return(ret);
}
}

View File

@ -0,0 +1,52 @@
#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 fm_dp; // Device-present.
uint8 fm_buffer[4][8];
bool fm_deferred_error_temp;
bool fm_deferred_error;
bool fm_command_error;
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-09333/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-09333/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_VBLANK = 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

741
mednafen/psx-09333/mdec.cpp Normal file
View File

@ -0,0 +1,741 @@
/* 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 int16 block_y[2][2][8][8];
static int16 block_cb[8][8]; // [y >> 1][x >> 1]
static int16 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, 0x08, 0x01, 0x02, 0x09, 0x10, 0x18, 0x11,
0x0a, 0x03, 0x04, 0x0b, 0x12, 0x19, 0x20, 0x28,
0x21, 0x1a, 0x13, 0x0c, 0x05, 0x06, 0x0d, 0x14,
0x1b, 0x22, 0x29, 0x30, 0x38, 0x31, 0x2a, 0x23,
0x1c, 0x15, 0x0e, 0x07, 0x0f, 0x16, 0x1d, 0x24,
0x2b, 0x32, 0x39, 0x3a, 0x33, 0x2c, 0x25, 0x1e,
0x17, 0x1f, 0x26, 0x2d, 0x34, 0x3b, 0x3c, 0x35,
0x2e, 0x27, 0x2f, 0x36, 0x3d, 0x3e, 0x37, 0x3f,
};
void MDEC_Power(void)
{
#if 0
for(int i = 0; i < 64; i++)
{
int d = ((ZigZag[i] & 0x7) << 3) | ((ZigZag[i] >> 3) & 0x7);
printf("0x%02x, ", d);
if((i & 0x7) == 7)
printf("\n");
}
#endif
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),
SFARRAY16(&block_y[0][0][0][0], sizeof(block_y) / sizeof(block_y[0][0][0][0])),
SFARRAY16(&block_cb[0][0], sizeof(block_cb) / sizeof(block_cb[0][0])),
SFARRAY16(&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 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;
{
int q = QMatrix[qmw][0]; // No QScale here!
int ci = sign_10_to_s16(V & 0x3FF);
int tmp;
if(q != 0)
tmp = ((ci * q) << 4) + (ci ? ((ci < 0) ? 8 : -8) : 0);
else
tmp = (ci * 2) << 4;
// Not sure if it should be 0x3FFF or 0x3FF0 or maybe 0x3FF8?
Coeff[DecodeWB][ZigZag[0]] = std::min<int>(0x3FFF, std::max<int>(-0x4000, tmp));
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)
{
int q = QScale * QMatrix[qmw][CoeffIndex];
int ci = sign_10_to_s16(V & 0x3FF);
int tmp;
if(q != 0)
tmp = (((ci * q) >> 3) << 4) + (ci ? ((ci < 0) ? 8 : -8) : 0);
else
tmp = (ci * 2) << 4;
// Not sure if it should be 0x3FFF or 0x3FF0 or maybe 0x3FF8?
Coeff[DecodeWB][ZigZag[CoeffIndex]] = std::min<int>(0x3FFF, std::max<int>(-0x4000, tmp));
CoeffIndex++;
}
}
}
if(CoeffIndex == 64 && BlockEnd)
{
BlockEnd = false;
CoeffIndex = 0;
//printf("Block %d finished\n", DecodeWB);
DecodeWB++;
if(DecodeWB == (((Command >> 27) & 2) ? 6 : 3))
{
DecodeWB = 0;
DecodeImage();
}
}
}
template<bool phase>
static void IDCT_1D_Multi(int16 *in_coeff, int16 *out_coeff)
{
#if defined(__SSE2__)
{
for(unsigned col = 0; col < 8; col++)
{
__m128i c = _mm_load_si128((__m128i *)&in_coeff[(col * 8)]);
for(unsigned x = 0; x < 8; x++)
{
__m128i sum;
__m128i m;
int32 tmp[4] MDFN_ALIGN(16);
m = _mm_load_si128((__m128i *)&IDCTMatrix[(x * 8)]);
sum = _mm_madd_epi16(m, c);
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)));
//_mm_store_ss((float *)&tmp[0], (__m128)sum);
_mm_store_si128((__m128i*)tmp, sum);
if(phase)
out_coeff[(col * 8) + x] = (tmp[0] + 0x4000) >> 15;
else
out_coeff[(x * 8) + col] = (tmp[0] + 0x4000) >> 15;
}
}
}
#else
for(unsigned col = 0; col < 8; col++)
{
for(unsigned x = 0; x < 8; x++)
{
int32 sum = 0;
for(unsigned u = 0; u < 8; u++)
{
sum += (in_coeff[(col * 8) + u] * IDCTMatrix[(x * 8) + u]);
}
if(phase)
out_coeff[(col * 8) + x] = (sum + 0x4000) >> 15;
else
out_coeff[(x * 8) + col] = (sum + 0x4000) >> 15;
}
}
#endif
}
static void IDCT(int16 *in_coeff, int16 *out_coeff) NO_INLINE;
static void IDCT(int16 *in_coeff, int16 *out_coeff)
{
int16 tmpbuf[64] MDFN_ALIGN(16);
IDCT_1D_Multi<0>(in_coeff, tmpbuf);
IDCT_1D_Multi<1>(tmpbuf, out_coeff);
}
static void YCbCr_to_RGB(const int32 y, const int32 cb, const int32 cr, uint8 &r, uint8 &g, uint8 &b)
{
int rt = (y + 128) + ((91881 * cr) >> 16);
int gt = (y + 128) - ((22525 * cb) >> 16) - ((46812 * cr) >> 16);
int bt = (y + 128) + ((116130 * cb) >> 16);
r = std::max<int>(std::min<int>(rt, 255), 0);
g = std::max<int>(std::min<int>(gt, 255), 0);
b = std::max<int>(std::min<int>(bt, 255), 0);
}
static void DecodeImage(void)
{
//puts("DECODE");
if((Command >> 27) & 0x2)
{
run_time -= 2048;
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]);
}
else
{
run_time -= 341;
IDCT(Coeff[2], &block_y[0][0][0][0]);
}
block_ready = true;
}
static void EncodeImage(void)
{
//printf("ENCODE, %d\n", (Command & 0x08000000) ? 256 : 384);
block_ready = false;
switch((Command >> 27) & 0x3)
{
case 0: // 4bpp, TODO
break;
case 1: // 8bpp
{
uint8 us_xor = (Command & (1U << 26)) ? 0x00 : 0x80;
for(int y = 0; y < 8; y++)
{
uint32 qb = 0;
for(int x = 0; x < 8; x++)
{
int yv = block_y[0][0][y][x];
if(yv < -128)
yv = -128;
if(yv > 127)
yv = 127;
qb |= ((uint8)yv ^ us_xor) << ((x & 1) * 8);
if((x & 1) == 1)
{
if(OutBuffer.CanWrite())
OutBuffer.WriteUnit(qb);
qb = 0;
}
#if 0
qb |= yv << ((x & 3) * 8);
if((x & 3) == 3)
{
if(OutBuffer.CanWrite())
{
printf("0x%08x\n", qb);
OutBuffer.WriteUnit(qb);
}
qb = 0;
}
#endif
}
}
}
break;
case 2: // 24bpp
{
uint8 output[16][16][3]; // [y][x][cc]
for(int y = 0; y < 16; y++)
{
for(int x = 0; x < 16; x++)
{
uint8 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);
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));
}
}
break;
case 3: // 16bpp
{
uint16 pixel_or = (Command & 0x02000000) ? 0x8000 : 0x0000;
for(int y = 0; y < 16; y++)
{
for(int x = 0; x < 16; x++)
{
uint8 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));
}
}
}
break;
}
}
void MDEC_DMAWrite(uint32 V)
{
if(InCounter > 0)
{
InCounter--;
switch((Command >> 29) & 0x7)
{
case 1:
for(int vi = 0; vi < 2; vi++)
{
if(InputBuffer.CanWrite())
InputBuffer.WriteUnit(V);
V >>= 16;
}
break;
case 2:
for(int i = 0; i < 4; i++)
{
QMatrix[QMIndex >> 6][QMIndex & 0x3F] = (uint8)V;
QMIndex = (QMIndex + 1) & 0x7F;
V >>= 8;
}
break;
case 3:
for(unsigned i = 0; i < 2; i++)
{
IDCTMatrix[((IDCTMIndex & 0x7) << 3) | ((IDCTMIndex >> 3) & 0x7)] = (int16)(V & 0xFFFF) >> 3;
IDCTMIndex = (IDCTMIndex + 1) & 0x3F;
V >>= 16;
}
break;
default:
PSX_DBG(PSX_DBG_WARNING, "MYSTERY1: %08x\n", V);
break;
}
}
}
uint32 MDEC_DMARead(void)
{
uint32 V = 0;
if(((Command >> 29) & 0x7) == 0x1 && OutBuffer.CanRead() >= 2)
{
V = OutBuffer.ReadUnit() | (OutBuffer.ReadUnit() << 16);
}
else
{
PSX_DBG(PSX_DBG_WARNING, "[MDEC] BONUS GNOMES\n");
V = rand();
}
return(V);
}
// Test case related to this: GameShark Version 4.0 intro movie(coupled with (clever) abuse of DMA channel 0).
// also: SimCity 2000 startup.
bool MDEC_DMACanWrite(void)
{
return(InCounter > 0 && ((Command >> 29) & 0x7) >= 1 && ((Command >> 29) & 0x7) <= 3);
}
bool MDEC_DMACanRead(void)
{
return(OutBuffer.CanRead() >= 2);
}
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?
{
Command = 0;
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;
switch((Command >> 29) & 0x7)
{
case 1:
InputBuffer.Flush();
OutBuffer.Flush();
block_ready = false;
BlockEnd = false;
CoeffIndex = 0;
if((Command >> 27) & 2)
DecodeWB = 0;
else
DecodeWB = 2;
InCounter = V & 0xFFFF;
break;
case 2:
QMIndex = 0;
InCounter = 0x10 + ((Command & 0x1) ? 0x10 : 0x00);
break;
case 3:
IDCTMIndex = 0;
InCounter = 0x20;
break;
default:
InCounter = V & 0xFFFF;
break;
}
}
}
uint32 MDEC_Read(const pscpu_timestamp_t timestamp, uint32 A)
{
uint32 ret = 0;
if(A & 4)
{
ret = 0;
if(InputBuffer.CanRead())
ret |= 0x20000000;
ret |= ((Command >> 25) & 0xF) << 23;
}
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;
}
#if 0
// Maybe we should just use libco....
#define MDEC_WRITE_FIFO(n) case __COUNTER__: if(!InFIFO.CanRead()) { MDRPhase = __COUNTER__ - 1; return; } OutFIFO.Write(n);
#define MDEC_READ_FIFO(n) case __COUNTER__: if(!InFIFO.CanRead()) { MDRPhase = __COUNTER__ - 1; return; } n = InFIFO.Read();
#define MDEC_EAT_CLOCKS(n) ClockCounter -= clocks; case __COUNTER__: if(ClockCounter <= 0) { MDRPhase = __COUNTER__ - 1; return; }
void MDEC_Run2(int32 clocks)
{
ClockCounter += clocks;
if(ClockCounter > 128)
ClockCounter = 128;
switch(MDRPhase)
{
MDEC_READ_FIFO(Command);
//
//
//
if(((Command >> 29) & 0x7) == 1)
{
InCounter = Command & 0xFFFF;
OutBuffer.Flush();
block_ready = false;
BlockEnd = false;
CoeffIndex = 0;
if((Command >> 27) & 2)
DecodeWB = 0;
else
DecodeWB = 2;
InCounter--;
while(InCounter != 0xFFFF)
{
uint32 tfr;
bool need_encode;
MDEC_READ_FIFO(tfr);
need_encode = WriteImageData(tfr);
need_encode |= WriteImageData(tfr >> 16);
if(need_encode)
{
}
}
}
//
//
//
else if(((Command >> 29) & 0x7) == 2)
{
QMIndex = 0;
InCounter = 0x10 + ((Command & 0x1) ? 0x10 : 0x00);
InCounter--;
while(InCounter != 0xFFFF)
{
uint32 tfr;
MDEC_READ_FIFO(tfr);
for(int i = 0; i < 4; i++)
{
QMatrix[QMIndex >> 6][QMIndex & 0x3F] = (uint8)tfr;
QMIndex = (QMIndex + 1) & 0x7F;
tfr >>= 8;
}
}
}
//
//
//
else if(((Command >> 29) & 0x7) == 3)
{
IDCTMIndex = 0;
InCounter = 0x20;
InCounter--;
while(InCounter != 0xFFFF)
{
uint32 tfr;
MDEC_READ_FIFO(tfr);
for(unsigned i = 0; i < 2; i++)
{
int tmp = (int16)(tfr & 0xFFFF) >> 3;
IDCTMatrix[((IDCTMIndex & 0x7) << 3) | ((IDCTMIndex >> 3) & 0x7)] = (int16)(V & 0xFFFF) >> 3;
IDCTMIndex = (IDCTMIndex + 1) & 0x3F;
tfr >>= 16;
}
}
}
else
{
InCounter = Command & 0xFFFF;
}
}
}
#endif
}

24
mednafen/psx-09333/mdec.h Normal file
View File

@ -0,0 +1,24 @@
#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_DMACanWrite(void);
bool MDEC_DMACanRead(void);
void MDEC_Run(int32 clocks);
int MDEC_StateAction(StateMem *sm, int load, int data_only);
}
#endif

2401
mednafen/psx-09333/psx.cpp Normal file

File diff suppressed because it is too large Load Diff

118
mednafen/psx-09333/psx.h Normal file
View File

@ -0,0 +1,118 @@
#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 "../FileStream.h"
//
// Comment out these 2 defines for extra speeeeed.
//
#define PSX_DBGPRINT_ENABLE 1
#define PSX_EVENT_SYSTEM_CHECKS 1
//
// It's highly unlikely the user will want these if they're intentionally compiling without the debugger.
#ifndef WANT_DEBUGGER
#undef PSX_DBGPRINT_ENABLE
#undef PSX_EVENT_SYSTEM_CHECKS
#endif
//
//
//
namespace MDFN_IEN_PSX
{
#define PSX_DBG_ERROR 0 // Emulator-level error.
#define PSX_DBG_WARNING 1 // Warning about game doing questionable things/hitting stuff that might not be emulated correctly.
#define PSX_DBG_BIOS_PRINT 2 // BIOS printf/putchar output.
#define PSX_DBG_SPARSE 3 // Sparse(relatively) information debug messages(CDC commands).
#define PSX_DBG_FLOOD 4 // Heavy informational debug messages(GPU commands; TODO).
#if PSX_DBGPRINT_ENABLE
void PSX_DBG(unsigned level, const char *format, ...) throw() MDFN_COLD MDFN_FORMATSTR(printf, 2, 3);
#define PSX_WARNING(format, ...) { PSX_DBG(PSX_DBG_WARNING, format "\n", ## __VA_ARGS__); }
#define PSX_DBGINFO(format, ...) { }
#else
static INLINE void PSX_DBG(unsigned level, const char* format, ...) { }
static INLINE void PSX_WARNING(const char* format, ...) { }
static INLINE void PSX_DBGINFO(const char* format, ...) { }
#endif
typedef int32 pscpu_timestamp_t;
bool MDFN_FASTCALL PSX_EventHandler(const pscpu_timestamp_t timestamp);
void MDFN_FASTCALL PSX_MemWrite8(pscpu_timestamp_t timestamp, uint32 A, uint32 V);
void MDFN_FASTCALL PSX_MemWrite16(pscpu_timestamp_t timestamp, uint32 A, uint32 V);
void MDFN_FASTCALL PSX_MemWrite24(pscpu_timestamp_t timestamp, uint32 A, uint32 V);
void MDFN_FASTCALL PSX_MemWrite32(pscpu_timestamp_t timestamp, uint32 A, uint32 V);
uint8 MDFN_FASTCALL PSX_MemRead8(pscpu_timestamp_t &timestamp, uint32 A);
uint16 MDFN_FASTCALL PSX_MemRead16(pscpu_timestamp_t &timestamp, uint32 A);
uint32 MDFN_FASTCALL PSX_MemRead24(pscpu_timestamp_t &timestamp, uint32 A);
uint32 MDFN_FASTCALL PSX_MemRead32(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);
void ForceEventUpdates(const pscpu_timestamp_t timestamp);
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);
uint32 PSX_GetRandU32(uint32 mina, uint32 maxa);
};
#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-09333/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-09333/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

1478
mednafen/psx-09333/spu.cpp Normal file

File diff suppressed because it is too large Load Diff

331
mednafen/psx-09333/spu.h Normal file
View File

@ -0,0 +1,331 @@
#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);
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;
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 two(worst-case scenario) video frames(2* ~735 frames NTSC, 2* ~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];
}

View File

@ -0,0 +1,520 @@
/* 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(when mode is | 0x100):
0x1 = don't count while in vblank(except that the first count while in vblank does go through)
0x3 = vblank going inactive triggers timer reset, then some interesting behavior where counting again is delayed...
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).
Jan. 15, 2013 Note:
Counters using GPU clock sources(hretrace,dot clock) reportedly will with a low probability return wrong count values on an actual PS1, so keep this in mind
when writing test programs(IE keep reading the count value until two consecutive reads return the same value).
*/
/*
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
{
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)
{
PSX_DBG(PSX_DBG_ERROR, "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)
PSX_WARNING("Timer %d IRQ trigger error: %d", 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;
V <<= (A & 3) * 8;
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;
case 0xC: // Open bus
break;
}
// 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;
if(which >= 3)
{
PSX_WARNING("[TIMER] Open Bus Read: 0x%08x", A);
return(ret >> ((A & 3) * 8));
}
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;
case 0xC: PSX_WARNING("[TIMER] Open Bus Read: 0x%08x", A);
break;
}
return(ret >> ((A & 3) * 8));
}
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;
}
}
}

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