diff options
Diffstat (limited to 'plugins/sid/sidplay-libs/libsidplay/src/mos6510')
10 files changed, 4820 insertions, 0 deletions
diff --git a/plugins/sid/sidplay-libs/libsidplay/src/mos6510/Makefile.am b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/Makefile.am new file mode 100644 index 00000000..27acc569 --- /dev/null +++ b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/Makefile.am @@ -0,0 +1,9 @@ + +EXTRA_DIST = cycle_based + +noinst_LTLIBRARIES = libmos6510.la + +libmos6510_la_SOURCES = mos6510.cpp mos6510.h conf6510.h opcodes.h + +# Remove bad default includes +DEFAULT_INCLUDES= diff --git a/plugins/sid/sidplay-libs/libsidplay/src/mos6510/Makefile.in b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/Makefile.in new file mode 100644 index 00000000..9af93a74 --- /dev/null +++ b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/Makefile.in @@ -0,0 +1,426 @@ +# Makefile.in generated by automake 1.7.1 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# 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@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +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 = : +host_triplet = @host@ +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBVERSION = @LIBVERSION@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SID_HAVE_BOOL = @SID_HAVE_BOOL@ +SID_HAVE_STDBOOL_H = @SID_HAVE_STDBOOL_H@ +SID_SIZEOF_CHAR = @SID_SIZEOF_CHAR@ +SID_SIZEOF_INT = @SID_SIZEOF_INT@ +SID_SIZEOF_LONG_INT = @SID_SIZEOF_LONG_INT@ +SID_SIZEOF_SHORT_INT = @SID_SIZEOF_SHORT_INT@ +SID_WORDS_ENDIANESS = @SID_WORDS_ENDIANESS@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builders = @builders@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ + +EXTRA_DIST = cycle_based + +noinst_LTLIBRARIES = libmos6510.la + +libmos6510_la_SOURCES = mos6510.cpp mos6510.h conf6510.h opcodes.h + +# Remove bad default includes +DEFAULT_INCLUDES = +subdir = src/mos6510 +mkinstalldirs = $(SHELL) $(top_srcdir)/unix/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/unix/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libmos6510_la_LDFLAGS = +libmos6510_la_LIBADD = +am_libmos6510_la_OBJECTS = mos6510.lo +libmos6510_la_OBJECTS = $(am_libmos6510_la_OBJECTS) +depcomp = $(SHELL) $(top_srcdir)/unix/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/mos6510.Plo +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \ + $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libmos6510_la_SOURCES) +DIST_COMMON = Makefile.am Makefile.in +SOURCES = $(libmos6510_la_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/mos6510/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libmos6510.la: $(libmos6510_la_OBJECTS) $(libmos6510_la_DEPENDENCIES) + $(CXXLINK) $(libmos6510_la_LDFLAGS) $(libmos6510_la_OBJECTS) $(libmos6510_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mos6510.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \ +@am__fastdepCXX_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + 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; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + 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; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$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 $(LTLIBRARIES) + +installdirs: + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +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: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am info \ + info-am install install-am install-data install-data-am \ + install-exec install-exec-am install-info install-info-am \ + install-man 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 uninstall-info-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: diff --git a/plugins/sid/sidplay-libs/libsidplay/src/mos6510/conf6510.h b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/conf6510.h new file mode 100644 index 00000000..6a1ea0bd --- /dev/null +++ b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/conf6510.h @@ -0,0 +1,45 @@ +/*************************************************************************** + config.h - description + ------------------- + begin : Thu May 11 2000 + copyright : (C) 2000 by Simon White + email : s_a_white@email.com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +/*************************************************************************** + * $Log: conf6510.h,v $ + * Revision 1.3 2001/03/19 23:41:51 s_a_white + * Better support for global debug. + * + * Revision 1.2 2000/12/11 19:03:16 s_a_white + * AC99 Update. + * + ***************************************************************************/ + +#ifndef _conf6510_h_ +#define _conf6510_h_ + +#include "sidconfig.h" + +#define MOS6510_CYCLE_BASED +#define MOS6510_ACCURATE_CYCLES +#define MOS6510_SIDPLAY +//#define MOS6510_STATE_6510 +//#define MOS6510_DEBUG 1 + +// Support global debug option +#ifdef DEBUG +# ifndef MOS6510_DEBUG +# define MOS6510_DEBUG DEBUG +# endif +#endif + +#endif // _conf6510_h_ diff --git a/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/mos6510c.h b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/mos6510c.h new file mode 100644 index 00000000..9a046d2e --- /dev/null +++ b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/mos6510c.h @@ -0,0 +1,311 @@ +/*************************************************************************** + mos6510c.h - Cycle Accurate 6510 Emulation + ------------------- + begin : Thu May 11 2000 + copyright : (C) 2000 by Simon White + email : s_a_white@email.com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +/*************************************************************************** + * $Log: mos6510c.h,v $ + * Revision 1.15 2002/11/28 20:35:06 s_a_white + * Reduced number of thrown exceptions when dma occurs. + * + * Revision 1.14 2002/11/25 20:10:55 s_a_white + * A bus access failure should stop the CPU dead like the cycle never started. + * This is currently simulated using throw (execption handling) for now. + * + * Revision 1.13 2002/11/21 19:52:48 s_a_white + * CPU upgraded to be like other components. Theres nolonger a clock call, + * instead events are registered to occur at a specific time. + * + * Revision 1.12 2002/11/19 22:57:33 s_a_white + * Initial support for external DMA to steal cycles away from the CPU. + * + * Revision 1.11 2002/11/01 17:35:27 s_a_white + * Frame based support for old sidplay1 modes. + * + * Revision 1.10 2001/08/05 15:46:02 s_a_white + * No longer need to check on which cycle an instruction ends or when to print + * debug information. + * + * Revision 1.9 2001/07/14 16:48:03 s_a_white + * cycleCount and related must roject.Syn + * + * Revision 1.8 2001/07/14 13:15:30 s_a_white + * Accumulator is now unsigned, which improves code readability. Emulation + * tested with testsuite 2.15. Various instructions required modification. + * + * Revision 1.7 2001/03/28 21:17:34 s_a_white + * Added support for proper RMW instructions. + * + * Revision 1.6 2001/03/24 18:09:17 s_a_white + * On entry to interrupt routine the first instruction in the handler is now always + * executed before pending interrupts are re-checked. + * + * Revision 1.5 2001/03/19 23:48:21 s_a_white + * Interrupts made virtual to allow for redefintion for Sidplay1 compatible + * interrupts. + * + * Revision 1.4 2001/03/09 22:28:03 s_a_white + * Speed optimisation update. + * + * Revision 1.3 2001/02/13 21:03:33 s_a_white + * Changed inlines to non-inlines due to function bodies not being in header. + * + * Revision 1.2 2000/12/11 19:04:32 s_a_white + * AC99 Update. + * + ***************************************************************************/ + +#ifndef _mos6510c_h_ +#define _mos6510c_h_ + +#include "sidtypes.h" +#include "sidendian.h" + + +class MOS6510: public C64Environment, public Event +{ +private: + // External signals + bool aec; /* Address Controller, blocks all */ + bool rdy; /* Bus Access, blocks reads */ + bool m_blocked; + +protected: + bool dodump; + EventContext &eventContext; + + // Declare processor operations + struct ProcessorOperations + { + void (MOS6510::**cycle)(void); + uint cycles; + uint_least8_t opcode; + }; + + void (MOS6510::*fetchCycle[1]) (void); + struct ProcessorOperations instrTable[0x100]; + struct ProcessorOperations interruptTable[3]; + struct ProcessorOperations *instrCurrent; + + uint_least16_t instrStartPC; + uint_least8_t instrOpcode; + void (MOS6510::**procCycle) (void); + int_least8_t lastAddrCycle; + int_least8_t cycleCount; + + // Pointers to the current instruction cycle + uint_least16_t Cycle_EffectiveAddress; + uint8_t Cycle_Data; + uint_least16_t Cycle_Pointer; + + uint8_t Register_Accumulator; + uint8_t Register_X; + uint8_t Register_Y; + uint_least32_t Register_ProgramCounter; + uint8_t Register_Status; + uint_least8_t Register_c_Flag; + uint_least8_t Register_n_Flag; + uint_least8_t Register_v_Flag; + uint_least8_t Register_z_Flag; + uint_least16_t Register_StackPointer; + uint_least16_t Instr_Operand; + + // Interrupts + struct + { + uint_least8_t pending; + uint_least8_t irqs; + event_clock_t nmiClock; + event_clock_t irqClock; + event_clock_t delay; + bool irqRequest; + bool irqLatch; + } interrupts; + + uint8_t Debug_Data; + uint_least16_t Debug_EffectiveAddress; + uint_least8_t Debug_Opcode; + uint_least16_t Debug_Operand; + uint_least16_t Debug_ProgramCounter; + +protected: + void clock (void); + void event (void); + void Initialise (void); + // Declare Interrupt Routines + inline void RSTRequest (void); + inline void RST1Request (void); + inline void NMIRequest (void); + inline void NMI1Request (void); + inline void IRQRequest (void); + inline void IRQ1Request (void); + inline void IRQ2Request (void); + bool interruptPending (void); + + // Declare Instruction Routines + virtual void FetchOpcode (void); + void NextInstr (void); + inline void FetchDataByte (void); + inline void FetchLowAddr (void); + inline void FetchLowAddrX (void); + inline void FetchLowAddrY (void); + inline void FetchHighAddr (void); + inline void FetchHighAddrX (void); + inline void FetchHighAddrX2 (void); + inline void FetchHighAddrY (void); + inline void FetchHighAddrY2 (void); + inline void FetchLowEffAddr (void); + inline void FetchHighEffAddr (void); + inline void FetchHighEffAddrY (void); + inline void FetchHighEffAddrY2 (void); + inline void FetchLowPointer (void); + inline void FetchLowPointerX (void); + inline void FetchHighPointer (void); + inline void FetchEffAddrDataByte (void); + inline void PutEffAddrDataByte (void); + inline void FetchPutEffAddrDataByte (void); + inline void PushLowPC (void); + inline void PushHighPC (void); + inline void PushSR (bool b_flag); + inline void PushSR (void); + inline void PopLowPC (void); + inline void PopHighPC (void); + inline void PopSR (void); + inline void WasteCycle (void); + inline void DebugCycle (void); + + // Delcare Instruction Operation Routines + inline void adc_instr (void); + inline void alr_instr (void); + inline void anc_instr (void); + inline void and_instr (void); + inline void ane_instr (void); + inline void arr_instr (void); + inline void asl_instr (void); + inline void asla_instr (void); + inline void aso_instr (void); + inline void axa_instr (void); + inline void axs_instr (void); + inline void bcc_instr (void); + inline void bcs_instr (void); + inline void beq_instr (void); + inline void bit_instr (void); + inline void bmi_instr (void); + inline void bne_instr (void); + inline void branch_instr (bool condition); + inline void bpl_instr (void); + inline void brk_instr (void); + inline void bvc_instr (void); + inline void bvs_instr (void); + inline void clc_instr (void); + inline void cld_instr (void); + inline void cli_instr (void); + inline void clv_instr (void); + inline void cmp_instr (void); + inline void cpx_instr (void); + inline void cpy_instr (void); + inline void dcm_instr (void); + inline void dec_instr (void); + inline void dex_instr (void); + inline void dey_instr (void); + inline void eor_instr (void); + inline void inc_instr (void); + inline void ins_instr (void); + inline void inx_instr (void); + inline void iny_instr (void); + inline void jmp_instr (void); + inline void jsr_instr (void); + inline void las_instr (void); + inline void lax_instr (void); + inline void lda_instr (void); + inline void ldx_instr (void); + inline void ldy_instr (void); + inline void lse_instr (void); + inline void lsr_instr (void); + inline void lsra_instr (void); + inline void oal_instr (void); + inline void ora_instr (void); + inline void pha_instr (void); + inline void pla_instr (void); + inline void rla_instr (void); + inline void rol_instr (void); + inline void rola_instr (void); + inline void ror_instr (void); + inline void rora_instr (void); + inline void rra_instr (void); + inline void rti_instr (void); + inline void rts_instr (void); + inline void sbx_instr (void); + inline void say_instr (void); + inline void sbc_instr (void); + inline void sec_instr (void); + inline void sed_instr (void); + inline void sei_instr (void); + inline void shs_instr (void); + inline void sta_instr (void); + inline void stx_instr (void); + inline void sty_instr (void); + inline void tas_instr (void); + inline void tax_instr (void); + inline void tay_instr (void); + inline void tsx_instr (void); + inline void txa_instr (void); + inline void txs_instr (void); + inline void tya_instr (void); + inline void xas_instr (void); + void illegal_instr (void); + + // Declare Arithmatic Operations + inline void Perform_ADC (void); + inline void Perform_SBC (void); + +public: + MOS6510 (EventContext *context); + virtual ~MOS6510 (); + virtual void reset (void); + virtual void credits (char *str); + virtual void DumpState (void); + void debug (bool enable) {dodump = enable;} + void aecSignal (bool state); + void rdySignal (bool state); + + // Non-standard functions + virtual void triggerRST (void); + virtual void triggerNMI (void); + virtual void triggerIRQ (void); + void clearIRQ (void); +}; + + +//-------------------------------------------------------------------------// +// Emulate One Complete Cycle // +inline void MOS6510::clock (void) +{ + int_least8_t i = cycleCount++; + try { + (this->*procCycle[i]) (); + } catch (int_least8_t delta) { + cycleCount += delta; + m_blocked = true; + eventContext.cancel (this); + } +} + +inline void MOS6510::event (void) +{ + eventContext.schedule (this, 1); + clock (); +} + +#endif // _mos6510c_h_ diff --git a/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/mos6510c.i b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/mos6510c.i new file mode 100644 index 00000000..78d57ba6 --- /dev/null +++ b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/mos6510c.i @@ -0,0 +1,2562 @@ +/*************************************************************************** + mos6510.i - Cycle Accurate 6510 emulation + ------------------- + begin : Thu May 11 06:22:40 BST 2000 + copyright : (C) 2000 by Simon White + email : s_a_white@email.com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +/*************************************************************************** + * $Log: mos6510c.i,v $ + * Revision 1.30 2002/12/16 08:42:58 s_a_white + * Fixed use of nothrow to be namespaced with std::. + * + * Revision 1.29 2002/11/28 20:35:06 s_a_white + * Reduced number of thrown exceptions when dma occurs. + * + * Revision 1.28 2002/11/25 20:10:55 s_a_white + * A bus access failure should stop the CPU dead like the cycle never started. + * This is currently simulated using throw (execption handling) for now. + * + * Revision 1.27 2002/11/21 19:52:48 s_a_white + * CPU upgraded to be like other components. Theres nolonger a clock call, + * instead events are registered to occur at a specific time. + * + * Revision 1.26 2002/11/19 22:57:33 s_a_white + * Initial support for external DMA to steal cycles away from the CPU. + * + * Revision 1.25 2002/11/01 19:22:36 s_a_white + * Removed debug printf. + * + * Revision 1.24 2002/11/01 17:35:27 s_a_white + * Frame based support for old sidplay1 modes. + * + * Revision 1.23 2002/03/12 18:48:03 s_a_white + * Tidied illegal instruction debug print out. + * + * Revision 1.22 2001/12/11 19:24:15 s_a_white + * More GCC3 Fixes. + * + * Revision 1.21 2001/11/16 19:21:03 s_a_white + * Sign fixes. + * + * Revision 1.20 2001/10/28 21:31:26 s_a_white + * Removed kernel debuging code. + * + * Revision 1.19 2001/09/03 22:21:52 s_a_white + * When initialising the status register and therefore unmasking the irqs, + * check the irq line to see if any are pending. + * + * Revision 1.18 2001/08/10 20:05:50 s_a_white + * Fixed RMW instructions which broke due to the optimisation. + * + * Revision 1.17 2001/08/05 15:46:02 s_a_white + * No longer need to check on which cycle an instruction ends or when to print + * debug information. + * + * Revision 1.16 2001/07/14 13:15:30 s_a_white + * Accumulator is now unsigned, which improves code readability. Emulation + * tested with testsuite 2.15. Various instructions required modification. + * + * Revision 1.15 2001/04/20 22:23:11 s_a_white + * Handling of page boundary crossing now correct for branch instructions. + * + * Revision 1.14 2001/03/28 22:59:59 s_a_white + * Converted some bad envReadMemByte's to + * envReadMemDataByte + * + * Revision 1.13 2001/03/28 21:17:34 s_a_white + * Added support for proper RMW instructions. + * + * Revision 1.12 2001/03/24 18:09:17 s_a_white + * On entry to interrupt routine the first instruction in the handler is now always + * executed before pending interrupts are re-checked. + * + * Revision 1.11 2001/03/22 22:40:43 s_a_white + * Added new header for definition of nothrow. + * + * Revision 1.10 2001/03/21 22:27:18 s_a_white + * Change to IRQ error message. + * + * Revision 1.9 2001/03/19 23:46:35 s_a_white + * NMI no longer sets I flag. RTI and store instructions are no longer + * overlapped. + * + * Revision 1.8 2001/03/09 22:28:51 s_a_white + * Speed optimisation update and fix for interrupt flag in PushSR call. + * + * Revision 1.7 2001/02/22 08:28:57 s_a_white + * Interrupt masking fixed. + * + * Revision 1.6 2001/02/13 23:01:44 s_a_white + * envReadMemDataByte now used for some memory accesses. + * + * Revision 1.5 2000/12/24 00:45:38 s_a_white + * HAVE_EXCEPTIONS update + * + * Revision 1.4 2000/12/14 23:55:07 s_a_white + * PushSR optimisation and PopSR code cleanup. + * + ***************************************************************************/ +/* +const char _sidtune_CHRtab[256] = // CHR$ conversion table (0x01 = no output) +{ + 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xd, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x20,0x21, 0x1,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x24,0x5d,0x20,0x20, + // alternative: CHR$(92=0x5c) => ISO Latin-1(0xa3) + 0x2d,0x23,0x7c,0x2d,0x2d,0x2d,0x2d,0x7c,0x7c,0x5c,0x5c,0x2f,0x5c,0x5c,0x2f,0x2f, + 0x5c,0x23,0x5f,0x23,0x7c,0x2f,0x58,0x4f,0x23,0x7c,0x23,0x2b,0x7c,0x7c,0x26,0x5c, + // 0x80-0xFF + 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x20,0x7c,0x23,0x2d,0x2d,0x7c,0x23,0x7c,0x23,0x2f,0x7c,0x7c,0x2f,0x5c,0x5c,0x2d, + 0x2f,0x2d,0x2d,0x7c,0x7c,0x7c,0x7c,0x2d,0x2d,0x2d,0x2f,0x5c,0x5c,0x2f,0x2f,0x23, + 0x2d,0x23,0x7c,0x2d,0x2d,0x2d,0x2d,0x7c,0x7c,0x5c,0x5c,0x2f,0x5c,0x5c,0x2f,0x2f, + 0x5c,0x23,0x5f,0x23,0x7c,0x2f,0x58,0x4f,0x23,0x7c,0x23,0x2b,0x7c,0x7c,0x26,0x5c, + 0x20,0x7c,0x23,0x2d,0x2d,0x7c,0x23,0x7c,0x23,0x2f,0x7c,0x7c,0x2f,0x5c,0x5c,0x2d, + 0x2f,0x2d,0x2d,0x7c,0x7c,0x7c,0x7c,0x2d,0x2d,0x2d,0x2f,0x5c,0x5c,0x2f,0x2f,0x23 +}; +*/ + +#include "config.h" + +#ifdef HAVE_EXCEPTIONS +# include <new> +#endif + +// Microsoft Visual C++ Version Number to work around compiler bug +// Currently both Visual C++ Versions 5, 6 are broken. +#define _MSC_VER_BAD_NEW 1200 /* Defines VC6 and below */ +//char filetmp[0x100]; +//int filepos = 0; + +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// +// Status Register Routines // +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// +// Use macros to access flags. Allows compatiblity with other versions +// of this emulation +// Set N and Z flags according to byte +#define setFlagsNZ(x) (Register_z_Flag = (Register_n_Flag = (uint_least8_t) (x))) +#define setFlagN(x) (Register_n_Flag = (uint_least8_t) (x)) +#define setFlagV(x) (Register_v_Flag = (uint_least8_t) (x)) +#define setFlagD(x) (Register_Status = (Register_Status & ~(1 << SR_DECIMAL)) \ + | (((x) != 0) << SR_DECIMAL)) +#define setFlagI(x) (Register_Status = (Register_Status & ~(1 << SR_INTERRUPT)) \ + | (((x) != 0) << SR_INTERRUPT)) +#define setFlagZ(x) (Register_z_Flag = (uint_least8_t) (x)) +#define setFlagC(x) (Register_c_Flag = (uint_least8_t) (x)) + + +#define getFlagN() ((Register_n_Flag & (1 << SR_NEGATIVE)) != 0) +#define getFlagV() (Register_v_Flag != 0) +#define getFlagD() ((Register_Status & (1 << SR_DECIMAL)) != 0) +#define getFlagI() ((Register_Status & (1 << SR_INTERRUPT)) != 0) +#define getFlagZ() (Register_z_Flag == 0) +#define getFlagC() (Register_c_Flag != 0) + +#define stealCycle() \ + interrupts.delay++; \ + throw((int_least8_t) -1); + + +// Handle bus access signals +void MOS6510::aecSignal (bool state) +{ // If the cpu blocked waiting for the bus + // the schedule a retry. + aec = state; + if (state && m_blocked) + { + m_blocked = false; + eventContext.schedule (this, 1); + } +} + +void MOS6510::rdySignal (bool state) +{ // If the cpu blocked waiting for the bus + // the schedule a retry. + rdy = state; + if (state && m_blocked) + { + m_blocked = false; + eventContext.schedule (this, 1); + } +} + +// Push P on stack, decrement S +void MOS6510::PushSR (bool b_flag) +{ + if (aec) + { + uint_least16_t addr = Register_StackPointer; + endian_16hi8 (addr, SP_PAGE); + /* Rev 1.04 - Corrected flag mask */ + Register_Status &= ((1 << SR_NOTUSED) | (1 << SR_INTERRUPT) | + (1 << SR_DECIMAL) | (1 << SR_BREAK)); + Register_Status |= (getFlagN () << SR_NEGATIVE); + Register_Status |= (getFlagV () << SR_OVERFLOW); + Register_Status |= (getFlagZ () << SR_ZERO); + Register_Status |= (getFlagC () << SR_CARRY); + envWriteMemByte (addr, Register_Status & ~((!b_flag) << SR_BREAK)); + Register_StackPointer--; + } + else + { // Address bus not ready + stealCycle(); + } +} + +void MOS6510::PushSR (void) +{ + PushSR (true); +} + +// increment S, Pop P off stack +void MOS6510::PopSR (void) +{ + if (rdy && aec) + { + bool newFlagI, oldFlagI; + oldFlagI = getFlagI (); + + // Get status register off stack + Register_StackPointer++; + { + uint_least16_t addr = Register_StackPointer; + endian_16hi8 (addr, SP_PAGE); + Register_Status = envReadMemByte (addr); + } + Register_Status |= ((1 << SR_NOTUSED) | (1 << SR_BREAK)); + setFlagN (Register_Status); + setFlagV (Register_Status & (1 << SR_OVERFLOW)); + setFlagZ (!(Register_Status & (1 << SR_ZERO))); + setFlagC (Register_Status & (1 << SR_CARRY)); + + // I flag change is delayed by 1 instruction + newFlagI = getFlagI (); + interrupts.irqLatch = oldFlagI ^ newFlagI; + // Check to see if interrupts got re-enabled + if (!newFlagI && interrupts.irqs) + interrupts.irqRequest = true; + } + else + { // Address bus not ready + stealCycle(); + } +} + + +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// +// Interrupt Routines // +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// +#define iIRQSMAX 3 +enum +{ + oNONE = -1, + oRST, + oNMI, + oIRQ +}; + +enum +{ + iNONE = 0, + iRST = 1 << oRST, + iNMI = 1 << oNMI, + iIRQ = 1 << oIRQ +}; + +void MOS6510::triggerRST (void) +{ + interrupts.pending |= iRST; +} + +void MOS6510::triggerNMI (void) +{ + interrupts.pending |= iNMI; + interrupts.nmiClock = eventContext.getTime (); +} + +// Level triggered interrupt +void MOS6510::triggerIRQ (void) +{ // IRQ Suppressed + if (!getFlagI ()) + interrupts.irqRequest = true; + if (!interrupts.irqs++) + interrupts.irqClock = eventContext.getTime (); + + if (interrupts.irqs > iIRQSMAX) + { + printf ("\nMOS6510 ERROR: An external component is not clearing down it's IRQs.\n\n"); + exit (-1); + } +} + +void MOS6510::clearIRQ (void) +{ + if (interrupts.irqs > 0) + { + if (!(--interrupts.irqs)) + { // Clear off the interrupts + interrupts.irqRequest = false; + } + } +} + +bool MOS6510::interruptPending (void) +{ + int_least8_t offset, pending; + static const int_least8_t offTable[] = {oNONE, oRST, oNMI, oRST, + oIRQ, oRST, oNMI, oRST}; + // Update IRQ pending + if (!interrupts.irqLatch) + { + interrupts.pending &= ~iIRQ; + if (interrupts.irqRequest) + interrupts.pending |= iIRQ; + } + + pending = interrupts.pending; +MOS6510_interruptPending_check: + // Service the highest priority interrupt + offset = offTable[pending]; + switch (offset) + { + case oNONE: + return false; + + case oNMI: + { + // Try to determine if we should be processing the NMI yet + event_clock_t cycles = eventContext.getTime (interrupts.nmiClock); + if (cycles >= interrupts.delay) + { + interrupts.pending &= ~iNMI; + break; + } + + // NMI delayed so check for other interrupts + pending &= ~iNMI; + goto MOS6510_interruptPending_check; + } + + case oIRQ: + { + // Try to determine if we should be processing the IRQ yet + event_clock_t cycles = eventContext.getTime (interrupts.irqClock); + if (cycles >= interrupts.delay) + break; + + // NMI delayed so check for other interrupts + pending &= ~iIRQ; + goto MOS6510_interruptPending_check; + } + + case oRST: + break; + } + +#ifdef MOS6510_DEBUG + if (dodump) + { + printf ("****************************************************\n"); + switch (offset) + { + case oIRQ: + printf (" IRQ Routine\n"); + break; + case oNMI: + printf (" NMI Routine\n"); + break; + case oRST: + printf (" RST Routine\n"); + break; + } + printf ("****************************************************\n"); + } +#endif + + // Start the interrupt + instrCurrent = &interruptTable[offset]; + procCycle = instrCurrent->cycle; + cycleCount = 0; + return true; +} + +void MOS6510::RSTRequest (void) +{ + envReset (); +} + +void MOS6510::NMIRequest (void) +{ + if (rdy && aec) + endian_16lo8 (Cycle_EffectiveAddress, envReadMemDataByte (0xFFFA)); + else + { // Address bus not ready + stealCycle(); + } +} + +void MOS6510::NMI1Request (void) +{ + if (rdy && aec) + { + endian_16hi8 (Cycle_EffectiveAddress, envReadMemDataByte (0xFFFB)); + endian_32lo16 (Register_ProgramCounter, Cycle_EffectiveAddress); + } + else + { // Address bus not ready + stealCycle(); + } +} + +void MOS6510::IRQRequest (void) +{ + PushSR (false); + setFlagI (true); + interrupts.irqRequest = false; +} + +void MOS6510::IRQ1Request (void) +{ + if (rdy && aec) + endian_16lo8 (Cycle_EffectiveAddress, envReadMemDataByte (0xFFFE)); + else + { // Address bus not ready + stealCycle(); + } +} + +void MOS6510::IRQ2Request (void) +{ + if (rdy && aec) + { + endian_16hi8 (Cycle_EffectiveAddress, envReadMemDataByte (0xFFFF)); + endian_32lo16 (Register_ProgramCounter, Cycle_EffectiveAddress); + } + else + { // Address bus not ready + stealCycle(); + } +} + +void MOS6510::NextInstr (void) +{ + if (!interruptPending ()) + FetchOpcode (); +} + + +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// +// Common Instruction Addressing Routines // +// Addressing operations as described in 64doc by John West and // +// Marko Makela // +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// + +// Fetch opcode, increment PC +// Addressing Modes: All +void MOS6510::FetchOpcode (void) +{ + if (rdy && aec) + { // On new instruction all interrupt delays are reset + interrupts.delay = MOS6510_INTERRUPT_DELAY; + interrupts.irqLatch = false; + + instrStartPC = endian_32lo16 (Register_ProgramCounter++); + instrOpcode = envReadMemByte (instrStartPC); + // Convert opcode to pointer in instruction table + instrCurrent = &instrTable[instrOpcode]; + Instr_Operand = 0; + procCycle = instrCurrent->cycle; + cycleCount = 0; + clock (); + } + else + { // Address bus not ready + stealCycle(); + } +} + +// Fetch value, increment PC +/* Addressing Modes: Immediate + Relative +*/ +void MOS6510::FetchDataByte (void) +{ // Get data byte from memory + Cycle_Data = envReadMemByte (endian_32lo16 (Register_ProgramCounter)); + Register_ProgramCounter++; + + // Nextline used for Debug + Instr_Operand = (uint_least16_t) Cycle_Data; +} + +// Fetch low address byte, increment PC +/* Addressing Modes: Stack Manipulation + Absolute + Zero Page + Zerp Page Indexed + Absolute Indexed + Absolute Indirect +*/ +void MOS6510::FetchLowAddr (void) +{ + if (rdy && aec) + { + Cycle_EffectiveAddress = envReadMemByte (endian_32lo16 (Register_ProgramCounter)); + Register_ProgramCounter++; + + // Nextline used for Debug + Instr_Operand = Cycle_EffectiveAddress; + } + else + { // Address bus not ready + stealCycle(); + } +} + +// Read from address, add index register X to it +// Addressing Modes: Zero Page Indexed +void MOS6510::FetchLowAddrX (void) +{ + FetchLowAddr (); + Cycle_EffectiveAddress = (Cycle_EffectiveAddress + Register_X) & 0xFF; +} + +// Read from address, add index register Y to it +// Addressing Modes: Zero Page Indexed +void MOS6510::FetchLowAddrY (void) +{ + FetchLowAddr (); + Cycle_EffectiveAddress = (Cycle_EffectiveAddress + Register_Y) & 0xFF; +} + +// Fetch high address byte, increment PC (Absoulte Addressing) +// Low byte must have been obtained first! +// Addressing Modes: Absolute +void MOS6510::FetchHighAddr (void) +{ + if (rdy && aec) + { // Get the high byte of an address from memory + endian_16hi8 (Cycle_EffectiveAddress, envReadMemByte (endian_32lo16 (Register_ProgramCounter))); + Register_ProgramCounter++; + + // Nextline used for Debug + endian_16hi8 (Instr_Operand, endian_16hi8 (Cycle_EffectiveAddress)); + } + else + { // Address bus not ready + stealCycle(); + } +} + +// Fetch high byte of address, add index register X to low address byte, +// increment PC +// Addressing Modes: Absolute Indexed +void MOS6510::FetchHighAddrX (void) +{ + uint8_t page; + // Rev 1.05 (saw) - Call base Function + FetchHighAddr (); + page = endian_16hi8 (Cycle_EffectiveAddress); + Cycle_EffectiveAddress += Register_X; + +#ifdef MOS6510_ACCURATE_CYCLES + // Handle page boundary crossing + if (endian_16hi8 (Cycle_EffectiveAddress) == page) + cycleCount++; +#endif +} + +// Same as above except dosen't worry about page crossing +void MOS6510::FetchHighAddrX2 (void) +{ + FetchHighAddr (); + Cycle_EffectiveAddress += Register_X; +} + +// Fetch high byte of address, add index register Y to low address byte, +// increment PC +// Addressing Modes: Absolute Indexed +void MOS6510::FetchHighAddrY (void) +{ + uint8_t page; + // Rev 1.05 (saw) - Call base Function + FetchHighAddr (); + page = endian_16hi8 (Cycle_EffectiveAddress); + Cycle_EffectiveAddress += Register_Y; + +#ifdef MOS6510_ACCURATE_CYCLES + // Handle page boundary crossing + if (endian_16hi8 (Cycle_EffectiveAddress) == page) + cycleCount++; +#endif +} + +// Same as above except dosen't worry about page crossing +void MOS6510::FetchHighAddrY2 (void) +{ + FetchHighAddr (); + Cycle_EffectiveAddress += Register_Y; +} + +// Fetch pointer address low, increment PC +/* Addressing Modes: Absolute Indirect + Indirect indexed (post Y) +*/ +void MOS6510::FetchLowPointer (void) +{ + if (rdy && aec) + { + Cycle_Pointer = envReadMemByte (endian_32lo16 (Register_ProgramCounter)); + Register_ProgramCounter++; + // Nextline used for Debug + Instr_Operand = Cycle_Pointer; + } + else + { // Address bus not ready + stealCycle(); + } +} + +// Read pointer from the address and add X to it +// Addressing Modes: Indexed Indirect (pre X) +void MOS6510::FetchLowPointerX (void) +{ + if (rdy && aec) + { + endian_16hi8 (Cycle_Pointer, envReadMemDataByte (Cycle_Pointer)); + // Page boundary crossing is not handled + Cycle_Pointer = (Cycle_Pointer + Register_X) & 0xFF; + } + else + { // Address bus not ready + stealCycle(); + } +} + +// Fetch pointer address high, increment PC +// Addressing Modes: Absolute Indirect +void MOS6510::FetchHighPointer (void) +{ + if (rdy && aec) + { + endian_16hi8 (Cycle_Pointer, envReadMemByte (endian_32lo16 (Register_ProgramCounter))); + Register_ProgramCounter++; + + // Nextline used for Debug + endian_16hi8 (Instr_Operand, endian_16hi8 (Cycle_Pointer)); + } + else + { // Address bus not ready + stealCycle(); + } +} + +// Fetch effective address low +/* Addressing Modes: Indirect + Indexed Indirect (pre X) + Indirect indexed (post Y) +*/ +void MOS6510::FetchLowEffAddr (void) +{ + if (rdy && aec) + Cycle_EffectiveAddress = envReadMemDataByte (Cycle_Pointer); + else + { // Address bus not ready + stealCycle(); + } +} + +// Fetch effective address high +/* Addressing Modes: Indirect + Indexed Indirect (pre X) +*/ +void MOS6510::FetchHighEffAddr (void) +{ + if (rdy && aec) + { // Rev 1.03 (Mike) - Extra +1 removed + endian_16lo8 (Cycle_Pointer, (Cycle_Pointer + 1) & 0xff); + endian_16hi8 (Cycle_EffectiveAddress, envReadMemDataByte (Cycle_Pointer)); + } + else + { // Address bus not ready + stealCycle(); + } +} + +// Fetch effective address high, add Y to low byte of effective address +// Addressing Modes: Indirect indexed (post Y) +void MOS6510::FetchHighEffAddrY (void) +{ + uint8_t page; + // Rev 1.05 (saw) - Call base Function + FetchHighEffAddr (); + page = endian_16hi8 (Cycle_EffectiveAddress); + Cycle_EffectiveAddress += Register_Y; + +#ifdef MOS6510_ACCURATE_CYCLES + // Handle page boundary crossing + if (endian_16hi8 (Cycle_EffectiveAddress) == page) + cycleCount++; +#endif +} + +// Same as above except dosen't worry about page crossing +void MOS6510::FetchHighEffAddrY2 (void) +{ + FetchHighEffAddr (); + Cycle_EffectiveAddress += Register_Y; +} + +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// +// Common Data Accessing Routines // +// Data Accessing operations as described in 64doc by John West and // +// Marko Makela // +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// + +void MOS6510::FetchEffAddrDataByte (void) +{ + if (rdy && aec) + Cycle_Data = envReadMemDataByte (Cycle_EffectiveAddress); + else + { // Address bus not ready + stealCycle(); + } +} + +void MOS6510::PutEffAddrDataByte (void) +{ + if (aec) + envWriteMemByte (Cycle_EffectiveAddress, Cycle_Data); + else + { // Address bus not ready + stealCycle(); + } +} + +// Used for Read Modify Write (RMW) instructions +void MOS6510::FetchPutEffAddrDataByte (void) +{ + FetchEffAddrDataByte (); + PutEffAddrDataByte (); +} + +// Push Program Counter Low Byte on stack, decrement S +void MOS6510::PushLowPC (void) +{ + if (aec) + { + uint_least16_t addr; + addr = Register_StackPointer; + endian_16hi8 (addr, SP_PAGE); + envWriteMemByte (addr, endian_32lo8 (Register_ProgramCounter)); + Register_StackPointer--; + } + else + { // Address bus not ready + stealCycle(); + } +} + +// Push Program Counter High Byte on stack, decrement S +void MOS6510::PushHighPC (void) +{ + if (aec) + { + uint_least16_t addr; + addr = Register_StackPointer; + endian_16hi8 (addr, SP_PAGE); + envWriteMemByte (addr, endian_32hi8 (Register_ProgramCounter)); + Register_StackPointer--; + } + else + { // Address bus not ready + stealCycle(); + } +} + +// Increment stack and pull program counter low byte from stack, +void MOS6510::PopLowPC (void) +{ + if (rdy && aec) + { + uint_least16_t addr; + Register_StackPointer++; + addr = Register_StackPointer; + endian_16hi8 (addr, SP_PAGE); + endian_16lo8 (Cycle_EffectiveAddress, envReadMemDataByte (addr)); + } + else + { // Address bus not ready + stealCycle(); + } +} + +// Increment stack and pull program counter high byte from stack, +void MOS6510::PopHighPC (void) +{ + if (rdy && aec) + { + uint_least16_t addr; + Register_StackPointer++; + addr = Register_StackPointer; + endian_16hi8 (addr, SP_PAGE); + endian_16hi8 (Cycle_EffectiveAddress, envReadMemDataByte (addr)); + } + else + { // Address bus not ready + stealCycle(); + } +} + +void MOS6510::WasteCycle (void) +{ +} + +void MOS6510::DebugCycle (void) +{ + if (dodump) + DumpState (); + clock (); +} + + +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// +// Common Instruction Opcodes // +// See and 6510 Assembly Book for more information on these instructions // +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// + +void MOS6510::brk_instr (void) +{ + PushSR (); + setFlagI (true); + interrupts.irqRequest = false; + + // Check for an NMI, and switch over if pending + if (interrupts.pending & iNMI) + { + event_clock_t cycles = eventContext.getTime (interrupts.nmiClock); + if (cycles >= interrupts.delay) + { + interrupts.pending &= ~iNMI; + instrCurrent = &interruptTable[oNMI]; + procCycle = &instrCurrent->cycle[cycleCount]; + } + } +} + +void MOS6510::cld_instr (void) +{ + setFlagD (false); +} + +void MOS6510::cli_instr (void) +{ + bool oldFlagI = getFlagI (); + setFlagI (false); + // I flag change is delayed by 1 instruction + interrupts.irqLatch = oldFlagI ^ getFlagI (); + // Check to see if interrupts got re-enabled + if (interrupts.irqs) + interrupts.irqRequest = true; +} + +void MOS6510::jmp_instr (void) +{ + endian_32lo16 (Register_ProgramCounter, Cycle_EffectiveAddress); +} + +void MOS6510::jsr_instr (void) +{ // JSR uses absolute addressing in this emulation, + // hence the -1. The real SID does not use this addressing + // mode. + Register_ProgramCounter--; + PushHighPC (); +} + +void MOS6510::pha_instr (void) +{ + if (aec) + { + uint_least16_t addr; + addr = Register_StackPointer; + endian_16hi8 (addr, SP_PAGE); + envWriteMemByte (addr, Register_Accumulator); + Register_StackPointer--; + } + else + { // Address bus not ready + cycleCount--; + return; + } +} + +/* RTI does not delay the IRQ I flag change as it is set 3 cycles before + * the end of the opcode, and thus the 6510 has enough time to call the + * interrupt routine as soon as the opcode ends, if necessary. */ +void MOS6510::rti_instr (void) +{ +#ifdef MOS6510_DEBUG + if (dodump) + printf ("****************************************************\n\n"); +#endif + + endian_32lo16 (Register_ProgramCounter, Cycle_EffectiveAddress); + interrupts.irqLatch = false; +} + +void MOS6510::rts_instr (void) +{ +/* + // Hack - Output character to screen + if (Register_ProgramCounter == 0xffd3) + { + char ch = _sidtune_CHRtab[Register_Accumulator]; + switch (ch) + { + case 0: + break; + case 1: + printf (" "); + fprintf (stderr, " "); + case 0xd: + printf ("\n"); + fprintf (stderr, "\n"); + filepos = 0; + break; + default: + filetmp[filepos++] = ch; + printf ("%c", ch); + fprintf (stderr, "%c", ch); + } + } + + if (Register_ProgramCounter == 0xe170) + { + filetmp[filepos] = '\0'; + envLoadFile (filetmp); + } +*/ + endian_32lo16 (Register_ProgramCounter, Cycle_EffectiveAddress); + Register_ProgramCounter++; +} + +void MOS6510::sed_instr (void) +{ + setFlagD (true); +} + +void MOS6510::sei_instr (void) +{ + bool oldFlagI = getFlagI (); + setFlagI (true); + // I flag change is delayed by 1 instruction + interrupts.irqLatch = oldFlagI ^ getFlagI (); + interrupts.irqRequest = false; +} + +void MOS6510::sta_instr (void) +{ + Cycle_Data = Register_Accumulator; + PutEffAddrDataByte (); +} + +void MOS6510::stx_instr (void) +{ + Cycle_Data = Register_X; + PutEffAddrDataByte (); +} + +void MOS6510::sty_instr (void) +{ + Cycle_Data = Register_Y; + PutEffAddrDataByte (); +} + + + +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// +// Common Instruction Undocumented Opcodes // +// See documented 6502-nmo.opc by Adam Vardy for more details // +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// + +// Undocumented - This opcode stores the result of A AND X AND the high +// byte of the target address of the operand +1 in memory. +void MOS6510::axa_instr (void) +{ + Cycle_Data = Register_X & Register_Accumulator & (endian_16hi8 (Cycle_EffectiveAddress) + 1); + PutEffAddrDataByte (); +} + +// Undocumented - AXS ANDs the contents of the A and X registers (without changing the +// contents of either register) and stores the result in memory. +// AXS does not affect any flags in the processor status register. +void MOS6510::axs_instr (void) +{ + Cycle_Data = Register_Accumulator & Register_X; +} + +/* Not required - Operation performed By another method +// Undocumented - HLT crashes the microprocessor. When this opcode is executed, program +// execution ceases. No hardware interrupts will execute either. The author +// has characterized this instruction as a halt instruction since this is the +// most straightforward explanation for this opcode's behaviour. Only a reset +// will restart execution. This opcode leaves no trace of any operation +// performed! No registers affected. +void MOS6510::hlt_instr (void) +{ +} +*/ + +/* Not required - Operation performed By another method +void MOS6510::nop_instr (void) +{ +} +*/ + +/* Not required - Operation performed By another method +void MOS6510::php_instr (void) +{ +} +*/ + +// Undocumented - This opcode ANDs the contents of the Y register with <ab+1> and stores the +// result in memory. +void MOS6510::say_instr (void) +{ + Cycle_Data = Register_Y & (endian_16hi8 (Cycle_EffectiveAddress) + 1); +} + +/* Not required - Operation performed By another method +// Undocumented - skip next byte. +void MOS6510::skb_instr (void) +{ + Register_ProgramCounter++; +} +*/ + +/* Not required - Operation performed By another method +// Undocumented - skip next word. +void MOS6510::skw_instr (void) +{ + Register_ProgramCounter += 2; +} +*/ + +// Undocumented - This opcode ANDs the contents of the X register with <ab+1> and stores the +// result in memory. +void MOS6510::xas_instr (void) +{ + Cycle_Data = Register_X & (endian_16hi8 (Cycle_EffectiveAddress) + 1); +} + + +#ifdef X86 +#include "MOS6510\CYCLE_~1\X86.CPP" +//#include "MOS6510\CYCLE_BASED\X86.CPP" +#else + +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// +// Generic Binary Coded Decimal Correction // +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// + +void MOS6510::Perform_ADC (void) +{ + uint C = getFlagC (); + uint A = Register_Accumulator; + uint s = Cycle_Data; + uint regAC2 = A + s + C; + + if (getFlagD ()) + { // BCD mode + uint lo = (A & 0x0f) + (s & 0x0f) + C; + uint hi = (A & 0xf0) + (s & 0xf0); + if (lo > 0x09) lo += 0x06; + if (lo > 0x0f) hi += 0x10; + + setFlagZ (regAC2); + setFlagN (hi); + setFlagV (((hi ^ A) & 0x80) && !((A ^ s) & 0x80)); + if (hi > 0x90) hi += 0x60; + + setFlagC (hi > 0xff); + Register_Accumulator = (hi | (lo & 0x0f)); + } + else + { // Binary mode + setFlagC (regAC2 > 0xff); + setFlagV (((regAC2 ^ A) & 0x80) && !((A ^ s) & 0x80)); + setFlagsNZ (Register_Accumulator = regAC2 & 0xff); + } +} + +void MOS6510::Perform_SBC (void) +{ + uint C = !getFlagC (); + uint A = Register_Accumulator; + uint s = Cycle_Data; + uint regAC2 = A - s - C; + + setFlagC (regAC2 < 0x100); + setFlagV (((regAC2 ^ A) & 0x80) && ((A ^ s) & 0x80)); + setFlagsNZ (regAC2); + + if (getFlagD ()) + { // BCD mode + uint lo = (A & 0x0f) - (s & 0x0f) - C; + uint hi = (A & 0xf0) - (s & 0xf0); + if (lo & 0x10) + { + lo -= 0x06; + hi -= 0x10; + } + if (hi & 0x100) hi -= 0x60; + Register_Accumulator = (hi | (lo & 0x0f)); + } + else + { // Binary mode + Register_Accumulator = regAC2 & 0xff; + } +} + + + +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// +// Generic Instruction Addressing Routines // +//-------------------------------------------------------------------------/ + + +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// +// Generic Instruction Opcodes // +// See and 6510 Assembly Book for more information on these instructions // +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// + +void MOS6510::adc_instr (void) +{ + Perform_ADC (); +} + +void MOS6510::and_instr (void) +{ + setFlagsNZ (Register_Accumulator &= Cycle_Data); +} + +void MOS6510::ane_instr (void) +{ + setFlagsNZ (Register_Accumulator = (Register_Accumulator | 0xee) & Register_X & Cycle_Data); +} + +void MOS6510::asl_instr (void) +{ + setFlagC (Cycle_Data & 0x80); + setFlagsNZ (Cycle_Data <<= 1); +} + +void MOS6510::asla_instr (void) +{ + setFlagC (Register_Accumulator & 0x80); + setFlagsNZ (Register_Accumulator <<= 1); +} + +void MOS6510::branch_instr (bool condition) +{ + if (condition) +#ifdef MOS6510_ACCURATE_CYCLES + { + uint8_t page; + page = endian_32hi8 (Register_ProgramCounter); + Register_ProgramCounter += (int8_t) Cycle_Data; + + // Handle page boundary crossing + if (endian_32hi8 (Register_ProgramCounter) == page) + { + cycleCount++; + interrupts.delay++; + } + } + else + { + cycleCount += 2; + } +#else + Register_ProgramCounter += (int8_t) Cycle_Data; +#endif +} + +void MOS6510::bcc_instr (void) +{ + branch_instr (!getFlagC ()); +} + +void MOS6510::bcs_instr (void) +{ + branch_instr (getFlagC ()); +} + +void MOS6510::beq_instr (void) +{ + branch_instr (getFlagZ ()); +} + +void MOS6510::bit_instr (void) +{ + setFlagZ (Register_Accumulator & Cycle_Data); + setFlagN (Cycle_Data); + setFlagV (Cycle_Data & 0x40); +} + +void MOS6510::bmi_instr (void) +{ + branch_instr (getFlagN ()); +} + +void MOS6510::bne_instr (void) +{ + branch_instr (!getFlagZ ()); +} + +void MOS6510::bpl_instr(void) +{ + branch_instr (!getFlagN ()); +} + +void MOS6510::bvc_instr (void) +{ + branch_instr (!getFlagV ()); +} + +void MOS6510::bvs_instr (void) +{ + branch_instr (getFlagV ()); +} + +void MOS6510::clc_instr (void) +{ + setFlagC (false); +} + +void MOS6510::clv_instr (void) +{ + setFlagV (false); +} + +void MOS6510::cmp_instr (void) +{ + uint_least16_t tmp = (uint_least16_t) Register_Accumulator - Cycle_Data; + setFlagsNZ (tmp); + setFlagC (tmp < 0x100); +} + +void MOS6510::cpx_instr (void) +{ + uint_least16_t tmp = (uint_least16_t) Register_X - Cycle_Data; + setFlagsNZ (tmp); + setFlagC (tmp < 0x100); +} + +void MOS6510::cpy_instr (void) +{ + uint_least16_t tmp = (uint_least16_t) Register_Y - Cycle_Data; + setFlagsNZ (tmp); + setFlagC (tmp < 0x100); +} + +void MOS6510::dec_instr (void) +{ + setFlagsNZ (--Cycle_Data); +} + +void MOS6510::dex_instr (void) +{ + setFlagsNZ (--Register_X); +} + +void MOS6510::dey_instr (void) +{ + setFlagsNZ (--Register_Y); +} + +void MOS6510::eor_instr (void) +{ + setFlagsNZ (Register_Accumulator^= Cycle_Data); +} + +void MOS6510::inc_instr (void) +{ + setFlagsNZ (++Cycle_Data); +} + +void MOS6510::inx_instr (void) +{ + setFlagsNZ (++Register_X); +} + +void MOS6510::iny_instr (void) +{ + setFlagsNZ (++Register_Y); +} + +void MOS6510::lda_instr (void) +{ + setFlagsNZ (Register_Accumulator = Cycle_Data); +} + +void MOS6510::ldx_instr (void) +{ + setFlagsNZ (Register_X = Cycle_Data); +} + +void MOS6510::ldy_instr (void) +{ + setFlagsNZ (Register_Y = Cycle_Data); +} + +void MOS6510::lsr_instr (void) +{ + setFlagC (Cycle_Data & 0x01); + setFlagsNZ (Cycle_Data >>= 1); +} + +void MOS6510::lsra_instr (void) +{ + setFlagC (Register_Accumulator & 0x01); + setFlagsNZ (Register_Accumulator >>= 1); +} + +void MOS6510::ora_instr (void) +{ + setFlagsNZ (Register_Accumulator |= Cycle_Data); +} + +void MOS6510::pla_instr (void) +{ + if (rdy && aec) + { + uint_least16_t addr; + Register_StackPointer++; + addr = Register_StackPointer; + endian_16hi8 (addr, SP_PAGE); + setFlagsNZ (Register_Accumulator = envReadMemByte (addr)); + } + else + { // Address bus not ready + cycleCount--; + return; + } +} + +void MOS6510::rol_instr (void) +{ + uint8_t tmp = Cycle_Data & 0x80; + Cycle_Data <<= 1; + if (getFlagC ()) Cycle_Data |= 0x01; + setFlagsNZ (Cycle_Data); + setFlagC (tmp); +} + +void MOS6510::rola_instr (void) +{ + uint8_t tmp = Register_Accumulator & 0x80; + Register_Accumulator <<= 1; + if (getFlagC ()) Register_Accumulator |= 0x01; + setFlagsNZ (Register_Accumulator); + setFlagC (tmp); +} + +void MOS6510::ror_instr (void) +{ + uint8_t tmp = Cycle_Data & 0x01; + Cycle_Data >>= 1; + if (getFlagC ()) Cycle_Data |= 0x80; + setFlagsNZ (Cycle_Data); + setFlagC (tmp); +} + +void MOS6510::rora_instr (void) +{ + uint8_t tmp = Register_Accumulator & 0x01; + Register_Accumulator >>= 1; + if (getFlagC ()) Register_Accumulator |= 0x80; + setFlagsNZ (Register_Accumulator); + setFlagC (tmp); +} + +void MOS6510::sbx_instr (void) +{ + uint tmp = (Register_X & Register_Accumulator) - Cycle_Data; + setFlagsNZ (Register_X = tmp & 0xff); + setFlagC (tmp < 0x100); +} + +void MOS6510::sbc_instr (void) +{ + Perform_SBC (); +} + +void MOS6510::sec_instr (void) +{ + setFlagC (true); +} + +void MOS6510::shs_instr (void) +{ + endian_16lo8 (Register_StackPointer, (Register_Accumulator & Register_X)); + Cycle_Data = (endian_16hi8 (Cycle_EffectiveAddress) + 1) & Register_StackPointer; +} + +void MOS6510::tax_instr (void) +{ + setFlagsNZ (Register_X = Register_Accumulator); +} + +void MOS6510::tay_instr (void) +{ + setFlagsNZ (Register_Y = Register_Accumulator); +} + +void MOS6510::tsx_instr (void) +{ // Rev 1.03 (saw) - Got these tsx and txs reversed + setFlagsNZ (Register_X = endian_16lo8 (Register_StackPointer)); +} + +void MOS6510::txa_instr (void) +{ + setFlagsNZ (Register_Accumulator = Register_X); +} + +void MOS6510::txs_instr (void) +{ // Rev 1.03 (saw) - Got these tsx and txs reversed + endian_16lo8 (Register_StackPointer, Register_X); +} + +void MOS6510::tya_instr (void) +{ + setFlagsNZ (Register_Accumulator = Register_Y); +} + +void MOS6510::illegal_instr (void) +{ + printf ("\n\nILLEGAL INSTRUCTION, resetting emulation. **************\n"); + DumpState (); + printf ("********************************************************\n"); + // Perform Environment Reset + envReset (); +} + + +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// +// Generic Instruction Undocuemented Opcodes // +// See documented 6502-nmo.opc by Adam Vardy for more details // +//-------------------------------------------------------------------------// +//-------------------------------------------------------------------------// + +// Undocumented - This opcode ANDs the contents of the A register with an immediate value and +// then LSRs the result. +void MOS6510::alr_instr (void) +{ + Register_Accumulator &= Cycle_Data; + setFlagC (Register_Accumulator & 0x01); + setFlagsNZ (Register_Accumulator >>= 1); +} + +// Undcouemented - ANC ANDs the contents of the A register with an immediate value and then +// moves bit 7 of A into the Carry flag. This opcode works basically +// identically to AND #immed. except that the Carry flag is set to the same +// state that the Negative flag is set to. +void MOS6510::anc_instr (void) +{ + setFlagsNZ (Register_Accumulator &= Cycle_Data); + setFlagC (getFlagN ()); +} + +// Undocumented - This opcode ANDs the contents of the A register with an immediate value and +// then RORs the result (Implementation based on that of Frodo C64 Emulator) +void MOS6510::arr_instr (void) +{ + uint8_t data = Cycle_Data & Register_Accumulator; + Register_Accumulator = data >> 1; + if (getFlagC ()) Register_Accumulator |= 0x80; + + if (getFlagD ()) + { + setFlagN (0); + if (getFlagC ()) setFlagN (1 << SR_NEGATIVE); + setFlagZ (Register_Accumulator); + setFlagV ((data ^ Register_Accumulator) & 0x40); + + if ((data & 0x0f) + (data & 0x01) > 5) + Register_Accumulator = Register_Accumulator & 0xf0 | (Register_Accumulator + 6) & 0x0f; + setFlagC (((data + (data & 0x10)) & 0x1f0) > 0x50); + if (getFlagC ()) + Register_Accumulator += 0x60; + } + else + { + setFlagsNZ (Register_Accumulator); + setFlagC (Register_Accumulator & 0x40); + setFlagV ((Register_Accumulator & 0x40) ^ ((Register_Accumulator & 0x20) << 1)); + } +} + +// Undocumented - This opcode ASLs the contents of a memory location and then ORs the result +// with the accumulator. +void MOS6510::aso_instr (void) +{ + setFlagC (Cycle_Data & 0x80); + Cycle_Data <<= 1; + setFlagsNZ (Register_Accumulator |= Cycle_Data); +} + +// Undocumented - This opcode DECs the contents of a memory location and then CMPs the result +// with the A register. +void MOS6510::dcm_instr (void) +{ + uint_least16_t tmp; + Cycle_Data--; + tmp = (uint_least16_t) Register_Accumulator - Cycle_Data; + setFlagsNZ (tmp); + setFlagC (tmp < 0x100); +} + +// Undocumented - This opcode INCs the contents of a memory location and then SBCs the result +// from the A register. +void MOS6510::ins_instr (void) +{ + Cycle_Data++; + Perform_SBC (); +} + +// Undocumented - This opcode ANDs the contents of a memory location with the contents of the +// stack pointer register and stores the result in the accumulator, the X +// register, and the stack pointer. Affected flags: N Z. +void MOS6510::las_instr (void) +{ + setFlagsNZ (Cycle_Data &= endian_16lo8 (Register_StackPointer)); + Register_Accumulator = Cycle_Data; + Register_X = Cycle_Data; + Register_StackPointer = Cycle_Data; +} + +// Undocumented - This opcode loads both the accumulator and the X register with the contents +// of a memory location. +void MOS6510::lax_instr (void) +{ + setFlagsNZ (Register_Accumulator = Register_X = Cycle_Data); +} + +// Undocumented - LSE LSRs the contents of a memory location and then EORs the result with +// the accumulator. +void MOS6510::lse_instr (void) +{ + setFlagC (Cycle_Data & 0x01); + Cycle_Data >>= 1; + setFlagsNZ (Register_Accumulator ^= Cycle_Data); +} + +// Undocumented - This opcode ORs the A register with #xx, ANDs the result with an immediate +// value, and then stores the result in both A and X. +// xx may be EE,EF,FE, OR FF, but most emulators seem to use EE +void MOS6510::oal_instr (void) +{ + setFlagsNZ (Register_X = (Register_Accumulator = (Cycle_Data & (Register_Accumulator | 0xee)))); +} + +// Undocumented - RLA ROLs the contents of a memory location and then ANDs the result with +// the accumulator. +void MOS6510::rla_instr (void) +{ + uint8_t tmp = Cycle_Data & 0x80; + Cycle_Data = Cycle_Data << 1; + if (getFlagC ()) Cycle_Data |= 0x01; + setFlagC (tmp); + setFlagsNZ (Register_Accumulator &= Cycle_Data); +} + +// Undocumented - RRA RORs the contents of a memory location and then ADCs the result with +// the accumulator. +void MOS6510::rra_instr (void) +{ + uint8_t tmp = Cycle_Data & 0x01; + Cycle_Data >>= 1; + if (getFlagC ()) Cycle_Data |= 0x80; + setFlagC (tmp); + Perform_ADC (); +} + +// Undocumented - This opcode ANDs the contents of the A and X registers (without changing +// the contents of either register) and transfers the result to the stack +// pointer. It then ANDs that result with the contents of the high byte of +// the target address of the operand +1 and stores that final result in +// memory. +void MOS6510::tas_instr (void) +{ + endian_16lo8 (Register_StackPointer, Register_Accumulator & Register_X); + uint_least16_t tmp = Register_StackPointer & (Cycle_EffectiveAddress + 1); + Cycle_Data = (signed) endian_16lo8 (tmp); +} + +#endif // X86 + + +//-------------------------------------------------------------------------// +// Initialise and create CPU Chip // + +//MOS6510::MOS6510 (model_t _model, const char *id) +MOS6510::MOS6510 (EventContext *context) +:eventContext(*context), + Event("CPU") +{ + struct ProcessorOperations *instr; + uint8_t legalMode = true; + uint8_t legalInstr = true; + uint i, pass; + + //---------------------------------------------------------------------- + // Build up the processor instruction table + for (i = 0; i < 0x100; i++) + { +#if MOS6510_DEBUG > 1 + printf ("Building Command %d[%02x]..", i, i); +#endif + + // Pass 1 allocates the memory, Pass 2 builds the instruction + instr = &instrTable[i]; + instr->cycle = NULL; + + for (pass = 0; pass < 2; pass++) + { + enum {WRITE = 0, RMW = 1, READ = 2}; + int access = WRITE; + cycleCount = -1; + legalMode = true; + legalInstr = true; + if (pass) procCycle = instr->cycle; + + switch (i) + { + // Accumulator or Implied addressing + case ASLn: case CLCn: case CLDn: case CLIn: case CLVn: case DEXn: + case DEYn: case INXn: case INYn: case LSRn: case NOPn_: case PHAn: + case PHPn: case PLAn: case PLPn: case ROLn: case RORn: case RTIn: + case RTSn: case SECn: case SEDn: case SEIn: case TAXn: case TAYn: + case TSXn: case TXAn: case TXSn: case TYAn: +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + break; + + // Immediate and Relative Addressing Mode Handler + case ADCb: case ANDb: case ANCb_: case ANEb: case ASRb: case ARRb: + case BCCr: case BCSr: case BEQr: case BMIr: case BNEr: case BPLr: + case BRKn: case BVCr: case BVSr: case CMPb: case CPXb: case CPYb: + case EORb: case LDAb: case LDXb: case LDYb: case LXAb: case NOPb_: + case ORAb: case SBCb_: case SBXb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchDataByte; + break; + + // Zero Page Addressing Mode Handler - Read & RMW + case ADCz: case ANDz: case BITz: case CMPz: case CPXz: case CPYz: + case EORz: case LAXz: case LDAz: case LDXz: case LDYz: case ORAz: + case NOPz_: case SBCz: + access++; + case ASLz: case DCPz: case DECz: case INCz: case ISBz: case LSRz: + case ROLz: case RORz: case SREz: case SLOz: case RLAz: case RRAz: + access++; + case SAXz: case STAz: case STXz: case STYz: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddr; + if (access == READ) { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; + } else if (access == RMW) { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; + } + break; + + // Zero Page with X Offset Addressing Mode Handler + case ADCzx: case ANDzx: case CMPzx: case EORzx: case LDAzx: case LDYzx: + case NOPzx_: case ORAzx: case SBCzx: + access++; + case ASLzx: case DCPzx: case DECzx: case INCzx: case ISBzx: case LSRzx: + case RLAzx: case ROLzx: case RORzx: case RRAzx: case SLOzx: case SREzx: + access++; + case STAzx: case STYzx: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddrX; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + if (access == READ) { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; + } else if (access == RMW) { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; + } + break; + + // Zero Page with Y Offset Addressing Mode Handler + case LDXzy: case LAXzy: + access = READ; + case STXzy: case SAXzy: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddrY; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + if (access == READ) { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; + } + break; + + // Absolute Addressing Mode Handler + case ADCa: case ANDa: case BITa: case CMPa: case CPXa: case CPYa: + case EORa: case LAXa: case LDAa: case LDXa: case LDYa: case NOPa: + case ORAa: case SBCa: + access++; + case ASLa: case DCPa: case DECa: case INCa: case ISBa: case LSRa: + case ROLa: case RORa: case SLOa: case SREa: case RLAa: case RRAa: + access++; + case JMPw: case JSRw: case SAXa: case STAa: case STXa: case STYa: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighAddr; + if (access == READ) { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; + } else if (access == RMW) { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; + } + break; + + // Absolute With X Offset Addressing Mode Handler (Read) + case ADCax: case ANDax: case CMPax: case EORax: case LDAax: + case LDYax: case NOPax_: case ORAax: case SBCax: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighAddrX; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; + break; + + // Absolute X (No page crossing handled) + case ASLax: case DCPax: case DECax: case INCax: case ISBax: + case LSRax: case RLAax: case ROLax: case RORax: case RRAax: + case SLOax: case SREax: + access = RMW; + case SHYax: case STAax: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighAddrX2; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + if (access == RMW) { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; + } + break; + + // Absolute With Y Offset Addresing Mode Handler (Read) + case ADCay: case ANDay: case CMPay: case EORay: case LASay: + case LAXay: case LDAay: case LDXay: case ORAay: case SBCay: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighAddrY; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; + break; + + // Absolute Y (No page crossing handled) + case DCPay: case ISBay: case RLAay: case RRAay: case SLOay: + case SREay: + access = RMW; + case SHAay: case SHSay: case SHXay: case STAay: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighAddrY2; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + if (access == RMW) { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; + } + break; + + // Absolute Indirect Addressing Mode Handler + case JMPi: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowPointer; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighPointer; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowEffAddr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighEffAddr; + break; + + // Indexed with X Preinc Addressing Mode Handler + case ADCix: case ANDix: case CMPix: case EORix: case LAXix: case LDAix: + case ORAix: case SBCix: + access++; + case DCPix: case ISBix: case SLOix: case SREix: case RLAix: case RRAix: + access++; + case SAXix: case STAix: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowPointer; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowPointerX; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowEffAddr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighEffAddr; + if (access == READ) { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; + } else if (access == RMW) { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; + } + break; + + // Indexed with Y Postinc Addressing Mode Handler (Read) + case ADCiy: case ANDiy: case CMPiy: case EORiy: case LAXiy: + case LDAiy: case ORAiy: case SBCiy: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowPointer; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowEffAddr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighEffAddrY; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; + break; + + // Indexed Y (No page crossing handled) + case DCPiy: case ISBiy: case RLAiy: case RRAiy: case SLOiy: + case SREiy: + access = RMW; + case SHAiy: case STAiy: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowPointer; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowEffAddr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighEffAddrY2; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + if (access == RMW) { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; + } + break; + + default: + legalMode = false; + break; + } + +#ifdef MOS6510_DEBUG + if (legalMode) + { + cycleCount++; + if (pass) procCycle[cycleCount] = &MOS6510::DebugCycle; + } +#endif // MOS6510_DEBUG + + //--------------------------------------------------------------------------------------- + // Addressing Modes Finished, other cycles are instruction dependent + switch(i) + { + case ADCz: case ADCzx: case ADCa: case ADCax: case ADCay: case ADCix: + case ADCiy: case ADCb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::adc_instr; + break; + + case ANCb_: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::anc_instr; + break; + + case ANDz: case ANDzx: case ANDa: case ANDax: case ANDay: case ANDix: + case ANDiy: case ANDb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::and_instr; + break; + + case ANEb: // Also known as XAA + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::ane_instr; + break; + + case ARRb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::arr_instr; + break; + + case ASLn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::asla_instr; + break; + + case ASLz: case ASLzx: case ASLa: case ASLax: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::asl_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case ASRb: // Also known as ALR + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::alr_instr; + break; + + case BCCr: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bcc_instr; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + break; + + case BCSr: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bcs_instr; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + break; + + case BEQr: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::beq_instr; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + break; + + case BITz: case BITa: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bit_instr; + break; + + case BMIr: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bmi_instr; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + break; + + case BNEr: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bne_instr; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + break; + + case BPLr: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bpl_instr; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + break; + + case BRKn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushHighPC; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushLowPC; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::brk_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::IRQ1Request; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::IRQ2Request; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchOpcode; + break; + + case BVCr: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bvc_instr; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + break; + + case BVSr: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bvs_instr; +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + break; + + case CLCn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::clc_instr; + break; + + case CLDn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::cld_instr; + break; + + case CLIn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::cli_instr; + break; + + case CLVn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::clv_instr; + break; + + case CMPz: case CMPzx: case CMPa: case CMPax: case CMPay: case CMPix: + case CMPiy: case CMPb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::cmp_instr; + break; + + case CPXz: case CPXa: case CPXb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::cpx_instr; + break; + + case CPYz: case CPYa: case CPYb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::cpy_instr; + break; + + case DCPz: case DCPzx: case DCPa: case DCPax: case DCPay: case DCPix: + case DCPiy: // Also known as DCM + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::dcm_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case DECz: case DECzx: case DECa: case DECax: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::dec_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case DEXn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::dex_instr; + break; + + case DEYn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::dey_instr; + break; + + case EORz: case EORzx: case EORa: case EORax: case EORay: case EORix: + case EORiy: case EORb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::eor_instr; + break; + +/* HLT // Also known as JAM + case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: + case 0x62: case 0x72: case 0x92: case 0xb2: case 0xd2: case 0xf2: + case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: + case 0x62: case 0x72: case 0x92: case 0xb2: case 0xd2: case 0xf2: + cycleCount++; if (pass) procCycle[cycleCount] = hlt_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; +*/ + + case INCz: case INCzx: case INCa: case INCax: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::inc_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case INXn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::inx_instr; + break; + + case INYn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::iny_instr; + break; + + case ISBz: case ISBzx: case ISBa: case ISBax: case ISBay: case ISBix: + case ISBiy: // Also known as INS + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::ins_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case JMPw: case JMPi: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::jmp_instr; + break; + + case JSRw: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::jsr_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushLowPC; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::jmp_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case LASay: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::las_instr; + break; + + case LAXz: case LAXzy: case LAXa: case LAXay: case LAXix: case LAXiy: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::lax_instr; + break; + + case LDAz: case LDAzx: case LDAa: case LDAax: case LDAay: case LDAix: + case LDAiy: case LDAb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::lda_instr; + break; + + case LDXz: case LDXzy: case LDXa: case LDXay: case LDXb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::ldx_instr; + break; + + case LDYz: case LDYzx: case LDYa: case LDYax: case LDYb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::ldy_instr; + break; + + case LSRn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::lsra_instr; + break; + + case LSRz: case LSRzx: case LSRa: case LSRax: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::lsr_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case NOPn_: case NOPb_: + // Should not be required! + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case NOPz_: case NOPzx_: case NOPa: case NOPax_: + // NOPb NOPz NOPzx - Also known as SKBn + // NOPa NOPax - Also known as SKWn + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case LXAb: // Also known as OAL + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::oal_instr; + break; + + case ORAz: case ORAzx: case ORAa: case ORAax: case ORAay: case ORAix: + case ORAiy: case ORAb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::ora_instr; + break; + + case PHAn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::pha_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case PHPn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushSR; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case PLAn: +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::pla_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case PLPn: +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PopSR; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case RLAz: case RLAzx: case RLAix: case RLAa: case RLAax: case RLAay: + case RLAiy: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rla_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case ROLn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rola_instr; + break; + + case ROLz: case ROLzx: case ROLa: case ROLax: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rol_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case RORn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rora_instr; + break; + + case RORz: case RORzx: case RORa: case RORax: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::ror_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case RRAa: case RRAax: case RRAay: case RRAz: case RRAzx: case RRAix: + case RRAiy: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rra_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case RTIn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PopSR; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PopLowPC; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PopHighPC; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rti_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case RTSn: +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PopLowPC; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PopHighPC; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rts_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case SAXz: case SAXzy: case SAXa: case SAXix: // Also known as AXS + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::axs_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + break; + + case SBCz: case SBCzx: case SBCa: case SBCax: case SBCay: case SBCix: + case SBCiy: case SBCb_: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sbc_instr; + break; + + case SBXb: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sbx_instr; + break; + + case SECn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sec_instr; + break; + + case SEDn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sed_instr; + break; + + case SEIn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sei_instr; + break; + + case SHAay: case SHAiy: // Also known as AXA + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::axa_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case SHSay: // Also known as TAS + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::shs_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + break; + + case SHXay: // Also known as XAS + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::xas_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + break; + + case SHYax: // Also known as SAY + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::say_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + break; + + case SLOz: case SLOzx: case SLOa: case SLOax: case SLOay: case SLOix: + case SLOiy: // Also known as ASO + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::aso_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case SREz: case SREzx: case SREa: case SREax: case SREay: case SREix: + case SREiy: // Also known as LSE + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::lse_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case STAz: case STAzx: case STAa: case STAax: case STAay: case STAix: + case STAiy: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sta_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case STXz: case STXzy: case STXa: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::stx_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case STYz: case STYzx: case STYa: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sty_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + break; + + case TAXn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::tax_instr; + break; + + case TAYn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::tay_instr; + break; + + case TSXn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::tsx_instr; + break; + + case TXAn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::txa_instr; + break; + + case TXSn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::txs_instr; + break; + + case TYAn: + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::tya_instr; + break; + + default: + legalInstr = false; + break; + } + + if (!(legalMode || legalInstr)) + { + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::illegal_instr; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + } + else if (!(legalMode && legalInstr)) + { + printf ("\nInstruction 0x%x: Not built correctly.\n\n", i); + exit(1); + } + + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::NextInstr; + cycleCount++; + if (!pass) + { // Pass 1 - Allocate Memory + if (cycleCount) + { +#if defined(_MSC_VER) && (_MSC_VER <= _MSC_VER_BAD_NEW) + typedef void (MOS6510::*ptr2cycle) (void); + instr->cycle = (ptr2cycle*) new char[sizeof (ptr2cycle) *cycleCount]; +#else +# ifdef HAVE_EXCEPTIONS + instr->cycle = new(std::nothrow) (void (MOS6510::*[cycleCount]) (void)); +# else + instr->cycle = new (void (MOS6510::*[cycleCount]) (void)); +# endif +#endif // _MSC_VER + if (!instr->cycle) + goto MOS6510_MemAllocFailed; + } + } + else + instr->opcode = i; + +#if MOS6510_DEBUG > 1 + printf ("."); +#endif + } + + instr->cycles = cycleCount; +#if MOS6510_DEBUG > 1 + printf ("Done [%d Cycles]\n", cycleCount); +#endif + } + + //---------------------------------------------------------------------- + // Build interrupts + for (i = 0; i < 3; i++) + { +#if MOS6510_DEBUG > 1 + printf ("Building Interrupt %d[%02x]..", i, i); +#endif + + // Pass 1 allocates the memory, Pass 2 builds the interrupt + instr = &interruptTable[i]; + instr->cycle = NULL; + instr->opcode = 0; + + for (int pass = 0; pass < 2; pass++) + { + cycleCount = -1; + if (pass) procCycle = instr->cycle; + + switch (i) + { + case oRST: +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::RSTRequest; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchOpcode; + break; + + case oNMI: +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushHighPC; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushLowPC; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::IRQRequest; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::NMIRequest; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::NMI1Request; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchOpcode; + break; + + case oIRQ: +#ifdef MOS6510_ACCURATE_CYCLES + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; +#endif + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushHighPC; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushLowPC; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::IRQRequest; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::IRQ1Request; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::IRQ2Request; + cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchOpcode; + break; + } + + cycleCount++; + if (!pass) + { // Pass 1 - Allocate Memory + if (cycleCount) + { +#if defined(_MSC_VER) && (_MSC_VER <= _MSC_VER_BAD_NEW) + typedef void (MOS6510::*ptr2cycle) (void); + instr->cycle = (ptr2cycle*) new char[sizeof (ptr2cycle) *cycleCount]; +#else +# ifdef HAVE_EXCEPTIONS + instr->cycle = new(std::nothrow) (void (MOS6510::*[cycleCount]) (void)); +# else + instr->cycle = new (void (MOS6510::*[cycleCount]) (void)); +# endif +#endif // _MSC_VER + if (!instr->cycle) + goto MOS6510_MemAllocFailed; + } + } + +#if MOS6510_DEBUG > 1 + printf ("."); +#endif + } + + instr->cycles = cycleCount; +#if MOS6510_DEBUG > 1 + printf ("Done [%d Cycles]\n", cycleCount); +#endif + } + + // Intialise Processor Registers + Register_Accumulator = 0; + Register_X = 0; + Register_Y = 0; + + Cycle_EffectiveAddress = 0; + Cycle_Data = 0; + fetchCycle[0] = &MOS6510::NextInstr; + + dodump = false; + Initialise (); +return; + +MOS6510_MemAllocFailed: + printf ("Unable to allocate enough memory.\n\n"); +exit (-1); +} + +MOS6510::~MOS6510 () +{ + struct ProcessorOperations *instr; + uint i; + + // Remove Opcodes + for (i = 0; i < 0x100; i++) + { + instr = &instrTable[i]; + if (instr->cycle != NULL) delete [] instr->cycle; + } + + // Remove Interrupts + for (i = 0; i < 3; i++) + { + instr = &interruptTable[i]; + if (instr->cycle != NULL) delete [] instr->cycle; + } +} + + +//-------------------------------------------------------------------------// +// Initialise CPU Emulation (Registers) // +void MOS6510::Initialise (void) +{ + // Reset stack + Register_StackPointer = endian_16 (SP_PAGE, 0xFF); + + // Reset Cycle Count + cycleCount = 0; + procCycle = fetchCycle; + + // Reset Status Register + Register_Status = (1 << SR_NOTUSED) | (1 << SR_BREAK); + // FLAGS are set from data directly and do not require + // being calculated first before setting. E.g. if you used + // SetFlags (0), N flag would = 0, and Z flag would = 1. + setFlagsNZ (1); + setFlagC (false); + setFlagV (false); + + // Set PC to some value + Register_ProgramCounter = 0; + // IRQs pending check + interrupts.irqLatch = false; + interrupts.irqRequest = false; + if (interrupts.irqs) + interrupts.irqRequest = true; + + // Signals + aec = true; + rdy = true; + + m_blocked = false; + eventContext.schedule (this, 1); +} + +//-------------------------------------------------------------------------// +// Reset CPU Emulation // +void MOS6510::reset (void) +{ + // Reset Interrupts + interrupts.pending = false; + interrupts.irqs = 0; + interrupts.delay = MOS6510_INTERRUPT_DELAY; + + // Internal Stuff + Initialise (); + + // Requires External Bits + // Read from reset vector for program entry point + endian_16lo8 (Cycle_EffectiveAddress, envReadMemDataByte (0xFFFC)); + endian_16hi8 (Cycle_EffectiveAddress, envReadMemDataByte (0xFFFD)); + Register_ProgramCounter = Cycle_EffectiveAddress; +// filepos = 0; +} + +//-------------------------------------------------------------------------// +// Module Credits // +void MOS6510::credits (char *sbuffer) +{ // Copy credits to buffer + sprintf (sbuffer, "%sModule : MOS6510 Cycle Exact Emulation\n", sbuffer); + sprintf (sbuffer, "%sWritten By : %s\n", sbuffer, MOS6510_AUTHOR); + sprintf (sbuffer, "%sVersion : %s\n", sbuffer, MOS6510_VERSION); + sprintf (sbuffer, "%sReleased : %s\n", sbuffer, MOS6510_DATE); + sprintf (sbuffer, "%sEmail : %s\n", sbuffer, MOS6510_EMAIL); +} diff --git a/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/sid6510c.h b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/sid6510c.h new file mode 100644 index 00000000..49d96dd6 --- /dev/null +++ b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/sid6510c.h @@ -0,0 +1,118 @@ +/*************************************************************************** + sid6510c.h - Special MOS6510 to be fully + compatible with sidplay + ------------------- + begin : Thu May 11 2000 + copyright : (C) 2000 by Simon White + email : s_a_white@email.com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +/*************************************************************************** + * $Log: sid6510c.h,v $ + * Revision 1.16 2002/11/25 21:07:32 s_a_white + * Allow setting of program counter on reset. + * + * Revision 1.15 2002/11/21 19:52:48 s_a_white + * CPU upgraded to be like other components. Theres nolonger a clock call, + * instead events are registered to occur at a specific time. + * + * Revision 1.14 2002/11/19 22:56:25 s_a_white + * Sidplay1 modes modified to make them nolonger require the psid driver. + * + * Revision 1.13 2002/11/01 17:35:27 s_a_white + * Frame based support for old sidplay1 modes. + * + * Revision 1.12 2002/03/12 18:47:13 s_a_white + * Made IRQ in sidplay1 compatibility modes behaves like JSR. This fixes tunes + * that have kernel switched out. + * + * Revision 1.11 2002/02/07 18:02:10 s_a_white + * Real C64 compatibility fixes. Debug of BRK works again. Fixed illegal + * instructions to work like sidplay1. + * + * Revision 1.10 2002/02/04 23:53:23 s_a_white + * Improved compatibilty of older sidplay1 modes. Fixed BRK to work like sidplay1 + * only when stack is 0xff in real mode for better compatibility with C64. + * + * Revision 1.9 2001/09/01 11:08:06 s_a_white + * Fixes for sidplay1 environment modes. + * + * Revision 1.8 2001/07/14 13:18:15 s_a_white + * Stack & PC invalid tests now only performed on a BRK. + * + * Revision 1.7 2001/03/24 18:09:17 s_a_white + * On entry to interrupt routine the first instruction in the handler is now always + * executed before pending interrupts are re-checked. + * + * Revision 1.6 2001/03/22 22:40:07 s_a_white + * Replaced tabs characters. + * + * Revision 1.5 2001/03/21 22:26:13 s_a_white + * Fake interrupts now been moved into here from player.cpp. At anytime it's + * now possible to ditch this compatibility class and use the real thing. + * + * Revision 1.4 2001/03/09 22:28:03 s_a_white + * Speed optimisation update. + * + * Revision 1.3 2001/02/13 21:02:25 s_a_white + * Small tidy up and possibly a small performace increase. + * + * Revision 1.2 2000/12/11 19:04:32 s_a_white + * AC99 Update. + * + ***************************************************************************/ + +#ifndef _sid6510c_h_ +#define _sid6510c_h_ + +#include "mos6510c.h" +#include "sid2types.h" + +class SID6510: public MOS6510 +{ +private: + // Sidplay Specials + bool m_sleeping; + sid2_env_t m_mode; + event_clock_t m_delayClk, m_delayCycles; + bool m_framelock; + +public: + SID6510 (EventContext *context); + + // Standard Functions + void reset (void); + void reset (uint_least16_t pc, uint8_t a, uint8_t x, uint8_t y); + void clock (void); + + void environment (sid2_env_t mode) { m_mode = mode; } + void triggerRST (void); + void triggerNMI (void); + void triggerIRQ (void); + void sleep (void); + +protected: + void FetchOpcode (void); + +private: + void (MOS6510::*delayCycle[1]) (void); + + inline void sid_illegal (void); + inline void sid_delay (void); + inline void sid_brk (void); + inline void sid_jmp (void); + inline void sid_rts (void); + inline void sid_cli (void); + inline void sid_rti (void); + inline void sid_irq (void); +}; + +#endif // _sid6510c_h_ diff --git a/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/sid6510c.i b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/sid6510c.i new file mode 100644 index 00000000..bc573d3b --- /dev/null +++ b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/sid6510c.i @@ -0,0 +1,409 @@ +/*************************************************************************** + sid6510c.i - Sidplay Specific 6510 emulation + ------------------- + begin : Thu May 11 2000 + copyright : (C) 2000 by Simon White + email : s_a_white@email.com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +/*************************************************************************** + * $Log: sid6510c.i,v $ + * Revision 1.28 2002/12/03 23:24:52 s_a_white + * Let environment know when cpu sleeps in real c64 mode. + * + * Revision 1.27 2002/12/02 22:19:43 s_a_white + * sid_brk fix to prevent it running some of the real brk cycles in old emulation + * modes. + * + * Revision 1.26 2002/11/25 21:07:34 s_a_white + * Allow setting of program counter on reset. + * + * Revision 1.25 2002/11/21 19:52:48 s_a_white + * CPU upgraded to be like other components. Theres nolonger a clock call, + * instead events are registered to occur at a specific time. + * + * Revision 1.24 2002/11/19 22:56:25 s_a_white + * Sidplay1 modes modified to make them nolonger require the psid driver. + * + * Revision 1.23 2002/11/01 17:35:27 s_a_white + * Frame based support for old sidplay1 modes. + * + * Revision 1.22 2002/10/15 23:52:14 s_a_white + * Fix sidplay2 cpu sleep optimisation and NMIs. + * + * Revision 1.21 2002/09/23 22:50:55 s_a_white + * Reverted update 1.20 as was incorrect. Only need to + * change MOS6510 to SID6510 for compliancy. + * + * Revision 1.20 2002/09/23 19:42:14 s_a_white + * Newer compilers don't allow pointers to be taken directly + * from base class member functions. + * + * Revision 1.19 2002/03/12 18:47:13 s_a_white + * Made IRQ in sidplay1 compatibility modes behaves like JSR. This fixes tunes + * that have kernel switched out. + * + * Revision 1.18 2002/02/07 18:02:10 s_a_white + * Real C64 compatibility fixes. Debug of BRK works again. Fixed illegal + * instructions to work like sidplay1. + * + * Revision 1.17 2002/02/06 17:49:12 s_a_white + * Fixed sign comparison warning. + * + * Revision 1.16 2002/02/04 23:53:23 s_a_white + * Improved compatibilty of older sidplay1 modes. Fixed BRK to work like sidplay1 + * only when stack is 0xff in real mode for better compatibility with C64. + * + * Revision 1.15 2002/01/28 19:32:16 s_a_white + * PSID sample improvements. + * + * Revision 1.14 2001/10/02 18:00:37 s_a_white + * Removed un-necessary cli. + * + * Revision 1.13 2001/09/18 07:51:39 jpaana + * Small fix to rti-processing. + * + * Revision 1.12 2001/09/03 22:23:06 s_a_white + * Fixed faked IRQ trigger on BRK for sidplay1 environment modes. + * + * Revision 1.11 2001/09/01 11:08:06 s_a_white + * Fixes for sidplay1 environment modes. + * + * Revision 1.10 2001/08/05 15:46:02 s_a_white + * No longer need to check on which cycle an instruction ends or when to print + * debug information. + * + * Revision 1.9 2001/07/14 13:17:40 s_a_white + * Sidplay1 optimisations moved to here. Stack & PC invalid tests now only + * performed on a BRK. + * + * Revision 1.8 2001/03/24 18:09:17 s_a_white + * On entry to interrupt routine the first instruction in the handler is now always + * executed before pending interrupts are re-checked. + * + * Revision 1.7 2001/03/22 22:40:07 s_a_white + * Replaced tabs characters. + * + * Revision 1.6 2001/03/21 22:26:24 s_a_white + * Fake interrupts now been moved into here from player.cpp. At anytime it's + * now possible to ditch this compatibility class and use the real thing. + * + * Revision 1.5 2001/03/09 22:28:03 s_a_white + * Speed optimisation update. + * + * Revision 1.4 2001/02/13 21:02:16 s_a_white + * Small tidy up and possibly a small performace increase. + * + * Revision 1.3 2000/12/11 19:04:32 s_a_white + * AC99 Update. + * + ***************************************************************************/ + +#include "sid6510c.h" + + +SID6510::SID6510 (EventContext *context) +:MOS6510(context), + m_mode(sid2_envR), + m_framelock(false) +{ // Ok start all the hacks for sidplay. This prevents + // execution of code in roms. For real c64 emulation + // create object from base class! Also stops code + // rom execution when bad code switches roms in over + // itself. + for (uint i = 0; i < OPCODE_MAX; i++) + { + procCycle = instrTable[i].cycle; + if (procCycle == NULL) continue; + + for (uint n = 0; n < instrTable[i].cycles; n++) + { + if (procCycle[n] == &SID6510::illegal_instr) + { // Rev 1.2 (saw) - Changed nasty union to reinterpret_cast + procCycle[n] = reinterpret_cast <void (MOS6510::*)()> + (&SID6510::sid_illegal); + } + else if (procCycle[n] == &SID6510::jmp_instr) + { // Stop jumps into rom code + procCycle[n] = reinterpret_cast <void (MOS6510::*)()> + (&SID6510::sid_jmp); + } + else if (procCycle[n] == &SID6510::cli_instr) + { // No overlapping IRQs allowed + procCycle[n] = reinterpret_cast <void (MOS6510::*)()> + (&SID6510::sid_cli); + } + } + } + + { // Since no real IRQs, all RTIs mapped to RTS + // Required for fix bad tunes in old modes + uint n; + procCycle = instrTable[RTIn].cycle; + for (n = 0; n < instrTable[RTIn].cycles; n++) + { + if (procCycle[n] == &SID6510::PopSR) + { + procCycle[n] = reinterpret_cast <void (MOS6510::*)()> + (&SID6510::sid_rti); + break; + } + } + + procCycle = interruptTable[oIRQ].cycle; + for (n = 0; n < interruptTable[oIRQ].cycles; n++) + { + if (procCycle[n] == &SID6510::IRQRequest) + { + procCycle[n] = reinterpret_cast <void (MOS6510::*)()> + (&SID6510::sid_irq); + break; + } + } + } + + { // Support of sidplays BRK functionality + procCycle = instrTable[BRKn].cycle; + for (uint n = 0; n < instrTable[BRKn].cycles; n++) + { + if (procCycle[n] == &SID6510::PushHighPC) + { + procCycle[n] = reinterpret_cast <void (MOS6510::*)()> + (&SID6510::sid_brk); + break; + } + } + } + + // Used to insert busy delays into the CPU emulation + delayCycle[0] = reinterpret_cast <void (MOS6510::*)()> + (&SID6510::sid_delay); +} + +void SID6510::reset (uint_least16_t pc, uint8_t a, uint8_t x, uint8_t y) +{ // Reset the processor + reset (); + + // Registers not touched by a reset + Register_Accumulator = a; + Register_X = x; + Register_Y = y; + Register_ProgramCounter = pc; +} + +void SID6510::reset () +{ + m_sleeping = false; + // Call inherited reset + MOS6510::reset (); +} + +// Send CPU is about to sleep. Only a reset or +// interrupt will wake up the processor +void SID6510::sleep () +{ // Simulate a delay for JMPw + m_delayClk = eventContext.getTime (); + m_sleeping = true; + procCycle = delayCycle; + cycleCount = 0; + eventContext.cancel (this); + envSleep (); + + // Check for outstanding interrupts + if (interrupts.irqs) + { + interrupts.irqs--; + triggerIRQ (); + } + else if (interrupts.pending) + { + m_sleeping = false; + eventContext.schedule (this, 1); + } +} + +void SID6510::FetchOpcode (void) +{ + if (m_mode == sid2_envR) + { + MOS6510::FetchOpcode (); + return; + } + + // Sid tunes end by wrapping the stack. For compatibilty it + // has to be handled. + m_sleeping |= (endian_16hi8 (Register_StackPointer) != SP_PAGE); + m_sleeping |= (endian_32hi16 (Register_ProgramCounter) != 0); + if (!m_sleeping) + MOS6510::FetchOpcode (); + + if (m_framelock == false) + { + m_framelock = true; + // Simulate sidplay1 frame based execution + while (!m_sleeping) + MOS6510::clock (); + sleep (); + m_framelock = false; + } +} + + +//************************************************************************************** +// For sidplay compatibility implement those instructions which don't behave properly. +//************************************************************************************** +void SID6510::sid_brk (void) +{ + if (m_mode == sid2_envR) + { + MOS6510::PushHighPC (); + return; + } + + sei_instr (); +#if !defined(NO_RTS_UPON_BRK) + sid_rts (); +#endif + FetchOpcode (); +} + +void SID6510::sid_jmp (void) +{ // For sidplay compatibility, inherited from environment + if (m_mode == sid2_envR) + { // If a busy loop then just sleep + if (Cycle_EffectiveAddress != instrStartPC) + jmp_instr (); + else + { + Register_ProgramCounter = Cycle_EffectiveAddress; + sleep (); + } + return; + } + + if (envCheckBankJump (Cycle_EffectiveAddress)) + jmp_instr (); + else + sid_rts (); +} + +// Will do a full rts in 1 cycle, to +// destroy current function and quit +void SID6510::sid_rts (void) +{ + PopLowPC(); + PopHighPC(); + rts_instr(); +} + +void SID6510::sid_cli (void) +{ + if (m_mode == sid2_envR) + cli_instr (); +} + +void SID6510::sid_rti (void) +{ + if (m_mode == sid2_envR) + { + PopSR (); + return; + } + + // Fake RTS + sid_rts (); + FetchOpcode (); +} + +void SID6510::sid_irq (void) +{ + MOS6510::IRQRequest (); + if (m_mode != sid2_envR) + { // RTI behaves like RTI in sidplay1 modes + Register_StackPointer++; + } +} + +// Sidplay Suppresses Illegal Instructions +void SID6510::sid_illegal (void) +{ + if (m_mode == sid2_envR) + { + MOS6510::illegal_instr (); + return; + } +#ifdef MOS6510_DEBUG + DumpState (); +#endif +} + +void SID6510::sid_delay (void) +{ + cycleCount = 0; + if (++m_delayCycles >= 3) + { + (void) interruptPending (); + m_delayCycles = 0; + } +} + + +//************************************************************************************** +// Sidplay compatibility interrupts. Basically wakes CPU if it is m_sleeping +//************************************************************************************** +void SID6510::triggerRST (void) +{ // All modes + MOS6510::triggerRST (); + if (m_sleeping) + { + m_sleeping = false; + eventContext.schedule (this, 1); + } +} + +void SID6510::triggerNMI (void) +{ // Only in Real C64 mode + if (m_mode == sid2_envR) + { + MOS6510::triggerNMI (); + if (m_sleeping) + { + m_delayCycles = eventContext.getTime (m_delayClk) % 3; + m_sleeping = false; + eventContext.schedule (this, 1); + } + } +} + +void SID6510::triggerIRQ (void) +{ + switch (m_mode) + { + default: +#ifdef MOS6510_DEBUG + if (dodump) + { + printf ("****************************************************\n"); + printf (" Fake IRQ Routine\n"); + printf ("****************************************************\n"); + } +#endif + return; + case sid2_envR: + MOS6510::triggerIRQ (); + if (m_sleeping) + { // Simulate busy loop + m_delayCycles = eventContext.getTime (m_delayClk) % 3; + m_sleeping = false; + eventContext.schedule (this, 1); + } + } +} diff --git a/plugins/sid/sidplay-libs/libsidplay/src/mos6510/mos6510.cpp b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/mos6510.cpp new file mode 100644 index 00000000..74b09c95 --- /dev/null +++ b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/mos6510.cpp @@ -0,0 +1,534 @@ +/*************************************************************************** + main.cpp - description + ------------------- + begin : Thu May 11 06:22:40 BST 2000 + copyright : (C) 2000 by Simon White + email : s_a_white@email.com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +/*************************************************************************** + * $Log: mos6510.cpp,v $ + * Revision 1.8 2001/08/05 15:46:38 s_a_white + * No longer need to check on which cycle to print debug information. + * + * Revision 1.7 2001/07/14 13:04:34 s_a_white + * Accumulator is now unsigned, which improves code readability. + * + * Revision 1.6 2001/03/09 22:27:46 s_a_white + * Speed optimisation update. + * + * Revision 1.5 2001/02/13 23:01:10 s_a_white + * envReadMemDataByte now used for debugging. + * + * Revision 1.4 2000/12/11 19:03:16 s_a_white + * AC99 Update. + * + ***************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include "sidtypes.h" +#include "sidendian.h" +#include "sidenv.h" +#include "conf6510.h" +#include "opcodes.h" + +#ifdef HAVE_EXCEPTIONS +# include <new> +#endif + +#ifdef MOS6510_STATE_6510 +# include "state6510.h" +# include "state6510.cpp" +#else + +#include "mos6510.h" + +// Check to see what type of emulation is required +#ifdef MOS6510_CYCLE_BASED +# include "cycle_based/mos6510c.i" + +# ifdef MOS6510_SIDPLAY + // Compile in sidplay code +# include "cycle_based/sid6510c.i" +# endif // MOS6510_SIDPLAY +#else + // Line based emulation code has not been provided +#endif // MOS6510_CYCLE_BASED + +void MOS6510::DumpState (void) +{ + uint8_t opcode, data; + uint_least16_t operand, address; + + printf(" PC I A X Y SP DR PR NV-BDIZC Instruction\n"); + printf("%04x ", instrStartPC); + printf("%u ", interrupts.irqs); + printf("%02x ", Register_Accumulator); + printf("%02x ", Register_X); + printf("%02x ", Register_Y); + printf("01%02x ", endian_16lo8 (Register_StackPointer)); + printf("%02x ", envReadMemDataByte (0)); + printf("%02x ", envReadMemDataByte (1)); + + if (getFlagN()) printf ("1"); else printf ("0"); + if (getFlagV()) printf ("1"); else printf ("0"); + if (Register_Status & (1 << SR_NOTUSED)) printf ("1"); else printf ("0"); + if (Register_Status & (1 << SR_BREAK)) printf ("1"); else printf ("0"); + if (getFlagD()) printf ("1"); else printf ("0"); + if (getFlagI()) printf ("1"); else printf ("0"); + if (getFlagZ()) printf ("1"); else printf ("0"); + if (getFlagC()) printf ("1"); else printf ("0"); + + opcode = instrOpcode; + operand = Instr_Operand; + data = Cycle_Data; + + switch (opcode) + { + case BCCr: case BCSr: case BEQr: case BMIr: case BNEr: case BPLr: + case BVCr: case BVSr: + address = (uint_least16_t) (Register_ProgramCounter + (int8_t) operand); + break; + + default: + address = Cycle_EffectiveAddress; + break; + } + + printf(" %02x ", opcode); + + switch(opcode) + { + //Accumulator or Implied addressing + case ASLn: case LSRn: case ROLn: case RORn: + printf(" "); + break; + //Zero Page Addressing Mode Handler + case ADCz: case ANDz: case ASLz: case BITz: case CMPz: case CPXz: + case CPYz: case DCPz: case DECz: case EORz: case INCz: case ISBz: + case LAXz: case LDAz: case LDXz: case LDYz: case LSRz: case NOPz_: + case ORAz: case ROLz: case RORz: case SAXz: case SBCz: case SREz: + case STAz: case STXz: case STYz: case SLOz: case RLAz: case RRAz: + //ASOz AXSz DCMz INSz LSEz - Optional Opcode Names + printf("%02x ", (uint8_t) operand); + break; + //Zero Page with X Offset Addressing Mode Handler + case ADCzx: case ANDzx: case ASLzx: case CMPzx: case DCPzx: case DECzx: + case EORzx: case INCzx: case ISBzx: case LDAzx: case LDYzx: case LSRzx: + case NOPzx_: case ORAzx: case RLAzx: case ROLzx: case RORzx: case RRAzx: + case SBCzx: case SLOzx: case SREzx: case STAzx: case STYzx: + //ASOzx DCMzx INSzx LSEzx - Optional Opcode Names + printf("%02x ", (uint8_t) operand); + break; + //Zero Page with Y Offset Addressing Mode Handler + case LDXzy: case STXzy: case SAXzy: case LAXzy: + //AXSzx - Optional Opcode Names + printf("%02x ", endian_16lo8 (operand)); + break; + //Absolute Addressing Mode Handler + case ADCa: case ANDa: case ASLa: case BITa: case CMPa: case CPXa: + case CPYa: case DCPa: case DECa: case EORa: case INCa: case ISBa: + case JMPw: case JSRw: case LAXa: case LDAa: case LDXa: case LDYa: + case LSRa: case NOPa: case ORAa: case ROLa: case RORa: case SAXa: + case SBCa: case SLOa: case SREa: case STAa: case STXa: case STYa: + case RLAa: case RRAa: + //ASOa AXSa DCMa INSa LSEa - Optional Opcode Names + printf("%02x %02x ", endian_16lo8 (operand), endian_16hi8 (operand)); + break; + //Absolute With X Offset Addresing Mode Handler + case ADCax: case ANDax: case ASLax: case CMPax: case DCPax: case DECax: + case EORax: case INCax: case ISBax: case LDAax: case LDYax: case LSRax: + case NOPax_: case ORAax: case RLAax: case ROLax: case RORax: case RRAax: + case SBCax: case SHYax: case SLOax: case SREax: case STAax: + //ASOax DCMax INSax LSEax SAYax - Optional Opcode Names + printf("%02x %02x ", endian_16lo8 (operand), endian_16hi8 (operand)); + break; + //Absolute With Y Offset Addresing Mode Handler + case ADCay: case ANDay: case CMPay: case DCPay: case EORay: case ISBay: + case LASay: case LAXay: case LDAay: case LDXay: case ORAay: case RLAay: + case RRAay: case SBCay: case SHAay: case SHSay: case SHXay: case SLOay: + case SREay: case STAay: + //ASOay AXAay DCMay INSax LSEay TASay XASay - Optional Opcode Names + printf("%02x %02x ", endian_16lo8 (operand), endian_16hi8 (operand)); + break; + //Immediate and Relative Addressing Mode Handler + case ADCb: case ANDb: case ANCb_: case ANEb: case ASRb: case ARRb: + + case CMPb: case CPXb: case CPYb: case EORb: case LDAb: case LDXb: + case LDYb: case LXAb: case NOPb_: case ORAb: case SBCb_: case SBXb: + //OALb ALRb XAAb - Optional Opcode Names + printf("%02x ", endian_16lo8 (operand)); + break; + case BCCr: case BCSr: case BEQr: case BMIr: case BNEr: case BPLr: + case BVCr: case BVSr: + printf("%02x ", endian_16lo8 (operand)); + break; + //Indirect Addressing Mode Handler + case JMPi: + printf("%02x %02x ", endian_16lo8 (operand), endian_16hi8 (operand)); + break; + //Indexed with X Preinc Addressing Mode Handler + case ADCix: case ANDix: case CMPix: case DCPix: case EORix: case ISBix: + case LAXix: case LDAix: case ORAix: case SAXix: case SBCix: case SLOix: + case SREix: case STAix: case RLAix: case RRAix: + //ASOix AXSix DCMix INSix LSEix - Optional Opcode Names + printf("%02x ", endian_16lo8 (operand)); + break; + //Indexed with Y Postinc Addressing Mode Handler + case ADCiy: case ANDiy: case CMPiy: case DCPiy: case EORiy: case ISBiy: + case LAXiy: case LDAiy: case ORAiy: case RLAiy: case RRAiy: case SBCiy: + case SHAiy: case SLOiy: case SREiy: case STAiy: + //AXAiy ASOiy LSEiy DCMiy INSiy - Optional Opcode Names + printf("%02x ", endian_16lo8 (operand)); + break; + default: + printf(" "); + break; + } + + switch(opcode) + { + case ADCb: case ADCz: case ADCzx: case ADCa: case ADCax: case ADCay: + case ADCix: case ADCiy: + printf(" ADC"); break; + case ANCb_: + printf("*ANC"); break; + case ANDb: case ANDz: case ANDzx: case ANDa: case ANDax: case ANDay: + case ANDix: case ANDiy: + printf(" AND"); break; + case ANEb: //Also known as XAA + printf("*ANE"); break; + case ARRb: + printf("*ARR"); break; + case ASLn: case ASLz: case ASLzx: case ASLa: case ASLax: + printf(" ASL"); break; + case ASRb: //Also known as ALR + printf("*ASR"); break; + case BCCr: + printf(" BCC"); break; + case BCSr: + printf(" BCS"); break; + case BEQr: + printf(" BEQ"); break; + case BITz: case BITa: + printf(" BIT"); break; + case BMIr: + printf(" BMI"); break; + case BNEr: + printf(" BNE"); break; + case BPLr: + printf(" BPL"); break; + case BRKn: + printf(" BRK"); break; + case BVCr: + printf(" BVC"); break; + case BVSr: + printf(" BVS"); break; + case CLCn: + printf(" CLC"); break; + case CLDn: + printf(" CLD"); break; + case CLIn: + printf(" CLI"); break; + case CLVn: + printf(" CLV"); break; + case CMPb: case CMPz: case CMPzx: case CMPa: case CMPax: case CMPay: + case CMPix: case CMPiy: + printf(" CMP"); break; + case CPXb: case CPXz: case CPXa: + printf(" CPX"); break; + case CPYb: case CPYz: case CPYa: + printf(" CPY"); break; + case DCPz: case DCPzx: case DCPa: case DCPax: case DCPay: case DCPix: + case DCPiy: //Also known as DCM + printf("*DCP"); break; + case DECz: case DECzx: case DECa: case DECax: + printf(" DEC"); break; + case DEXn: + printf(" DEX"); break; + case DEYn: + printf(" DEY"); break; + case EORb: case EORz: case EORzx: case EORa: case EORax: case EORay: + case EORix: case EORiy: + printf(" EOR"); break; + case INCz: case INCzx: case INCa: case INCax: + printf(" INC"); break; + case INXn: + printf(" INX"); break; + case INYn: + printf(" INY"); break; + case ISBz: case ISBzx: case ISBa: case ISBax: case ISBay: case ISBix: + case ISBiy: //Also known as INS + printf("*ISB"); break; + case JMPw: case JMPi: + printf(" JMP"); break; + case JSRw: + printf(" JSR"); break; + case LASay: + printf("*LAS"); break; + case LAXz: case LAXzy: case LAXa: case LAXay: case LAXix: case LAXiy: + printf("*LAX"); break; + case LDAb: case LDAz: case LDAzx: case LDAa: case LDAax: case LDAay: + case LDAix: case LDAiy: + printf(" LDA"); break; + case LDXb: case LDXz: case LDXzy: case LDXa: case LDXay: + printf(" LDX"); break; + case LDYb: case LDYz: case LDYzx: case LDYa: case LDYax: + printf(" LDY"); break; + case LSRz: case LSRzx: case LSRa: case LSRax: case LSRn: + printf(" LSR"); break; + case NOPn_: case NOPb_: case NOPz_: case NOPzx_: case NOPa: case NOPax_: + if(opcode != NOPn) printf("*"); + else printf(" "); + printf("NOP"); break; + case LXAb: //Also known as OAL + printf("*LXA"); break; + case ORAb: case ORAz: case ORAzx: case ORAa: case ORAax: case ORAay: + case ORAix: case ORAiy: + printf(" ORA"); break; + case PHAn: + printf(" PHA"); break; + case PHPn: + printf(" PHP"); break; + case PLAn: + printf(" PLA"); break; + case PLPn: + printf(" PLP"); break; + case RLAz: case RLAzx: case RLAix: case RLAa: case RLAax: case RLAay: + case RLAiy: + printf("*RLA"); break; + case ROLz: case ROLzx: case ROLa: case ROLax: case ROLn: + printf(" ROL"); break; + case RORz: case RORzx: case RORa: case RORax: case RORn: + printf(" ROR"); break; + case RRAa: case RRAax: case RRAay: case RRAz: case RRAzx: case RRAix: + case RRAiy: + printf("*RRA"); break; + case RTIn: + printf(" RTI"); break; + case RTSn: + printf(" RTS"); break; + case SAXz: case SAXzy: case SAXa: case SAXix: //Also known as AXS + printf("*SAX"); break; + case SBCb_: + if(opcode != SBCb) printf("*"); + else printf(" "); + printf ("SBC"); break; + case SBCz: case SBCzx: case SBCa: case SBCax: case SBCay: case SBCix: + case SBCiy: + printf(" SBC"); break; + case SBXb: + printf("*SBX"); break; + case SECn: + printf(" SEC"); break; + case SEDn: + printf(" SED"); break; + case SEIn: + printf(" SEI"); break; + case SHAay: case SHAiy: //Also known as AXA + printf("*SHA"); break; + case SHSay: //Also known as TAS + printf("*SHS"); break; + case SHXay: //Also known as XAS + printf("*SHX"); break; + case SHYax: //Also known as SAY + printf("*SHY"); break; + case SLOz: case SLOzx: case SLOa: case SLOax: case SLOay: case SLOix: + case SLOiy: //Also known as ASO + printf("*SLO"); break; + case SREz: case SREzx: case SREa: case SREax: case SREay: case SREix: + case SREiy: //Also known as LSE + printf("*SRE"); break; + case STAz: case STAzx: case STAa: case STAax: case STAay: case STAix: + case STAiy: + printf(" STA"); break; + case STXz: case STXzy: case STXa: + printf(" STX"); break; + case STYz: case STYzx: case STYa: + printf(" STY"); break; + case TAXn: + printf(" TAX"); break; + case TAYn: + printf(" TAY"); break; + case TSXn: + printf(" TSX"); break; + case TXAn: + printf(" TXA"); break; + case TXSn: + printf(" TXS"); break; + case TYAn: + printf(" TYA"); break; + default: + printf("*HLT"); break; + } + + switch(opcode) + { + //Accumulator or Implied addressing + case ASLn: case LSRn: case ROLn: case RORn: + printf("n A"); + break; + + //Zero Page Addressing Mode Handler + case ADCz: case ANDz: case ASLz: case BITz: case CMPz: case CPXz: + case CPYz: case DCPz: case DECz: case EORz: case INCz: case ISBz: + case LAXz: case LDAz: case LDXz: case LDYz: case LSRz: case ORAz: + + case ROLz: case RORz: case SBCz: case SREz: case SLOz: case RLAz: + case RRAz: + //ASOz AXSz DCMz INSz LSEz - Optional Opcode Names + printf("z %02x {%02x}", (uint8_t) operand, data); + break; + case SAXz: case STAz: case STXz: case STYz: +#ifdef MOS6510_DEBUG + case NOPz_: +#endif + printf("z %02x", endian_16lo8 (operand)); + break; + + //Zero Page with X Offset Addressing Mode Handler + case ADCzx: case ANDzx: case ASLzx: case CMPzx: case DCPzx: case DECzx: + case EORzx: case INCzx: case ISBzx: case LDAzx: case LDYzx: case LSRzx: + case ORAzx: case RLAzx: case ROLzx: case RORzx: case RRAzx: case SBCzx: + case SLOzx: case SREzx: + //ASOzx DCMzx INSzx LSEzx - Optional Opcode Names + printf("zx %02x,X", endian_16lo8 (operand)); + printf(" [%04x]{%02x}", address, data); + break; + case STAzx: case STYzx: +#ifdef MOS6510_DEBUG + case NOPzx_: +#endif + printf("zx %02x,X", endian_16lo8 (operand)); + printf(" [%04x]", address); + break; + + //Zero Page with Y Offset Addressing Mode Handler + case LAXzy: case LDXzy: + //AXSzx - Optional Opcode Names + printf("zy %02x,Y", endian_16lo8 (operand)); + printf(" [%04x]{%02x}", address, data); + break; + case STXzy: case SAXzy: + printf("zy %02x,Y", endian_16lo8 (operand)); + printf(" [%04x]", address); + break; + + //Absolute Addressing Mode Handler + case ADCa: case ANDa: case ASLa: case BITa: case CMPa: case CPXa: + case CPYa: case DCPa: case DECa: case EORa: case INCa: case ISBa: + case LAXa: case LDAa: case LDXa: case LDYa: case LSRa: case ORAa: + case ROLa: case RORa: case SBCa: case SLOa: case SREa: case RLAa: + case RRAa: + //ASOa AXSa DCMa INSa LSEa - Optional Opcode Names + printf("a %04x {%02x}", operand, data); + break; + case SAXa: case STAa: case STXa: case STYa: +#ifdef MOS6510_DEBUG + case NOPa: +#endif + printf("a %04x", operand); + break; + case JMPw: case JSRw: + printf("w %04x", operand); + break; + + //Absolute With X Offset Addresing Mode Handler + case ADCax: case ANDax: case ASLax: case CMPax: case DCPax: case DECax: + case EORax: case INCax: case ISBax: case LDAax: case LDYax: case LSRax: + case ORAax: case RLAax: case ROLax: case RORax: case RRAax: case SBCax: + case SLOax: case SREax: + //ASOax DCMax INSax LSEax SAYax - Optional Opcode Names + printf("ax %04x,X", operand); + printf(" [%04x]{%02x}", address, data); + break; + case SHYax: case STAax: +#ifdef MOS6510_DEBUG + case NOPax_: +#endif + printf("ax %04x,X", operand); + printf(" [%04x]", address); + break; + + //Absolute With Y Offset Addresing Mode Handler + case ADCay: case ANDay: case CMPay: case DCPay: case EORay: case ISBay: + case LASay: case LAXay: case LDAay: case LDXay: case ORAay: case RLAay: + case RRAay: case SBCay: case SHSay: case SLOay: case SREay: + //ASOay AXAay DCMay INSax LSEay TASay XASay - Optional Opcode Names + printf("ay %04x,Y", operand); + printf(" [%04x]{%02x}", address, data); + break; + case SHAay: case SHXay: case STAay: + printf("ay %04x,Y", operand); + printf(" [%04x]", address); + break; + + //Immediate Addressing Mode Handler + case ADCb: case ANDb: case ANCb_: case ANEb: case ASRb: case ARRb: + case CMPb: case CPXb: case CPYb: case EORb: case LDAb: case LDXb: + case LDYb: case LXAb: case ORAb: case SBCb_: case SBXb: + //OALb ALRb XAAb - Optional Opcode Names +#ifdef MOS6510_DEBUG + case NOPb_: +#endif + printf("b #%02x", endian_16lo8 (operand)); + break; + + //Relative Addressing Mode Handler + case BCCr: case BCSr: case BEQr: case BMIr: case BNEr: case BPLr: + case BVCr: case BVSr: + printf("r #%02x", endian_16lo8 (operand)); + printf(" [%04x]", address); + break; + + //Indirect Addressing Mode Handler + case JMPi: + printf("i (%04x)", operand); + printf(" [%04x]", address); + break; + + //Indexed with X Preinc Addressing Mode Handler + case ADCix: case ANDix: case CMPix: case DCPix: case EORix: case ISBix: + case LAXix: case LDAix: case ORAix: case SBCix: case SLOix: case SREix: + case RLAix: case RRAix: + //ASOix AXSix DCMix INSix LSEix - Optional Opcode Names + printf("ix (%02x,X)", endian_16lo8 (operand)); + printf(" [%04x]{%02x}", address, data); + break; + case SAXix: case STAix: + printf("ix (%02x,X)", endian_16lo8 (operand)); + printf(" [%04x]", address); + break; + + //Indexed with Y Postinc Addressing Mode Handler + case ADCiy: case ANDiy: case CMPiy: case DCPiy: case EORiy: case ISBiy: + case LAXiy: case LDAiy: case ORAiy: case RLAiy: case RRAiy: case SBCiy: + case SLOiy: case SREiy: + //AXAiy ASOiy LSEiy DCMiy INSiy - Optional Opcode Names + printf("iy (%02x),Y", endian_16lo8 (operand)); + printf(" [%04x]{%02x}", address, data); + break; + case SHAiy: case STAiy: + printf("iy (%02x),Y", endian_16lo8 (operand)); + printf(" [%04x]", address); + break; + + default: + break; + } + + printf ("\n\n"); + fflush (stdout); +} + +#endif // MOS6510_STATE_6510 + diff --git a/plugins/sid/sidplay-libs/libsidplay/src/mos6510/mos6510.h b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/mos6510.h new file mode 100644 index 00000000..e7ad1a3f --- /dev/null +++ b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/mos6510.h @@ -0,0 +1,75 @@ +/*************************************************************************** + mos6510.h - description + ------------------- + begin : Thu May 11 2000 + copyright : (C) 2000 by Simon White + email : s_a_white@email.com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +/*************************************************************************** + * $Log: mos6510.h,v $ + * Revision 1.5 2001/07/14 16:47:21 s_a_white + * Sync with sidbuilder class project. + * + * Revision 1.4 2001/07/14 13:04:34 s_a_white + * Accumulator is now unsigned, which improves code readability. + * + * Revision 1.3 2000/12/11 19:03:16 s_a_white + * AC99 Update. + * + ***************************************************************************/ + +#ifndef _mos6510_h_ +#define _mos6510_h_ + +#include "config.h" +#include "component.h" +#include "sidenv.h" +#include "event.h" + +#undef MOS6510_VERSION +#undef MOS6510_DATE +#undef MOS6510_AUTHOR +#undef MOS6510_EMAIL +#define MOS6510_VERSION "1.08" +#define MOS6510_DATE "23th May 2000" +#define MOS6510_AUTHOR "Simon White" +#define MOS6510_EMAIL "s_a_white@email.com" +#define MOS6510_INTERRUPT_DELAY 2 + +#include "opcodes.h" +#include "conf6510.h" + +// Status Register flag definistions +#define SR_NEGATIVE 7 +#define SR_OVERFLOW 6 +#define SR_NOTUSED 5 +#define SR_BREAK 4 +#define SR_DECIMAL 3 +#define SR_INTERRUPT 2 +#define SR_ZERO 1 +#define SR_CARRY 0 + +#define SP_PAGE 0x01 + +// Check to see what type of emulation is required +#ifdef MOS6510_CYCLE_BASED +# ifdef MOS6510_SIDPLAY +# include "cycle_based/sid6510c.h" +# else +# include "cycle_based/mos6510c.h" +# endif // MOS6510_SIDPLAY +#else + // Line based emulation code has not been provided +#endif // MOS6510_CYCLE_BASED + +#endif // _mos6510_h_ + diff --git a/plugins/sid/sidplay-libs/libsidplay/src/mos6510/opcodes.h b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/opcodes.h new file mode 100644 index 00000000..e4d44acd --- /dev/null +++ b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/opcodes.h @@ -0,0 +1,331 @@ +/*************************************************************************** + opcodes.h - description + ------------------- + begin : Thu May 11 2000 + copyright : (C) 2000 by Simon White + email : s_a_white@email.com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef _opcodes_h_ +#define _opcodes_h_ + +#define OPCODE_MAX 0x100 + +/* HLT + case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: + case 0x62: case 0x72: case 0x92: case 0xb2: case 0xd2: case 0xf2: + case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: + case 0x62: case 0x72: case 0x92: case 0xb2: case 0xd2: case 0xf2: +*/ + +#define BRKn 0x00 +#define JSRw 0x20 +#define RTIn 0x40 +#define RTSn 0x60 +#define NOPb 0x80 +#define NOPb_ NOPb: case 0x82: case 0xC2: case 0xE2: case 0x89 +#define LDYb 0xA0 +#define CPYb 0xC0 +#define CPXb 0xE0 + +#define ORAix 0x01 +#define ANDix 0x21 +#define EORix 0x41 +#define ADCix 0x61 +#define STAix 0x81 +#define LDAix 0xA1 +#define CMPix 0xC1 +#define SBCix 0xE1 + +#define LDXb 0xA2 + +#define SLOix 0x03 +#define RLAix 0x23 +#define SREix 0x43 +#define RRAix 0x63 +#define SAXix 0x83 +#define LAXix 0xA3 +#define DCPix 0xC3 +#define ISBix 0xE3 + +#define NOPz 0x04 +#define NOPz_ NOPz: case 0x44: case 0x64 +#define BITz 0x24 +#define STYz 0x84 +#define LDYz 0xA4 +#define CPYz 0xC4 +#define CPXz 0xE4 + +#define ORAz 0x05 +#define ANDz 0x25 +#define EORz 0x45 +#define ADCz 0x65 +#define STAz 0x85 +#define LDAz 0xA5 +#define CMPz 0xC5 +#define SBCz 0xE5 + +#define ASLz 0x06 +#define ROLz 0x26 +#define LSRz 0x46 +#define RORz 0x66 +#define STXz 0x86 +#define LDXz 0xA6 +#define DECz 0xC6 +#define INCz 0xE6 + +#define SLOz 0x07 +#define RLAz 0x27 +#define SREz 0x47 +#define RRAz 0x67 +#define SAXz 0x87 +#define LAXz 0xA7 +#define DCPz 0xC7 +#define ISBz 0xE7 + +#define PHPn 0x08 +#define PLPn 0x28 +#define PHAn 0x48 +#define PLAn 0x68 +#define DEYn 0x88 +#define TAYn 0xA8 +#define INYn 0xC8 +#define INXn 0xE8 + +#define ORAb 0x09 +#define ANDb 0x29 +#define EORb 0x49 +#define ADCb 0x69 +#define LDAb 0xA9 +#define CMPb 0xC9 +#define SBCb 0xE9 +#define SBCb_ SBCb: case 0XEB + +#define ASLn 0x0A +#define ROLn 0x2A +#define LSRn 0x4A +#define RORn 0x6A +#define TXAn 0x8A +#define TAXn 0xAA +#define DEXn 0xCA +#define NOPn 0xEA +#define NOPn_ NOPn: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA + +#define ANCb 0x0B +#define ANCb_ ANCb: case 0x2B +#define ASRb 0x4B +#define ARRb 0x6B +#define ANEb 0x8B +#define XAAb 0x8B +#define LXAb 0xAB +#define SBXb 0xCB + +#define NOPa 0x0C +#define BITa 0x2C +#define JMPw 0x4C +#define JMPi 0x6C +#define STYa 0x8C +#define LDYa 0xAC +#define CPYa 0xCC +#define CPXa 0xEC + +#define ORAa 0x0D +#define ANDa 0x2D +#define EORa 0x4D +#define ADCa 0x6D +#define STAa 0x8D +#define LDAa 0xAD +#define CMPa 0xCD +#define SBCa 0xED + +#define ASLa 0x0E +#define ROLa 0x2E +#define LSRa 0x4E +#define RORa 0x6E +#define STXa 0x8E +#define LDXa 0xAE +#define DECa 0xCE +#define INCa 0xEE + +#define SLOa 0x0F +#define RLAa 0x2F +#define SREa 0x4F +#define RRAa 0x6F +#define SAXa 0x8F +#define LAXa 0xAF +#define DCPa 0xCF +#define ISBa 0xEF + +#define BPLr 0x10 +#define BMIr 0x30 +#define BVCr 0x50 +#define BVSr 0x70 +#define BCCr 0x90 +#define BCSr 0xB0 +#define BNEr 0xD0 +#define BEQr 0xF0 + +#define ORAiy 0x11 +#define ANDiy 0x31 +#define EORiy 0x51 +#define ADCiy 0x71 +#define STAiy 0x91 +#define LDAiy 0xB1 +#define CMPiy 0xD1 +#define SBCiy 0xF1 + +#define SLOiy 0x13 +#define RLAiy 0x33 +#define SREiy 0x53 +#define RRAiy 0x73 +#define SHAiy 0x93 +#define LAXiy 0xB3 +#define DCPiy 0xD3 +#define ISBiy 0xF3 + +#define NOPzx 0x14 +#define NOPzx_ NOPzx: case 0x34: case 0x54: case 0x74: case 0xD4: case 0xF4 +#define STYzx 0x94 +#define LDYzx 0xB4 + +#define ORAzx 0x15 +#define ANDzx 0x35 +#define EORzx 0x55 +#define ADCzx 0x75 +#define STAzx 0x95 +#define LDAzx 0xB5 +#define CMPzx 0xD5 +#define SBCzx 0xF5 + +#define ASLzx 0x16 +#define ROLzx 0x36 +#define LSRzx 0x56 +#define RORzx 0x76 +#define STXzy 0x96 +#define LDXzy 0xB6 +#define DECzx 0xD6 +#define INCzx 0xF6 + +#define SLOzx 0x17 +#define RLAzx 0x37 +#define SREzx 0x57 +#define RRAzx 0x77 +#define SAXzy 0x97 +#define LAXzy 0xB7 +#define DCPzx 0xD7 +#define ISBzx 0xF7 + +#define CLCn 0x18 +#define SECn 0x38 +#define CLIn 0x58 +#define SEIn 0x78 +#define TYAn 0x98 +#define CLVn 0xB8 +#define CLDn 0xD8 +#define SEDn 0xF8 + +#define ORAay 0x19 +#define ANDay 0x39 +#define EORay 0x59 +#define ADCay 0x79 +#define STAay 0x99 +#define LDAay 0xB9 +#define CMPay 0xD9 +#define SBCay 0xF9 + +#define TXSn 0x9A +#define TSXn 0xBA + +#define SLOay 0x1B +#define RLAay 0x3B +#define SREay 0x5B +#define RRAay 0x7B +#define SHSay 0x9B +#define TASay 0x9B +#define LASay 0xBB +#define DCPay 0xDB +#define ISBay 0xFB + +#define NOPax 0x1C +#define NOPax_ NOPax: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC +#define SHYax 0x9C +#define LDYax 0xBC + +#define ORAax 0x1D +#define ANDax 0x3D +#define EORax 0x5D +#define ADCax 0x7D +#define STAax 0x9D +#define LDAax 0xBD +#define CMPax 0xDD +#define SBCax 0xFD + +#define ASLax 0x1E +#define ROLax 0x3E +#define LSRax 0x5E +#define RORax 0x7E +#define SHXay 0x9E +#define LDXay 0xBE +#define DECax 0xDE +#define INCax 0xFE + +#define SLOax 0x1F +#define RLAax 0x3F +#define SREax 0x5F +#define RRAax 0x7F +#define SHAay 0x9F +#define LAXay 0xBF +#define DCPax 0xDF +#define ISBax 0xFF + +// Instruction Aliases +#define ASOix SLOix +#define LSEix SREix +#define AXSix SAXix +#define DCMix DCPix +#define INSix ISBix +#define ASOz SLOz +#define LSEz SREz +#define AXSz SAXz +#define DCMz DCPz +#define INSz ISBz +#define ALRb ASRb +#define OALb LXAb +#define ASOa SLOa +#define LSEa SREa +#define AXSa SAXa +#define DCMa DCPa +#define INSa ISBa +#define ASOiy SLOiy +#define LSEiy SREiy +#define AXAiy SHAiy +#define DCMiy DCPiy +#define INSiy ISBiy +#define ASOzx SLOzx +#define LSEzx SREzx +#define AXSzy SAXzy +#define DCMzx DCPzx +#define INSzx ISBzx +#define ASOay SLOay +#define LSEay SREay +#define DCMay DCPay +#define INSay ISBay +#define SAYax SHYax +#define XASay SHXay +#define ASOax SLOax +#define LSEax SREax +#define AXAay SHAay +#define DCMax DCPax +#define INSax ISBax +#define SKBn NOPb +#define SKWn NOPa + +#endif // _opcodes_h_ |