mirror of
https://github.com/libretro/beetle-pce-fast-libretro.git
synced 2024-11-23 07:50:03 +00:00
(Mednafen PSX) Update to version 0.9.33.3
This commit is contained in:
parent
33d93a7229
commit
c4267b048b
3
Makefile
3
Makefile
@ -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 \
|
||||
|
@ -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
701
mednafen/psx-09333/Makefile
Normal 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:
|
12
mednafen/psx-09333/Makefile.am
Normal file
12
mednafen/psx-09333/Makefile.am
Normal 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
|
701
mednafen/psx-09333/Makefile.in
Normal file
701
mednafen/psx-09333/Makefile.in
Normal 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
3
mednafen/psx-09333/NOTES
Normal 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
173
mednafen/psx-09333/PSX-TODO
Normal 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).
|
38
mednafen/psx-09333/SOURCES
Normal file
38
mednafen/psx-09333/SOURCES
Normal 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
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
275
mednafen/psx-09333/cdc.h
Normal 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
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
254
mednafen/psx-09333/cpu.h
Normal 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 ×tamp, uint32 address, bool DS24 = false, bool LWC_timing = false);
|
||||
template<typename T> void WriteMemory(pscpu_timestamp_t ×tamp, 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
|
687
mednafen/psx-09333/debug.cpp
Normal file
687
mednafen/psx-09333/debug.cpp
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
21
mednafen/psx-09333/debug.h
Normal file
21
mednafen/psx-09333/debug.h
Normal 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
408
mednafen/psx-09333/dis.cpp
Normal 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
11
mednafen/psx-09333/dis.h
Normal 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
821
mednafen/psx-09333/dma.cpp
Normal 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
24
mednafen/psx-09333/dma.h
Normal 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
|
946
mednafen/psx-09333/frontio.cpp
Normal file
946
mednafen/psx-09333/frontio.cpp
Normal 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
|
||||
};
|
||||
|
||||
|
||||
}
|
142
mednafen/psx-09333/frontio.h
Normal file
142
mednafen/psx-09333/frontio.h
Normal 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
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
310
mednafen/psx-09333/gpu.h
Normal 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
|
195
mednafen/psx-09333/gpu_command_table.inc
Normal file
195
mednafen/psx-09333/gpu_command_table.inc
Normal 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(),
|
||||
|
249
mednafen/psx-09333/gpu_line.inc
Normal file
249
mednafen/psx-09333/gpu_line.inc
Normal 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);
|
||||
}
|
||||
|
489
mednafen/psx-09333/gpu_polygon.inc
Normal file
489
mednafen/psx-09333/gpu_polygon.inc
Normal 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);
|
||||
}
|
||||
|
235
mednafen/psx-09333/gpu_sprite.inc
Normal file
235
mednafen/psx-09333/gpu_sprite.inc
Normal 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
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
21
mednafen/psx-09333/gte.h
Normal 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
|
32768
mednafen/psx-09333/gte_divrecip.inc
Normal file
32768
mednafen/psx-09333/gte_divrecip.inc
Normal file
File diff suppressed because it is too large
Load Diff
1
mednafen/psx-09333/input/.deps/dualanalog.Po
Normal file
1
mednafen/psx-09333/input/.deps/dualanalog.Po
Normal file
@ -0,0 +1 @@
|
||||
# dummy
|
1
mednafen/psx-09333/input/.deps/dualshock.Po
Normal file
1
mednafen/psx-09333/input/.deps/dualshock.Po
Normal file
@ -0,0 +1 @@
|
||||
# dummy
|
1
mednafen/psx-09333/input/.deps/gamepad.Po
Normal file
1
mednafen/psx-09333/input/.deps/gamepad.Po
Normal file
@ -0,0 +1 @@
|
||||
# dummy
|
1
mednafen/psx-09333/input/.deps/guncon.Po
Normal file
1
mednafen/psx-09333/input/.deps/guncon.Po
Normal file
@ -0,0 +1 @@
|
||||
# dummy
|
1
mednafen/psx-09333/input/.deps/justifier.Po
Normal file
1
mednafen/psx-09333/input/.deps/justifier.Po
Normal file
@ -0,0 +1 @@
|
||||
# dummy
|
1
mednafen/psx-09333/input/.deps/memcard.Po
Normal file
1
mednafen/psx-09333/input/.deps/memcard.Po
Normal file
@ -0,0 +1 @@
|
||||
# dummy
|
1
mednafen/psx-09333/input/.deps/mouse.Po
Normal file
1
mednafen/psx-09333/input/.deps/mouse.Po
Normal file
@ -0,0 +1 @@
|
||||
# dummy
|
1
mednafen/psx-09333/input/.deps/multitap.Po
Normal file
1
mednafen/psx-09333/input/.deps/multitap.Po
Normal file
@ -0,0 +1 @@
|
||||
# dummy
|
1
mednafen/psx-09333/input/.deps/negcon.Po
Normal file
1
mednafen/psx-09333/input/.deps/negcon.Po
Normal file
@ -0,0 +1 @@
|
||||
# dummy
|
285
mednafen/psx-09333/input/dualanalog.cpp
Normal file
285
mednafen/psx-09333/input/dualanalog.cpp
Normal 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 },
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
11
mednafen/psx-09333/input/dualanalog.h
Normal file
11
mednafen/psx-09333/input/dualanalog.h
Normal 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
|
1051
mednafen/psx-09333/input/dualshock.cpp
Normal file
1051
mednafen/psx-09333/input/dualshock.cpp
Normal file
File diff suppressed because it is too large
Load Diff
11
mednafen/psx-09333/input/dualshock.h
Normal file
11
mednafen/psx-09333/input/dualshock.h
Normal 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
|
240
mednafen/psx-09333/input/gamepad.cpp
Normal file
240
mednafen/psx-09333/input/gamepad.cpp
Normal 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 },
|
||||
};
|
||||
|
||||
|
||||
}
|
12
mednafen/psx-09333/input/gamepad.h
Normal file
12
mednafen/psx-09333/input/gamepad.h
Normal 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
|
396
mednafen/psx-09333/input/guncon.cpp
Normal file
396
mednafen/psx-09333/input/guncon.cpp
Normal 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.
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
11
mednafen/psx-09333/input/guncon.h
Normal file
11
mednafen/psx-09333/input/guncon.h
Normal 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
|
393
mednafen/psx-09333/input/justifier.cpp
Normal file
393
mednafen/psx-09333/input/justifier.cpp
Normal 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 },
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
11
mednafen/psx-09333/input/justifier.h
Normal file
11
mednafen/psx-09333/input/justifier.h
Normal 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
|
448
mednafen/psx-09333/input/memcard.cpp
Normal file
448
mednafen/psx-09333/input/memcard.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
11
mednafen/psx-09333/input/memcard.h
Normal file
11
mednafen/psx-09333/input/memcard.h
Normal 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
|
252
mednafen/psx-09333/input/mouse.cpp
Normal file
252
mednafen/psx-09333/input/mouse.cpp
Normal 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 },
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
11
mednafen/psx-09333/input/mouse.h
Normal file
11
mednafen/psx-09333/input/mouse.h
Normal 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
|
397
mednafen/psx-09333/input/multitap.cpp
Normal file
397
mednafen/psx-09333/input/multitap.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
52
mednafen/psx-09333/input/multitap.h
Normal file
52
mednafen/psx-09333/input/multitap.h
Normal 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
|
259
mednafen/psx-09333/input/negcon.cpp
Normal file
259
mednafen/psx-09333/input/negcon.cpp
Normal 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 },
|
||||
};
|
||||
|
||||
}
|
9
mednafen/psx-09333/input/negcon.h
Normal file
9
mednafen/psx-09333/input/negcon.h
Normal 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
174
mednafen/psx-09333/irq.cpp
Normal 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
43
mednafen/psx-09333/irq.h
Normal 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
741
mednafen/psx-09333/mdec.cpp
Normal 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
24
mednafen/psx-09333/mdec.h
Normal 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
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
118
mednafen/psx-09333/psx.h
Normal 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 ×tamp, uint32 A);
|
||||
uint16 MDFN_FASTCALL PSX_MemRead16(pscpu_timestamp_t ×tamp, uint32 A);
|
||||
uint32 MDFN_FASTCALL PSX_MemRead24(pscpu_timestamp_t ×tamp, uint32 A);
|
||||
uint32 MDFN_FASTCALL PSX_MemRead32(pscpu_timestamp_t ×tamp, 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
106
mednafen/psx-09333/sio.cpp
Normal 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
13
mednafen/psx-09333/sio.h
Normal 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
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
331
mednafen/psx-09333/spu.h
Normal 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
|
256
mednafen/psx-09333/spu_fir_table.inc
Normal file
256
mednafen/psx-09333/spu_fir_table.inc
Normal 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 },
|
64
mednafen/psx-09333/spu_nft.inc
Normal file
64
mednafen/psx-09333/spu_nft.inc
Normal 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,
|
237
mednafen/psx-09333/spu_reverb.inc
Normal file
237
mednafen/psx-09333/spu_reverb.inc
Normal 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];
|
||||
}
|
||||
|
520
mednafen/psx-09333/timer.cpp
Normal file
520
mednafen/psx-09333/timer.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
42
mednafen/psx-09333/timer.h
Normal file
42
mednafen/psx-09333/timer.h
Normal 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
|
Loading…
Reference in New Issue
Block a user